Guide CTF : Wonderland de TryHackMe

Table des matières

Wonderland est un défi de capture du drapeau (CTF, “capture the flag” en anglais), créé par NinjaJc01 et disponible gratuitement sur TryHackme. Dans ce guide CTF, nous allons tomber dans le terrier du pentesting et atterrir dans un étrange pays des merveilles, celui de la cybersécurité !

Illustration d'Alice au pays des merveilles, le thème du défi CTF de capture du drapeau Wonderland de NinjaJC01 sur le site d'apprentissage en cybersécurité TryHackMe.
Informations du CTF

Nom         : Wonderland
Difficulté  : Moyenne
Publié le   : 05/05/2020
Auteur      : NinjaJc01
URL         : https://tryhackme.com/room/wonderland

Sans révéler les solutions de ce défi, nous allons ici explorer de façon méthodique les processus d’énumération, d’exploitation et d’escalade des privilèges nécessaires pour réussir Wonderland de TryHackMe. Avec une machine virtuelle Linux pour cible, nous serons amenés à brute-forcer un site web, à trouver des identifiants pour se connecter via SSH, à détourner une librairie Python, à dé-compiler un programme et à exploiter une vulnérabilité de configuration.

Comment prendre part au défi Wonderland de TryHackMe ?

Pour prendre part au défi Wonderland, il faut créer un compte gratuit sur TryHackMe et se rendre à l’adresse suivante : https://tryhackme.com/room/wonderland. Le bouton “Start Machine” créera une nouvelle machine virtuelle dont on nous fournira l’adresse IP. C’est cette machine que nous devons exploiter afin de trouver les drapeaux et remporter la victoire.

Remarquons que l’adresse IP qu’on nous fournit une fois la machine démarrée commence par 10.10.x.x. C’est une adresse privée, ce qui indique que la machine est sur un réseau privé : celui de TryHackMe. On ne pourra donc y accéder que depuis ce même réseau privé.

TryHackMe propose deux moyens d’accéder à leur réseau :

  • AttackBox : une machine virtuelle Ubuntu hébergée dans le réseau et accessible depuis notre navigateur. Pour la lancer, il suffit de cliquer sur le bouton bleu “Start AttackBox”. La machine apparaît alors dans la fenêtre du navigateur. Celle-ci est équipée de tous les outils dont nous aurons besoin.
  • OpenVPN : Ceux qui souhaitent travailler depuis leur propre machine peuvent, en alternative, télécharger la configuration OpenVPN de TryHackMe. Ensuite, il suffit de lancer la commande sudo openvpn /chemin/vers/fichier.ovpn dans un terminal. Attention à ne pas fermer cette fenêtre pour ne pas interrompre la connexion ! Pour vérifier qu’on est bien connecté au réseau privé, on peut lancer la commande ping 10.10.10.10. Si on reçoit une réponse, c’est qu’on est bien connecté. En utilisant cette méthode, il est évidemment recommandé d’utiliser une machine virtuelle afin de ne pas compromettre son propre système d’exploitation. ParrotOS et Kali Linux sont de bons choix en termes de systèmes d’exploitation : tous deux ont les outils nécessaires aux audits intrusifs que nous devons effectuer.

Dans cet article, nous utiliserons le terme “machine locale” pour faire référence à la machine avec laquelle nous attaquons, qu’elle soit déployée dans le navigateur ou non. De même, nous utiliserons “machine Wonderland” pour désigner la cible de notre attaque.

Maintenant que nous nous sommes connectés au réseau TryHackMe depuis notre machine locale et que nous avons lancé la machine Wonderland, penchons-nous sur l’exploitation de cette dernière.

Énumérer Wonderland

La première étape de tout audit intrusif (“penetration testing” ou “pentesting” en anglais), c’est l’énumération. L’énumération, c’est le procédé par lequel on découvre d’éventuels vecteurs d’attaque qui peuvent nous mener à établir une connexion au système ciblé et l’exploiter. Lors de cette étape, on va chercher à en apprendre le plus possible sur notre cible : ses ports, ses services, ces utilisateurs, et toute autre information qui pourrait nous être utile.

Ping : tester la connexion à Wonderland

Commençons par un petit test non-intrusif : envoyer un petit paquet ICMP (“Internet Control Message Protocol”) avec l’outil ping pour voir si elle nous répond. Au moment de la rédaction de cet article, l’adresse IP de ma machine Wonderland était 10.10.11.241, mais tout le monde n’aura pas la même !

ping -c 3 10.10.11.241

Ici, l’option -c suivi d’un chiffre nous permet de spécifier combien de fois envoyer le paquet. Sans cette spécification, ping ne cessera pas d’envoyer ses paquets à moins d’être interrompu avec ctrl-c.

