Add content from: nodes/proxy GET → Kubelet /exec RCE via WebSocket handshake ...

This commit is contained in:
HackTricks News Bot
2026-01-27 01:48:53 +00:00
parent b6082c0f47
commit e19da8e90c
2 changed files with 27 additions and 1 deletions

View File

@@ -677,7 +677,26 @@ Principals with access to the **`nodes/proxy`** subresource can **execute code o
../pentesting-kubernetes-services/kubelet-authentication-and-authorization.md
{{#endref}}
You have an example of how to get [**RCE talking authorized to a Kubelet API here**](../pentesting-kubernetes-services/index.html#kubelet-rce).
#### nodes/proxy GET -> Kubelet /exec via WebSocket verb confusion
- Kubelet maps HTTP methods to RBAC verbs **before** protocol upgrade. WebSocket handshakes must start with **HTTP GET** (`Connection: Upgrade`), so `/exec` over WebSocket is checked as **verb `get`** instead of the expected `create`.
- `/exec`, `/run`, `/attach`, and `/portforward` are not explicitly mapped and fall into the default **`proxy`** subresource, so the authorization question becomes **`can <user> get nodes/proxy?`**
- If a token only has **`nodes/proxy` + `get`**, direct WebSocket access to the kubelet on `https://<node_ip>:10250` allows arbitrary command execution in any pod on that node. The same request via the API server proxy path (`/api/v1/nodes/<node>/proxy/exec/...`) is denied because it is a normal HTTP POST and maps to `create`.
- The kubelet performs no second authorization after the WebSocket upgrade; only the initial GET is evaluated.
**Direct exploit (requires network reachability to the kubelet and a token with `nodes/proxy` GET):**
```bash
kubectl auth can-i --list | grep "nodes/proxy"
websocat --insecure \
--header "Authorization: Bearer $TOKEN" \
--protocol "v4.channel.k8s.io" \
"wss://$NODE_IP:10250/exec/$NAMESPACE/$POD/$CONTAINER?output=1&error=1&command=id"
```
- Use the **Node IP**, not the node name. The same request with `curl -X POST` will be **Forbidden** because it maps to `create`.
- Direct kubelet access bypasses the API server, so AuditPolicy only shows `subjectaccessreviews` from the kubelet user agent and **does not log `pods/exec`** commands.
- Enumerate affected service accounts with the [detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a) to find tokens limited to `nodes/proxy` GET.
### Delete pods + unschedulable nodes
@@ -844,6 +863,9 @@ https://github.com/aquasecurity/kube-bench
- [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers)
- [**https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html**](https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html)
- [**https://kubenomicon.com/**](https://kubenomicon.com/)
- [nodes/proxy GET -> kubelet exec WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce)
- [nodes/proxy GET detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a)
- [websocat](https://github.com/vi/websocat)
{{#include ../../../banners/hacktricks-training.md}}

View File

@@ -91,6 +91,9 @@ The kubelet authorizes API requests using the same [request attributes](https://
| /spec/\* | nodes | spec |
| _all others_ | nodes | proxy |
> [!NOTE]
> WebSocket-based `/exec`, `/run`, `/attach`, and `/portforward` fall into the default **proxy** subresource and are authorized using the initial HTTP **GET** handshake. A principal with only `nodes/proxy` **GET** can still exec containers if it connects directly to `https://<node_ip>:10250` over WebSockets. See the [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion) for details.
For example, the following request tried to access the pods info of kubelet without permission:
```bash
@@ -105,6 +108,7 @@ Forbidden (user=system:node:ip-172-31-28-172.ec2.internal, verb=get, resource=no
## References
- [https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
- [nodes/proxy GET -> kubelet exec via WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce)
{{#include ../../../banners/hacktricks-training.md}}