Analyse de programmes avec GCC et GDB

Création de l’exécutable à tester avec GCC puis présentation des principales commandes de GDB pour analyser des buffer overflows

Configuration

Attention : Les manipulations suivants sont à faire dans un environnement dédié, par exemple une machine virtuelle. Elles rendent votre machine vulnérable à de potentielles attaques.

Désactiver l’ASLR :

sudo bash -c "echo 0 > /proc/sys/kernel/randomize_va_space"

L’ajout de bash -c permet de conserver les droits sudo durant l’exécution de la commande.

Compilation avec GCC

Désactiver les protections sur la pile au moment de la compilation de votre programme c

gcc -m32 -fno-stack-protector -no-pie −z execstack −o prg prg.c

Le flag -m32 nécessite, sur Ubuntu, d’avoir installé gcc multilib

sudo apt-get install gcc-multilib

Source : https://askubuntu.com/questions/453681/gcc-wont-link-with-m32

Explications des flags

Flags gcc Explication
-fno-stack-protector Désactiver la protection sur la pile (stackoverflow)
–fstack-protector Activer la protection sur la pile
execstack Autoriser l’exécution de la pile
-no-pie Ne pas produire de lien dynamique indépendant de l’exécutable
-m32 Pour compiler en 32 bits

Source intéressante pour les protections sur la pile : www.intel.com - compiler-option-details - fstack-protector.html

Dans gdb, si vous voulez utiliser des shellcodes, il faut l’autoriser à ouvrir un processus fils.

(gdb) set follow-fork-mode parent

Vérification :

readelf -l nom_programme

Puis sous GNU_STACK, vérifier que le flag est mis à RWE.

GBD - Liste de commandes

Commande de base

Voici les commandes utiles pour une analyse pas à pas

Les parties entre crochet [] doivent être remplacé par le contenu souhaité

Commandes Explication  
gdb ./buffer Lancer gdb avec le binaire  
b main Mettre un breakpoint sur la fonction main  
b *0xFFFF8765 Breakpoint à une adresse. Ne pas oublier de mettre *  
r [args] Ex : r aabbbb Lancer le programme dans gdb avec les arguments args  
disas Désassembler le programme  
c Continuer le programme après s’être arrêté à un breakpoint  
finish Continuer l’exécution jusqu’à après le retour de la fonction en cours. Utilise si vous voulez vous retrouver juste après un call  
quit quitter gdb  
kill stopper l’exécution du programme  

Commandes pour une analyse avancée

CMD Explication
x/-10bs $ebp Afficher les 10 1ers bytes de la pile
x/s [adr] Affiche en string le contenu situé à l’adresse
x/x [adr] Afficher le byte situé à l’adresse en hexa
x/w [adr] Affiche 8 bytes du contenu de adr
x/a [adr] Afficher le contenu comme une adresse. Utile pour afficher l’adresse contenue dans un pointeur
p/x $ebp Obtenir l’adresse de ebp. Utilise pour ensuite écraser la valeur de eip, situé 4 byte plus loin(si adresse 32 bits)
p/s 0x804b048 Afficher la string située à l’adresse 0x804b048. Utile pour print des inputs/buffers
info symbol 0x804a1e0 Obtenir le symbole correspondant à l’adresse. C’est pratique si on a par exemple des movl avec des pointeurs de fonctions et qu’on voudrait savoir quel est le nom de la fonction correspondante

Analyse du programme

CMD  
info frame Afficher infos sur la pile
info functions Afficher toutes les fonctions et leur adresse
   

Astuces

Il est possible de passer du code python en argument dans gdb. Ici cela aura pour résulta tde passer AAAAAAAAAA en argument du programme

run `python2 -c 'print("A" * 10)'`

Si vous souhaitez avoir la notation assembleur d’Intel, vous pouvez configurer cela avec la commande suivante :

set disassembly-flavor intel

Exemples

Afficher une variable locale

Cet exemple montre comment afficher une variable locale. La variable locale sera ici un pointeur sur une fonction.

#include <stdlib.h>
#include <stdio.h>

void fun() {
    printf("fun\n");
}

int main(int argc, char **argv) {
    void (*ptr_fun)();
    char buffer[20]={0};
    ptr_fun=fun;
    ptr_fun();
    return 0;
}

Compilation (32 bits):

gcc -m32 -fno-stack-protector -no-pie test.c -o test

Tout d’abord, on peut afficher toutes les fonctions afin de récupérer l’adresse de fun

afficher-fonction

Une instruction intéressante si on souhaite connaitre l’adresse d’une fonction :

info address nomFonction

Ensuite, on peut mettre un breakpoint là où s’effectue l’instruction call. C’est cette instruction qui va faire que le programme saute à l’adresse contenue dans fun. Une autre instruction intéressante est l’instruction lea. Celle-ci permet de loader une adresse mémoire à un emplacement mémoire ou un registre. Une fois le breakpoint mis, on lance le programme avec r.

fonction-breakpoint

Puis on peut afficher la valeur de la variable locale en récupérant l’adresse de esp et en additionnant sa valeur avec l’offset indiqué que l’on peut voir en jaune avec le disas main.

afficher-valeur-variable

Sources

You might also enjoy