Si l’on reçoit une réponse de la machine ciblée, cela veut dire qu’elle est bel et bien en ligne et accessible depuis notre système. Par contre, si l’on ne reçoit aucune réponse, ce n’est pas pour autant qu’elle est inaccessible. Elle pourrait bien être protégée par un pare-feu qui inhibe ses réponses par mesure de sécurité.

Dans le cas d’une non-réponse, vérifions tout de même si nous sommes bien connectés au réseau TryHackMe en lançant un ping 10.10.10.10. TryHackme nous garantit que cette machine-là répond aux paquets ICMP lorsqu’on est correctement connecté au réseau.

Que la machine Wonderland réponde ou non, il nous faut de toutes façons des tests plus poussés pour l’analyser.

Nmap : tester les ports et services de Wonderland

Ce qu’on cherche à ce stade, c’est des ports par lesquels se connecter à la machine cible. Toute connexion entre deux ordinateurs se fait via un port. L’outil nmap (“network mapping” ou “cartographie du réseau” en français) est parfait pour ceci.

Muni de l’adresse IP qu’on lui fournit, nmap va pouvoir tester chaque port de notre cible afin de déterminer lesquels sont ouverts, fermés ou protégés par un pare-feu. Mieux, il sait même identifier les services qui y opèrent ainsi que détecter leurs versions et systèmes d’exploitations dans certains cas. Pour nous fournir ces informations, nmap envoie des paquets à chaque port possible et imaginable et interprète les réponses qu’il reçoit. Laçons-le contre cette IP :

nmap -vv -sV 10.10.11.241 | tee nmap.log

Décrivons rapidement les options de cette commande :

  • -vv augmente la verbosité de la sortie de nmap. Comme nous souhaitons avoir autant d’informations que possible, c’est toujours une bonne idée de l’inclure.
  • -sV indique à nmap de tenter de déterminer le service qui opère sur les ports ouverts qu’il découvre

Nous redirigeons la sortie de nmap vers un autre programme tee, qui prend en paramètres un fichier. L’outil tee permet à la fois d’afficher la sortie de la commande précédente sur la sortie standard (le terminal) et de la sauvegarder dans un fichier, nmap.log. De cette façon, on pourra y retourner au besoin, sans avoir à relancer l’analyse nmap. En effet, l’analyse peut prendre plusieurs minutes, vu que nmap teste chaque port de la cible, et qu’une machine en a généralement 65 536 !

Résultat de la commande nmap contre la machine virtuelle Wonderland dans le défi CTF de capture du drapeau de TryHackMe

L’option -vv a été omise dans cette commande par souci de brièveté.

Le résultat nous indique que la machine Wonderland a deux ports ouverts :

  • le port 22, qui est le port par défaut du protocole SSH (“secure shell”). C’est une bonne nouvelle : SSH nous permettra sans doute d’accéder à la machine à distance via notre terminal, sous condition de trouver des identifiants.
  • le port 80, qui est le port par défaut du protocole HTTP. Cette machine gère donc un site web, qu’on pourra peut-être exploiter, ou du moins explorer.

Grâce à l’analyse de nmap, on sait aussi que la machine Wonderland tourne sous Ubuntu Linux.

Port 80 : le site Wonderland

Allons tout d’abord voir ce site internet, puisque dans identifiant, il n’y a pas grand espoir de pouvoir se connecter via SSH. Dans notre navigateur, nous pouvons simplement mettre l’adresse IP de la cible dans la barre de navigation.

Page d’accueil du site web hébergé sur la machine virtuelle Wonderland dans le défi CTF de capture du drapeau de TryHackMe

À première vue, le site est très simple : uniquement du texte et une image. Il n’y a pas de liens ou de menu.

On peut aller voir le code source de la page, au cas où il y aurait des informations cachées. Chaque navigateur est différent, mais en général, il suffit de faire un clic droit sur la page et de sélectionner “voir le code source”. Manque de chance, on n’y trouve rien de suspect.

Mais le code source n’est pas le seul endroit où on pourrait cacher quelque chose…

Stéganographie : extraire des messages cachés dans des images

La stéganographie est une pratique voisine à la cryptographie. Elle consiste à dissimuler des informations à l’intérieur d’un autre message ou objet. On peut par exemple cacher un message, une image, une vidéo ou tout autre fichier à l’intérieur d’un autre fichier, d’une autre vidéo, d’une autre image ou d’un autre message.

L’image qu’on nous présente sur le site de la Wonderland semble tout à fait ordinaire, mais pourrait-elle cacher un message ? Téléchargeons l’image avec wget pour en avoir le cœur net :

