FristiLeaks : de la reconnaissance au root
C’était le TP de fin de la matière : un audit à mener en binôme avec Grégoire sur la machine d’une entreprise fictive, dans le scénario monté par la prof. Même principe que pour la Kioptrix : on part de l’extérieur sans rien connaître de la machine, on cherche un point d’entrée, et on remonte jusqu’au root en documentant chaque étape. La machine derrière le TP est la FristiLeaks 1.0 de VulnHub (créée par Ar0xA), qui repose sur un enchaînement de petites énigmes plutôt que sur une grosse CVE.
Je reprends ici le fil de l’audit, en détaillant un peu plus le pourquoi de chaque étape que dans le rapport, qui devait tenir en 5 pages.
📄 Le rapport complet au format PDF est disponible ici : Rapport d’audit FristiLeaks
La procédure
On a gardé la même logique d’audit du début à la fin :
- Scan et analyse globale depuis l’extérieur
- Recherche de vulnérabilités sur les chemins trouvés
- Exploitation
- Documentation et propositions de remédiation
Analyse de la machine
Scan avec Nmap
On commence par Nmap pour savoir ce qui tourne sur la cible : les ports ouverts et les services derrière.
1
sudo nmap -sS -sV 192.168.1.101
Un seul port ouvert : le 80 (HTTP). Pas de SSH, pas de MySQL exposé, rien d’autre. Tout va donc passer par le web. On récupère quand même deux infos utiles : Apache 2.2.15 et PHP 5.3.3, deux versions largement obsolètes.
J’ai ensuite lancé Nikto pour voir s’il remontait des mauvaises configs ou des CVE évidentes. Honnêtement il ne nous a pas appris grand-chose de plus, à part confirmer les versions et quelques en-têtes de sécurité manquants.
Ce qu’on sait à ce stade
- OS : CentOS
- Site accessible sur le port 80 uniquement
- Apache 2.2.15 (obsolète)
- PHP 5.3.3 (obsolète)
- Portail de connexion :
http://192.168.1.101/fristi(trouvé par déduction avec le nom du site et le thème de la machine)
Pour lister les chemins du site on a fuzzé avec ffuf (wordlist /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt) et en complément avec ZAP. On remonte plusieurs chemins : /beer, /cola, /sisi, /images/, /icons/, /robots.txt… La plupart sont des fausses pistes. Le seul qui nous intéresse vraiment, c’est /fristi, qui affiche un formulaire de login.
Trouver les identifiants dans le code source
Sur une page de login j’ai le réflexe d’aller lire le code source. On y trouve un commentaire HTML avec une chaîne en base64. En la décodant, on ne tombe pas sur du texte mais sur une image PNG, qui une fois affichée montre en clair :
1
keKkeKKeKKeKkEkkEk
Planquer le mot de passe dans une image évite qu’il sorte sur une simple recherche de texte. Juste à côté, un autre commentaire était signé eezeepz : on part du principe que c’est le nom d’utilisateur qui va avec.
- User :
eezeepz - Password :
keKkeKKeKKeKkEkkEk
Recherche de vulnérabilité
Avant d’aller plus loin, on passe le site à ZAP (OWASP Zed Attack Proxy), en mode auto puis en mode manuel une fois connectés avec le couple trouvé. Il remonte 16 alertes : absence de token anti-CSRF, CSP manquant, directory browsing, headers de sécurité absents.
On a aussi tenté des injections SQL à la main puis avec sqlmap sur le formulaire, par acquit de conscience. Rien d’injectable de ce côté-là.
L’injection SQL ne semble pas être une piste viable, mais on a maintenant des identifiants valides. On passe donc à l’exploitation côté applicatif.
Exploitation
Upload d’un fichier PHP déguisé en image
Une fois connectés avec eezeepz, on arrive sur une page qui permet d’uploader des images. L’application est censée n’accepter que des images, mais elle vérifie mal l’extension.
L’astuce classique : nommer notre fichier simple-backdoor.php.png. La double extension suffit à passer le filtre (qui ne regarde que la fin, .png), pendant qu’Apache, lui, interprète toujours le fichier comme du PHP. On a donc un bout de code PHP exécutable déposé sur le serveur.
NB : On utilise les fichiers php fournis sur Kali dans /usr/share/webshells/php/
On va le consulter dans le dossier /uploads en lui passant une commande en paramètre :
1
http://192.168.1.101/fristi/uploads/simple-backdoor.php.png?cmd=whoami
La page nous répond apache. La RCE est confirmée : on exécute des commandes sur la machine, pour l’instant avec les droits du serveur web.
Récupérer un reverse shell
Exécuter des commandes une par une dans l’URL, c’est inconfortable. On veut un vrai shell interactif. Le principe du reverse shell : on met notre machine (Kali) en écoute, et on fait en sorte que la cible vienne se connecter à nous.
Côté Kali on écoute :
1
sudo nc -lvnp 1234
Puis on déclenche depuis la cible un script PHP qui ouvre une connexion vers notre IP. La cible se connecte, et on récupère la main :
On est apache (uid 48), sur un kernel 2.6.32 (CentOS 6). C’est notre point de départ pour l’élévation de privilèges.
Post-exploitation : l’escalade de privilèges
La routine de Jerry
En explorant le système, on remarque que le home de l’utilisateur eezeepz est lisible. Dedans, un notes.txt laissé par un certain « Jerry » :
Le message explique qu’une routine lit le fichier /tmp/runthis, exécute chaque ligne en tant qu’admin, une fois par minute, et écrit le résultat dans /tmp/cronresult. Seule contrainte : on ne peut utiliser qu’une poignée de binaires (chmod, df, cat, echo, ps, grep, egrep) et il faut donner leur chemin complet.
Comme la routine tourne avec les droits d’admin, on lui fait faire ce qu’on veut dans la limite des binaires autorisés. On en profite pour rendre le dossier d’admin accessible :
1
echo "/usr/bin/chmod 777 /home/admin/" > /tmp/runthis
Après une minute, le dossier /home/admin est en 777 : on peut enfin lire son contenu.
Décoder le mot de passe de fristigod
Dans /home/admin, trois fichiers nous intéressent : cryptpass.py, cryptedpass.txt et whoisyourgodnow.txt.
Le contenu de whoisyourgodnow.txt ressemble à du base64, mais il commence par un =, ce qui est bizarre : le = est normalement un caractère placé à la fin d’une chaîne base64. S’il est au début, c’est que la chaîne a été inversée.
Le script cryptpass.py confirme la logique de chiffrement :
Il fait trois choses dans l’ordre : encode en base64, inverse la chaîne ([::-1]), puis applique un ROT13. Pour retrouver le mot de passe, il suffit de dérouler l’inverse. Et comme le ROT13 est sa propre réciproque (le ré-appliquer annule l’effet), on peut le refaire en premier :
- ROT13 sur la chaîne -> on récupère une base64 (toujours inversée)
- On inverse la chaîne -> base64 propre, le
=revient à la fin - On décode le base64 -> le mot de passe en clair
On obtient :
1
LetThereBeFristi!
On tente de se connecter avec, en essayant les différents utilisateurs de la machine (admin, fristigod…). Le seul qui fonctionne est fristigod :
L’exécutable setuid et le détour par sudo
On est désormais fristigod. Après une longue exploration qui n’a rien donné on s’est penché sur l’utilisation de sudo.
On regarde ce que cet utilisateur a le droit de faire avec sudo -l :
La ligne intéressante :
1
(fristi : ALL) /var/fristigod/.secret_admin_stuff/doCom
Traduction : fristigod peut lancer le programme doCom en tant que l’utilisateur fristi (bon ça je ne le savais pas, j’avais juste lu /var/fristigod/.secret_admin_stuff/doCom). On va voir ce que fait ce doCom. Si on le lance directement, il nous jette :
Nice try, but wrong user ;). L’exécutable attend donc un utilisateur bien précis. Comme c’est un binaire ELF, on le récupère via le serveur web pour l’ouvrir dans Ghidra (un désassembleur) et comprendre sa logique.
Le programme vérifie que notre uid vaut 503, et si c’est le cas il fait un setuid(0) avant d’exécuter la commande qu’on lui passe en paramètre :
Le setuid(0) est le point clé : 0 c’est l’uid de root. Donc tout ce que doCom lance tourne finalement en root. Reste à satisfaire la condition uid == 503. En regardant /etc/passwd, on voit que l’uid 503 appartient à l’utilisateur fristi… qui est en nologin.
Impossible de se connecter en tant que fristi directement (le nologin bloque su). Mais ce n’est pas nécessaire : sudo -l nous a dit que fristigod pouvait lancer doCom en tant que fristi. Le nologin empêche d’ouvrir une session, pas d’exécuter une commande via sudo -u.
On combine donc tout. On demande à sudo de lancer doCom en tant que fristi, et on lui passe bash comme commande à exécuter :
1
sudo -u fristi /var/fristigod/.secret_admin_stuff/doCom bash
Ce qui se passe en chaîne :
- sudo lance
doComavec l’uid de fristi (503) -> la vérification passe doComfaitsetuid(0)-> on bascule rootdoComexécutebash-> on obtient un shell root
On est root. Dans /root, le fichier fristileaks_secrets.txt contient le flag final :
1
Y0u_kn0w_y0u_l0ve_fr1st1
Remédiations
L’escalade s’est faite par accumulation de petites négligences plus que par une seule grosse faille. Les corrections à apporter, de la plus urgente à la moins :
- Identifiants dans le code source : le login/mot de passe planqués (même en base64) dans la page de login côté client sont à supprimer. Tout ce qui part au navigateur est lisible.
- Upload non sécurisé menant à une RCE : il faut vérifier le vrai type du fichier (contenu, pas seulement l’extension) et empêcher l’interprétation PHP dans le dossier d’upload. La double extension
.php.pngne doit jamais pouvoir être exécutée. - Routine
runthisexécutée en tant qu’admin : à supprimer. Un utilisateur ne doit pas pouvoir faire exécuter ses commandes avec les droits d’un autre via un « raccourci » laissé en place. - Chiffrement maison et fichier
whoisyourgodnow.txt: base64 + inversion + ROT13, ce n’est pas du chiffrement, c’est de l’encodage réversible en trois lignes. Le fichier et le script sont à retirer. - Exécutable setuid
doCom: un binaire qui faitsetuid(0)pour exécuter des commandes arbitraires est dangereux et inutile. Il faut attribuer les bons droits aux utilisateurs plutôt que de contourner le modèle de permissions.
Et les failles remontées par ZAP mais non exploitées, à corriger quand même : ajout d’un token anti-CSRF, mise en place d’une CSP et d’un header anti-clickjacking.
Conclusion
FristiLeaks repose sur l’enchaînement plutôt que sur la difficulté technique : chaque étape est simple une fois qu’on a l’indice précédent. La prise de root finale n’exploite aucune CVE, juste une mauvaise config de sudo et un binaire setuid qu’on n’aurait jamais dû laisser traîner.
Comme pour la Kioptrix, ce ne sont pas les grosses vulnérabilités qui font tomber la machine mais l’accumulation de petits raccourcis : un mot de passe planqué, un upload mal filtré, une routine pratique, un sudo -u trop permissif. Pris un par un ils semblent anodins, mis bout à bout ils mènent au root.




















