Behemoth - Ret2Lib & Function hijhacking
Behemoth est un niveau de la plateforme OverTheWire. La description est la suivante :
This wargame deals with a lot of regular vulnerabilities found commonly ‘out in the wild’. While the game makes no attempts at emulating a real environment it will teach you how to exploit several of the most common coding mistakes including buffer overflows, race conditions and privilege escalation.
Si les concepts de buffer-overflow sont nouveaux pour vous, l’article Protostar - Stack Buffer-Overflow permet d’avoir les bases, et des explications plus exhaustives.
Behemoth 0x01
Les différents challenges n’ont pas de descriptions. Seul l’accès aux binaires vulnérables est fournis. Pour ce premier niveau, il est nécessaire de contourner un mécanisme d’authentification : Il n’y a aucune chaîne de caractères dans le binaire qui s’apparentent à un mot de passe valide. En revanche, un ltrace permet d’observer les chaînes comparées dans la fonction strcmp du programme, et ainsi de récupérer le mot de passe attendu : Il ne reste plus qu’à passer ce mot de passe au binaire pour passer au niveau suivant :
Behemoth 0x02
Le prochain binaire à le même comportement que le niveau précédent, mais cette fois-ci, il n’y a pas de comparaison entre les chaînes de caractères. Un exploit de type buffer-overflow est donc envisageable sur la fonction gets, qui est vulnérable : D’autant plus que l’ASLR est désactivée sur la machine. En fuzzant le binaire, il se trouve que l’EIP est écrasé au bout de 71 bytes : Une première version de l’exploit peut donc être créé : Une charge utile est ensuite générée et ajoutée à l’exploit (ici, le payload va simplement lire le flag pour accéder au prochain niveau): Le shellcode est généré avec msfvenom:
msfvenom -p linux/x86/exec CMD=”cat /etc/behemoth_pass/behemoth2 > /tmp/a”
La prochaine étape consiste donc à récupérer une adresse avec laquelle écraser le registre EIP. Cette adresse doit pointer dans la chaine d’instructions NOPs. Il suffit de placer un breakpoint sur la fonction gets pour observer le positionnement de l’exploit dans le stack, et de récupérer une adresse pertinente. Ici, l’adresse 0xffffd6e0 pointe bien sur la NOP slide : La version finale de l’exploit est donc la suivante : En exécutant le binaire vulnérable, et en lui passant l’exploit en paramètre, le flag du prochain challenge est révélé :
Behemoth 0x03
Le binaire relatif à ce niveau ne semble rien faire de particulier. Pourtant, ltrace montre qu’un fichier est crée quelque part, avec la commande ‘touch’: Lorsqu’un programme appel une commande via la fonction system(), il est possible de hijacker le processus appelé en modifiant la variable d’environnement PATH. De ce fait, lorsque le programme va appeler une commande externe, le PATH pointera en premier vers ma propre version de la commande utilisée par le programme. Ceci permet d’exécuter du code depuis le compte système lié au binaire vulnérable (dans notre cas, un SUID vers Behemoth3). Il faut donc commencer par écrire un exécutable au nom de la commande à hijacker, soit “touch”. Puisque le but est de voler le flag pour passer au niveau suivant, je construis mon binaire de la façon suivante : Ce programme est compilé avec cc:
cc -o touch touch.c
La dernière étape consiste à modifier la variable d’environnement PATH en plaçant le répertoir dans lequel se trouve la version malicieuse de ‘touch’ avant le répertoire contenant la version légitime :
export PATH=/tmp/homardboy:/usr/local/bin:/usr/bin/bin:/usr/games
En lançant le programme, il est ainsi possible de récupérer le prochain flag, en détournant complètement le fonctionnement du binaire initial :