wget http://10.10.11.241/img/white_rabbit_1.jpg

Le programme steghide est un outil parmi d’autres qui permet d’extraire un message d’un fichier .jpeg, .bmp, .wav ou .au, s’il y en a un. Tentons cela :

steghide extract -sf white_rabbit_1.jpg

On nous demande une phrase secrète. Comme on n’en a pas, appuyons directement entrée sans rien taper avant. steghide nous informe qu’il a extrait les données vers un nouveau fichier, hint.txt.

cat hint.txt

Résultat de l’extraction sténographique de l’image sur la page d’accueil du site hébergé sur la machine virtuelle Wonderland dans le défi CTF de capture du drapeau de TryHackMe

Ah, un indice ! Comme sur le site web, on nous invite à suivre le lapin. Mais l’espacement des lettres de “rabbit” est pour le peu intriguant… On a maintenant un indice, mais rien d’autre.

Nous avons trouvé quelque chose de caché sur la page, mais qu’en est-il du reste du site ? Il n’y a aucun lien, mais peut-être y a-t-il tout de même d’autres pages ou d’autres répertoires…

Gobuster : trouver les répertoires d’un site web

Il y a plusieurs outils pour tenter de découvrir tous les fichiers et répertoires d’un site web, et parmi eux, gobuster. Cet outil nous permet entres autres, de brute-forcer la découverte d’URIs (fichiers et dossiers) ou de sous-domaines d’un site web.

Pour cela, on doit lui fournir d’adresse IP ou l’URL d’un site web ainsi qu’un dictionnaire de mots à essayer. Ensuite, gobuster se charge d’ajouter chaque mot du dictionnaire à l’adresse du site et de faire une requête au serveur. Si le serveur répond avec un code correct, gobuster nous indique que la page existe. Voyons s’il nous trouve quelque chose :

gobuster dir -u 10.10.11.241 -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt | tee gobuster.log

Regardons les options de cette commande de plus près :

  • dir (“directory”) indique à gobuster qu’on cherche à trouver des sous-répertoires, et non des sous-domaines par exemple.
  • -u signale que le prochain paramètre sera l’URL ou l’adresse IP du site à découvrir.
  • -w annonce que le paramètre suivant est le dictionnaire de mots à utiliser. Ici, on utilise un petit dictionnaire de mots fréquemment utilisés pour les sous-répertoires. Bien évidement, un dictionnaire plus long permet plus de précision et de découvertes, au prix d’un plus long temps de traitement. Il y a beaucoup de dictionnaires disponibles en ligne, la collection SecLists est populaire de par son exhaustivité.

Et comme toujours, c’est une bonne idée de conserver le résultat de gobuster dans un fichier, par exemple gobuster.log, pour ne pas avoir à relancer le processus qui peut prendre du temps.

Résultat de la découverte brute-force de gobuster contre le site web hébergé sur la machine virtuelle Wonderland dans le défi CTF de capture du drapeau de TryHackMe

On voit que gobuster a trouvé quelques sous-répertoires valides sur Wonderland, dont /img, /poem et /r. Allons donc visiter l’adresse 10.10.11.241/img qui contient l’image sur la page d’accueil qu’on a déjà analysée mais aussi quelques autres images. Nous pouvons les télécharger et les analyser aussi. La page 10.10.11.241/poem, contient, on l’aura deviné… un poème ! Cependant, le sous-dossier /r semble particulièrement intriguant, allons donc voir 10.10.11.241/r.

On y trouve encore une miette de l’histoire d’ Alice au Pays des Merveilles, mais pas grand chose d’autre. Le code source ne révèle rien non plus.

Retournons donc à notre cher gobuster et lançons une nouvelle analyse sur ce sous-répertoire, au cas-où :

gobuster dir -u 10.10.11.241/r -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt | tee gobuster-2.log

Voilà un répertoire qu’on avait pas trouvé avant : /a ! Par défaut, gobuster ne tente pas de chercher les sous-répertoires des sous-répertoires, cela prendrait très longtemps. Il faut dont toujours penser à relancer gobuster pour les sous-répertoires si besoin est.

Visitons donc l’adresse 10.10.11.241/r/a dans notre navigateur. La page existe et on peut y lire la prochaine ligne de l’histoire. Il n’y a rien d’autre d’intéressant sur cette page.

Maintenant, on pourrait retourner de nouveau voir si gobuster peut nous trouver un autre sous-répertoire. Mais nos pouvoirs de déduction viennent à notre secours : avec l’indice de l’image stéganographique, “Follow the r a b b i t”, on se rend vite compte dans quelle direction on s’en va ! Clairement, on suivre le /r/a/b/b/i/t.

