Post

FristiLeaks : de la reconnaissance au root

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 :

  1. Scan et analyse globale depuis l’extérieur
  2. Recherche de vulnérabilités sur les chemins trouvés
  3. Exploitation
  4. 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

Scan Nmap de la cible

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.

Portail de connexionfristi

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

Base64 décodé en image, révélant le mot de passe

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.

Alertes remontées par ZAP

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à.

sqlmap ne trouve pas d'injection

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 backdoor PHP exécute whoami et renvoie apache

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 :

Reverse shell obtenu avec netcat, utilisateur apache

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 notes.txt laissé par 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

La routine exécute notre chmod 777 surhome/admin

Après une minute, le dossier /home/admin est en 777 : on peut enfin lire son contenu.

Contenu du dossierhome/admin

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 fichier whoisyourgodnow.txt

Le script cryptpass.py confirme la logique de chiffrement :

Le script cryptpass.py

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 :

  1. ROT13 sur la chaîne -> on récupère une base64 (toujours inversée)
  2. On inverse la chaîne -> base64 propre, le = revient à la fin
  3. On décode le base64 -> le mot de passe en clair

Le ROT13 appliqué via dCode

Le base64 décodé donne le mot de passe

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 :

su fristigod avec le mot de passe trouvé

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 :

sudo -l pour fristigod

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 :

doCom refuse de s'exécuter : wrong user

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.

Analyse de doCom dans Ghidra

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 :

L'appel setuid(0) suivi de system()

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.

/etc/passwd : fristi a l'uid 503 mais 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 doCom avec l’uid de fristi (503) -> la vérification passe
  • doCom fait setuid(0) -> on bascule root
  • doCom exécute bash -> on obtient un shell root

Shell root et flag final

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.png ne doit jamais pouvoir être exécutée.
  • Routine runthis exé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 fait setuid(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.

This post is licensed under CC BY 4.0 by the author.