Voir le code source : lire l’HTML d’une page web

Quand on arrive sur la page 10.10.11.241/r/a/b/b/i/t, on y trouve encore un morceau de l’histoire et une image. On peut tenter d’extraire des informations dissimulées dans cette dernière s’il y en a. Mais jetons d’abord un œil au code source.

Code source de la page finale du site web hébergé sur la machine virtuelle Wonderland dans le défi CTF de capture du drapeau de TryHackMe

Que trouvons-nous ici ? Un paragraphe invisible contenant un identifiant en clair, celui d’Alice ! Il est écrit dans le format très courant : utilisateur:mot_de_passe.

Se connecter à Wonderland via SSH

Maintenant qu’on a un identifiant, on devrait pouvoir prendre pied dans le système de la machine Wonderland. Comme il n’y a aucune page de connexion sur ce site web, l’identifiant sert sans doute à se connecter via le port SSH.

Consultons notre sauvegarde de notre analyse nmap. On y trouve le port 22 qui a un service SSH. Comme 22 est le port par défaut de SSH, on n’aura pas besoin de spécifier l’option -p 22 dans notre commande :

Saisissons le mot de passe qu’on a trouvé dans le code source. Nous voilà connecté à l’utilisateur Alice !

À ce stade, il est possible de trouver le drapeau user.txt qu’il nous faut. L’explication sera en blanc sur blanc ci-dessous, pour ceux qui ne souhaitent pas déduire l’emplacement de ce drapeau à partir de l’indice sur la page Wonderland de TryHackMe. Il y aura toujours l’occasion de trouver ce drapeau plus tard.


L’indice sur la question user.txt sur la page Wonderland de TryHackMe nous dit “Everything is upside down here” : “tout est à l’envers, ici”. Quand on regarde dans son répertoire, on voit qu’Alice a un fichier root.txt qu’elle ne peut pas lire. Renversons cette idée : peut-être root a-t-il un fichier user.txt qu’Alice peut lire ? Alice ne peut pas se déplacer dans le répertoire root ni même regarder ce qu’il contient. Mais si elle a les permissions de lecture pour ce fichier en particulier, est-ce qu’elle ne pourrait pas faire un cat /root/user.txt ?


Escalader les privilèges dans Wonderland

Maintenant qu’on a un accès à la machine Wonderland, notre but est d’escalader les privilèges jusqu’à pouvoir devenir root, le super-utilisateur du système.

En lançant la commande ls -l on peut voir qu’Alice a un fichier root.txt, mais malheureusement, ce fichier ne lui appartient pas. Elle n’a pas les permissions nécessaires pour lire le drapeau qui s’y trouve. On trouve aussi ici un script intéressant en Python, walrus_and_the_carpenter.py.

Si l’on cd .. vers le dossier /home, on peut aussi voir qu’il y a 3 utilisateurs, Alice, Rabbit et Hatter. Bien sûr, Alice n’a pas les permissions d’aller explorer ce qu’il y a dans leurs répertoires.

Justement, voyons les limites des permissions d’Alice avec sudo. Le programme sudo est un moyen sécurisé de permettre à un utilisateur autorisé de lancer certaines commandes avec les permissions root.

sudo -l

Ici, l’option -l indique à sudo de nous faire une liste des commandes autorisées et interdites pour l’utilisateur qui l’invoque, donc dans ce cas, Alice. Le résultat nous montre quelque chose de très intéressant :

Résultat de la commande sudo -l qui montre les permissions de l’utilisateur alice de la machine virtuelle Wonderland dans le défi CTF de capture du drapeau de TryHackMe

Alice a donc la permission d’utiliser sudo pour lancer le script qui se trouve dans son répertoire en tant que l’utilisateur Rabbit. Cela veut dire que si on arrive à insérer du code malicieux dans ce script, et qu’on le lance avec sudo en spécifiant l’utilisateur Rabbit, on pourrait potentiellement accéder au shell de Rabbit. En voilà un bon vecteur d’escalade de privilèges ! Penchons-nous donc sur ce script.

Exploitation du script en Python

Malheureusement, Alice n’a pas les privilèges d’écriture pour directement modifier le script en Python. Mais avec quelques recherches sur l’escalade des privilèges à l’aide d’un script en Python, on tombe vite sur l’idée de détournement des librairies.

En examinant le fichier /home/alice/walrus_and_the_carpenter.py, on peut voir la première instruction : import random. Il importe donc le module random.py de la librairie Python. Mais comment Python fait-il pour trouver le fichier à importer ? Nous allons pouvoir répondre à cette question avec la commande suivante :

python3 -c 'import sys; print(sys.path)'

On demande ici à Python3 d’exécuter le code qui suit l’option -c. Le code importe la librairie système pour pouvoir imprimer sys.path, un tableau de chemins où pourrait se trouver les modules de ses librairies.

Résultat de l’analyse du script python chez l’utilisateur alice de la machine virtuelle Wonderland dans le défi CTF de capture du drapeau de TryHackMe

Python cherche dans chacun de ces chemins, de gauche à droite, en espérant tomber sur le bon module à importer. Le résultat de cette commande nous montre que tout d’abord, Python regarde dans le répertoire ''. Ça ne semble pas être grand chose mais c’est une très bonne nouvelle : '' indique le répertoire actuel, celui dans lequel le script lui-même se trouve !

C’est l’occasion pour nous de créer notre propre script random.py dans le même répertoire que walrus_and_the_carpenter.py ( /home/alice/). Lors de l’exécution du script, Python cherchera random.py en premier lieu dans le répertoire actuel ( /home/alice). Il tombera sur notre script, qu’il se contentera d’importer tel quel sans aller chercher plus loin. Il exécutera donc notre version malicieuse de random.py plutôt que le module de la librairie Python. Mais qu’allons-nous bien pouvoir y mettre ? On a mille et une options, dont deux qu’on va explorer ci-dessous.

Option 1 : obtenir un shell avec /bin/bash

L’option la plus simple est probablement de tenter d’obtenir un shell avec le code suivant dans notre script random.py :

import os
os.system('/bin/bash')

Puis, on peut ensuite exécuter la commande sudo en spécifiant l’utilisateur Rabbit avec l’option -u :

sudo -u rabbit /usr/bin/python3.6 /home/alice/walrus_and_the_carpenter.py

Résultat de l’exploit d’obtention du shell de l’utilisateur rabbit depuis l’utilisateur alice dans la machine virtuelle Wonderland du défi CTF de capture du drapeau de TryHackMe

Et voilà, le tour est joué ! Comme on peut le voir dans l’invite des commandes et le confirmer en lançant la commande id ou encore whoami, on est maintenant Rabbit !

Option 2 : autoriser une nouvelle clef SSH

Une autre option serait d’ajouter notre clef SSH publique dans le fichier des clefs autorisées de l’utilisateur Rabbit. Cela nous permettra de nous connecter à l’utilisateur Rabbit via SSH sans devoir fournir de mot de passe.

Tout d’abord, générons une paire de clefs SSH dans notre machine locale. Nous allons générer des clefs de type RSA puisque touts les systèmes ne sont pas garantis de pouvoir gérer les clefs plus récentes et plus efficaces, de type ed25519.

ssh-keygen -t rsa

Nous avons maintenant une paire de clefs SSH dans notre répertoire ~/.ssh : une privée qu’on ne va jamais partager, et une publique, qu’on veut mettre chez Rabbit sur Wonderland.

Toujours depuis notre machine locale, copions la clef publique (jamais la clef privée !) vers le répertoire d’Alice sur la machine Wonderland à l’aide de scp, l’outil de copie sécurisé :

scp ~/.ssh/id_rsa.pub [email protected]:id_rsa.pub

Après avoir saisi le mot de passe d’Alice, le fichier devrait apparaître dans son répertoire /home/alice. Maintenant que la clef est prête, on va pouvoir exploiter le script en Python pour l’ajouter à /home/rabbit/.ssh/authorized_keys.

De retour dans la machine Wonderland, créons notre script random.py dans le même répertoire que le script /home/alice/walrus_and_the_carpenter.py. On le fera tout d’abord exécuter cette commande :

mkdir -p /home/rabbit/.ssh && cat /home/alice/id_rsa.pub >> /home/rabbit/.ssh/authorized_keys

Avec cette commande, on crée le dossier /home/rabbit/.ssh au cas où il n’existe pas déjà. Ensuite, on ajoute le contenu de la clef au fichier /home/rabbit/.ssh/authorized_keys. Si ce fichier n’existe pas, il sera créé.

Mais ce n’est pas tout. Il nous faut lancer une deuxième commande pour gérer les permissions dans le cas où on doit créer le répertoire .ssh et/ou le fichier authorized_keys. Pour des raisons de sécurité, SSH rejette la connexion sans mot de passe si le dossier .ssh a des permissions supérieures à 700 ( rwx------). De même si le fichier authorized_keys a des permissions plus importantes que 600 ( rw-------). La commande sera donc :

chmod 700 /home/rabbit/.ssh && chmod 600 /home/rabbit/.ssh/authorized_keys

Mettons ces deux commandes dans notre script random.py :

import os
os.system('mkdir -p /home/rabbit/.ssh && cat /home/alice/id_rsa.pub >> /home/rabbit/.ssh/authorized_keys')
os.system('chmod 700 /home/rabbit/.ssh && chmod 600 /home/rabbit/.ssh/authorized_keys')
print('Exploit successful: ssh key injected.')

Enfin, on peut exécuter la commande sudo en spécifiant l’utilisateur Rabbit avec l’option -u :

sudo -u rabbit /usr/bin/python3.6 /home/alice/walrus_and_the_carpenter.py

Résultat de l’exploit par clef ssh de l’utilisateur rabbit par l’utilisateur alice de la machine virtuelle Wonderland dans le défi CTF de capture du drapeau de TryHackMe

Comme le script a été exécuté en tant que Rabbit et non Alice, et que Rabbit a naturellement les permissions de lecture et d’écriture dans son propre répertoire, notre script ne devrait pas rencontrer d’erreur. Pour s’en assurer, déconnectons-nous de l’utilisateur Alice avec la commande exit, puis tentons de nous reconnecter à l’utilisateur Rabbit :

Résultat de la l’insertion de la clef ssh chez l’utilisateur rabbit de la machine virtuelle Wonderland dans le défi CTF de capture du drapeau de TryHackMe

Parfait, on ne nous demande pas de mot de passe pour la connexion SSH !

Quoiqu’un peu plus complexe que l’option précédente, cette méthode peut être particulièrement utile puisqu’elle nous crée, de fait, une porte dérobée. Si on perd la connexion à notre machine Wonderland, par exemple, on pourra se reconnecter sans devoir repasser par Alice. Dans les CTFs plus compliqués, laisser ce genre de clef fonctionnera comme une sauvegarde de notre progrès pour ne pas avoir à relancer un exploit en plusieurs étapes, selon la difficulté d’obtention du shell.

Exploitation du programme teaParty

Le seul fichier qu’on trouve dans le répertoire de Rabbit est ce qui semble a première vue être un exécutable nommé teaParty. Déterminons tout d’abord son type avec l’outil file et puis lançons-le pour voir ce qu’il fait.

Analyse du programme teaParty de type setuid chez l’utilisateur rabbit de la machine virtuelle Wonderland dans le défi CTF de capture du drapeau de TryHackMe

On nous dit que le chapelier fou arrivera probablement l’heure suivant l’heure actuelle. Quand on appuie sur entrée, le programme se termine en un joli segfault. Il est peu probable que le chapelier fou nous laisse entrer même au bout d’une heure comme le suggère le programme !

Le type de ce fichier est extrêmement prometteur, par contre. setuid, c’est un paramétrage qui autorise un utilisateur à exécuter un processus ou un fichier avec les permissions de son propriétaire. Le propriétaire de teaParty étant root, ceci est sans aucun doute un vecteur d’attaque. Notons aussi les permissions de ce fichier : rws et non le plus courant rwx. La permission s nous indique déjà même sans avoir lancé la commande file, que ce fichier est de type setuid.

Tentons de dé-compiler le programme teaParty pour voir son code source. On ne sait pas dans quelle langue il a été écrit, mais le binaire devrait pouvoir être retraduit en Assembleur, puis en C. Pour cela, retournons sur notre machine locale pour y copier le fichier teaParty afin de l’analyser.

scp [email protected]:teaParty .

Pour dé-compiler le programme, nous allons utiliser Ghidra, un programme de rétro-ingénierie des logiciels. Toujours sur notre machine locale, lançons Ghidra et créons un nouveau projet en sélectionnant son menu File > New Project.... Le projet est vide, mais on peut y importer le programme à analyser en sélectionnant le menu File > Import File.... Évidemment, on va choisir teaParty. On peut laisser toutes les options par défaut.

Maintenant, on peut cliquer droit sur teaParty et sélectionner Open with... > CodeBrowser :

Importation du programme teaParty dans Ghidra pour dé-compilation dans le défi CTF de capture du drapeau Wonderland de TryHackMe

Ghidra va nous demander si on souhaite analyser le programme, cliquons “yes”. Maintenant, on peut voir le code en langage assembleur, ce qui n’est pas très aisé à lire pour nous les humains… Tentons de traduire la fonction main en C.

Pour cela, ouvrons la fenêtre dé-compilation si elle ne l’est pas déjà en sélectionnant le menu Window > Decompiler. Puis, dans le menu Symbol Tree à gauche de la fenêtre, trouvons la fonction main. Si l’on clique dessus, le code source en C s’affiche dans la fenêtre décompilation.

Résultat de la dé-compilation du programme teaParty dans Ghidra dans le défi CTF de capture du drapeau Wonderland de TryHackMe

Regardons ce code de plus près :

Code source du programme teaParty dé-compilé par Ghidra dans le défi CTF de capture du drapeau Wonderland de TryHackMe

La première chose dont on s’aperçoit c’est que le segfault n’est même pas un vrai segfault ! Et il n’y a pas non plus de compte à rebours, donc aucun espoir que le Hatter arrive à l’heure qu’on nous dit !

Le programme teaParty définit en premier lieu l’identifiant de l’utilisateur avec setuid à 0x3eb en hexadécimal. Une petite conversion nous indique 1003 en décimal. Sur la machine Wonderland, on peut lancer la commande id 1003 pour découvrir qu’il s’agit de Hatter. C’est donc en réalité lui qui va exécuter le reste de ce processus, et non root ou Rabbit.

Remarquons aussi que pour afficher la date et l’heure, teaParty fait appel au programme date, mais sans en spécifier le chemin absolu ( /bin/date). De ce fait, au lieu de pouvoir directement exécuter /bin/date, le shell va devoir chercher pour le trouver. Il va d’abord consulter la variable PATH de son environnement pour récupérer la liste des répertoires où pourrait se trouver un programme. L’absence de chemin absolu nous permet donc de créer notre propre programme nommé date qui pourra contenir des commandes malicieuses. Ensuite, il suffira d’ajouter le répertoire dans lequel se trouve notre programme à la variable d’environnement PATH.

On est dans la même situation que chez Alice avec le script en Python : on a un programme vulnérable qui peut être exécuté avec les privilèges d’un autre utilisateur. Un programme qui fait appel à un script externe de manière non sécurisée. Nos options d’exploitation sont donc identiques, au final.

Créons d’abord notre propre script date, qu’on peut mettre dans le répertoire /tmp, par exemple.

Option 1 : obtenir un shell avec /bin/bash

Pour obtenir un shell, nous allons simplement mettre la commande suivante dans /tmp/date :

#!/bin/bash
/bin/bash

Il ne faudra pas oublier de rendre ce script Bash exécutable avec la commande :

chmod +x /tmp/date

Puis, ajoutons le répertoire dans lequel se trouve notre script (ici, /tmp) au début de la variable d’environnement PATH pour que notre shell puisse le trouver en premier :

export PATH=/tmp:$PATH

Résultat de l’exploit d’obtention du shell de l’utilisateur hatter depuis l’utilisateur rabbit dans la machine virtuelle Wonderland du défi CTF de capture du drapeau de TryHackMe

Et voilà ! Nous sommes maintenant Hatter. Dans /home/hatter, nous trouverons un fichier password.txt qui contient son mot de passe en clair.

Option 2 : autoriser notre clef SSH

Comme précédemment pour accéder à Rabbit, nous pouvons mettre les deux mêmes commandes dans notre /tmp/date :

#!/bin/bash
mkdir -p /home/hatter/.ssh && cat /home/alice/id_rsa.pub >> /home/hatter/.ssh/authorized_keys
chmod 700 /home/hatter/.ssh && chmod 600 /home/hatter/.ssh/authorized_keys

N’oublions pas de rendre ce script exécutable :

chmod +x /tmp/date

Puis, pour que le shell trouve notre date avant /bin/date, ajoutons le répertoire dans lequel se trouve notre script (ici, /tmp) au début de la variable d’environnement PATH :

export PATH=/tmp:$PATH

Enfin, on va pouvoir exécuter de nouveau le programme teaParty.

Résultat de l’exploit d’insertion de clef ssh chez l’utilisateur hatter depuis l’utilisateur rabbit dans la machine virtuelle Wonderland du défi CTF de capture du drapeau de TryHackMe

On peut maintenant se déconnecter de Rabbit avec exit et se reconnecter en tant que Hatter sans avoir à renseigner de mot de passe :

Connexion de l’utilisateur hatter via SSH à la machine virtuelle Wonderland du défi CTF de capture du drapeau de TryHackMe

Parfait, nous sommes maintenant Hatter. Son répertoire /home/hatter contient un fichier password.txt qui contient son mot de passe, mais avec cette méthode, on n’en aura pas besoin.

LinPEAS : énumération des vulnérabilités

En examinant les fichiers et les privilèges de l’utilisateur Hatter, on ne trouve pas à première vue de vecteurs d’attaque flagrants. Faisons donc appel à un script d’énumération automatique pour nous montrer les possibilités d’escalade de privilèges sur la machine Wonderland.

LinPEAS (“Linux Privilege Escalation Awesome Script”) est facile d’utilisation et nous indique clairement les vulnérabilités qu’il trouve. Il affiche en rouge les configurations suspectes, et les signale en rouge sur jaune lorsqu’elles sont garanties à 99% d’être un vecteur d’escalade de privilèges.

Téléchargeons donc le script sur notre machine locale :

curl -L https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh > linpeas.sh

N’oublions pas de le rendre exécutable :

chmod +x linpeas.sh

Puis, copions ce fichier vers Hatter sur Wonderland. Si on a mis notre clef publique chez Hatter, scp ne nous demandera pas de mot de passe, mais dans le cas contraire, on devrait avoir trouvé le mot de passe dans son fichier /home/hatter/password.txt.

scp linpeas.sh [email protected]:linpeas.sh

De retour sur la machine Wonderland, exécutons le script en sauvegardant les résultats dans un fichier linpeas.log :

./linpeas.sh | tee linpeas.log

Quelque part au milieu de tous ces résultats, on remarquera quelque chose en rouge sur jaune :

Résultat de l’analyse linPEAS chez l’utilisateur hatter dans la machine virtuelle Wonderland du défi CTF de capture du drapeau de TryHackMe

Il y a une mauvaise configuration des programmes /usr/bin/perl5.26.1 et /usr/bin/perl. Comme le teaParty dans Rabbit, ils ont les capacités setuid ! Voilà quelque chose qu’on va pouvoir exploiter.

Exploitation de la configuration Perl

Quelques recherches sur le Perl et particulièrement l’escalade de privilèges avec Perl nous révèlent la commande à utiliser pour obtenir un shell root :

/usr/bin/perl -e 'use POSIX (setuid); POSIX::setuid(0); exec "/bin/bash";'

Ici, on lance /usr/bin/perl avec l’option -e qui nous permet d’ensuite spécifier le bout de code à exécuter. Les instructions qui suivent sont :

  • use POSIX (setuid); : on déclare l’utilisation de setuid,
  • POSIX::setuid(0); : on indique l’identifiant numérique de l’utilisateur root, 0,
  • exec "/bin/bash"; : on exécute le shell Bash.

Après avoir exécuté la commande, on obtient un shell root ! On peut maintenant aller voir les drapeaux :

# cat ~root/user.txt
# cat ~alice/root.txt

Résultat de l’exploit d’obtention du shell de l’utilisateur root depuis l’utilisateur hatter dans la machine virtuelle Wonderland du défi CTF de capture du drapeau de TryHackMe

Victoire !

Conclusion du CTF Wonderland

Le CTF Wonderland de TryHackme souligne l’importance des configurations de permissions et la susceptibilité de setuid dans un système Linux.

L’exploitation de la librairie du script Python pour obtenir le shell de Rabbit n’était possible que par une mauvaise configuration de sudo qui permettait à Alice d’exécuter ce script en tant que Rabbit. Cela met l’accent sur l’importance de la configuration correcte de sudo.

Le programme teaParty était sensible de par sa capacité à définir un identifiant avec setuid. Et le fait qu’il fasse appel à un programme externe sans spécifier un chemin absolu l’a rendu vulnérable à notre manipulation de son environnement. L’utilisation inappropriée de setuid pose donc un risque lorsque l’exécutable n’est pas soigneusement conçu.

Enfin, la mauvaise configuration de Perl qui lui donnait la capacité setuid nous a permis de changer d’identifiant utilisateur comme bon nous semblait. Cette capacité à manipuler l’identifiant de l’utilisateur d’un processus en cours est un risque sécuritaire. Elle ne devrait pas être accordée aux exécutables à la légère.

Merci à NinjaJc01 pour ce défi intéressant et très éducatif !


Une autre astuce à partager, une question à poser, ou une découverte intéressante à propos des vulnérabilités exposées dans Wonderland de TryHackMe ? Je serai ravie de lire et de répondre à chaque commentaire. Bon CTF !

Sources et lectures supplémentaires

Commentaires

Articles connexes

Envoyer et intercepter un signal en C

À force d’être confrontés à des segfaults ou a des erreurs de bus, on se sera déjà familiarisé avec l’idée d’un signal informatique.

Lire la suite

Programmation réseau via socket en C

Dans ce monde informatique ultra-connecté, il est crucial de savoir comment envoyer et recevoir des données à distance, grâce aux sockets.

Lire la suite

Malloc : allouer de la mémoire en C

Dans les langages de programmation compilés comme le C, il est souvent intéressant voire nécessaire d’allouer de la mémoire de façon dynamique sur le tas, pour accommoder des variables de grande taille ou de taille incertaine.

Lire la suite