Frage zu Bufferoverflow



  • Hallo ich hab ein einfach kleines Programm in C geschrieben welches für einen Buffer Overflow anfällig ist.

    Das verwundbare Programm:

    char name[10]; = 10 Hex = 16 Dezimal

    int ret; = 4 Byte

    20 Byte = Buffer Overflow

    Ein Exploit dafür habe ich auch schon und es funktioniert ohne Probleme.

    Nur ein verstehe ich nicht ganz wieso 20 Bytes ?

    Muss ich nicht eigentlich nur den Puffer überschreiben ( char name[10]; )

    Wieso muss ich noch 4 Bytes dazu rechnen damit der return Befehl der Funktion überschrieben wird ?

    Hat da wer zufällig Ahnung von ?

    Mein erklärung dafür:

    LEA EAX,DWORD PTR SS:[EBP-10] <-- 16 Byte Puffer hier in der Funktion
    CMP DWORD PTR SS:[EBP-4],0

    EBP - 16 Byte
    EBP - 4 Byte
    ------------
    20 Byte

    Mit dieser Theorie hat es auch funktioniert wenn in der Funktion
    z.b. so etwas stand

    int ret;
    int var;
    char name[10];

    Also das vor dem Puffer nochmal 2 andere Variablen sind aber wieso müssen die auch überschrieben werden ?

    #include <stdio.h>
    #include <string.h>
    
            int funktion(void)
            {
            int ret;
            char name[10];
    
                    printf("Name: ");
                    fflush(stdout);
    
                    gets(name);
    
                    ret = strcmp(name, "abc");
    
                    if (ret == 0)
                    {
                    printf("ok message aus funktion\n");
    
                    return 1;
                    }
    
                    if (ret != 0)
                    {
                    printf("err message aus funktion\n");   // diese message wird bei dem buffer overflow exploit immer ausgeführt
                    return 0;
                    }
    
            }
    
    int main(int argc, char *argv[])
    {
    int var;
    
    var = funktion();
    
            if (var == 1)
            {
                    printf("OK Message aus Hauptprogramm\n");
                    getch();
                    return 0;
            }
    
            printf("error Message aus Hauptprogramm\n");
    
            getch();
    
    return 0;
    }
    

    So siehts im Olly Debugger aus:

    00401210 funktion   /$  55              PUSH EBP
    00401211            |.  8BEC            MOV EBP,ESP
    00401213            |.  83C4 F0         ADD ESP,-10
    00401216            |.  68 A4B04000     PUSH vul.0040B0A4                ; /format = "Name: "
    0040121B            |.  E8 243B0000     CALL vul.___org_printf           ; \___org_printf
    00401220            |.  59              POP ECX                          ;  kernel32.7C817067
    00401221            |.  68 90BC4000     PUSH vul.0040BC90                ; /stream = vul.0040BC90
    00401226            |.  E8 FD320000     CALL vul.___org_fflush           ; \___org_fflush
    0040122B            |.  59              POP ECX                          ;  kernel32.7C817067
    0040122C            |.  8D45 F0         LEA EAX,DWORD PTR SS:[EBP-10]
    0040122F            |.  50              PUSH EAX                         ; /s = NULL
    00401230            |.  E8 CF340000     CALL vul.___org_gets             ; \___org_gets
    00401235            |.  59              POP ECX                          ;  kernel32.7C817067
    00401236            |.  68 ABB04000     PUSH vul.0040B0AB                ; /s2 = "abc"
    0040123B            |.  8D55 F0         LEA EDX,DWORD PTR SS:[EBP-10]    ; |
    0040123E            |.  52              PUSH EDX                         ; |s1 = "Í\xA4$"
    0040123F            |.  E8 381C0000     CALL vul.___org_strcmp           ; \___org_strcmp
    00401244            |.  83C4 08         ADD ESP,8
    00401247            |.  8945 FC         MOV DWORD PTR SS:[EBP-4],EAX
    0040124A            |.  837D FC 00      CMP DWORD PTR SS:[EBP-4],0
    0040124E            |.  75 12           JNZ SHORT vul.00401262
    00401250            |.  68 AFB04000     PUSH vul.0040B0AF                ; /format = "ok message aus funktion\n"
    00401255            |.  E8 EA3A0000     CALL vul.___org_printf           ; \___org_printf
    0040125A            |.  59              POP ECX                          ;  kernel32.7C817067
    0040125B            |.  B8 01000000     MOV EAX,1
    00401260            |.  EB 13           JMP SHORT vul.00401275
    00401262            |>  837D FC 00      CMP DWORD PTR SS:[EBP-4],0
    00401266            |.  74 0D           JE SHORT vul.00401275
    00401268            |.  68 C8B04000     PUSH vul.0040B0C8                ; /format = "err message aus funktion\n"
    0040126D            |.  E8 D23A0000     CALL vul.___org_printf           ; \___org_printf
    00401272            |.  59              POP ECX                          ;  kernel32.7C817067
    00401273            |.  33C0            XOR EAX,EAX
    00401275            |>  8BE5            MOV ESP,EBP
    00401277            |.  5D              POP EBP                          ;  kernel32.7C817067
    00401278            \.  C3              RETN
    00401279 main       /.  55              PUSH EBP
    0040127A            |.  8BEC            MOV EBP,ESP
    0040127C            |.  51              PUSH ECX
    0040127D            |.  E8 8EFFFFFF     CALL vul.funktion                ; [vul.funktion
    00401282            |.  8945 FC         MOV DWORD PTR SS:[EBP-4],EAX
    00401285            |.  837D FC 01      CMP DWORD PTR SS:[EBP-4],1
    00401289            |.  75 15           JNZ SHORT vul.004012A0
    0040128B            |.  68 E2B04000     PUSH vul.0040B0E2                ; /format = "OK Message aus Hauptprogramm\n"
    00401290            |.  E8 AF3A0000     CALL vul.___org_printf           ; \___org_printf
    00401295            |.  59              POP ECX                          ;  kernel32.7C817067
    00401296            |.  E8 8D190000     CALL vul.getch
    0040129B            |.  33C0            XOR EAX,EAX
    0040129D            |.  59              POP ECX                          ;  kernel32.7C817067
    0040129E            |.  5D              POP EBP                          ;  kernel32.7C817067
    0040129F            |.  C3              RETN
    004012A0            |>  68 00B14000     PUSH vul.0040B100                ; /format = "error Message aus Hauptprogramm\n"
    004012A5            |.  E8 9A3A0000     CALL vul.___org_printf           ; \___org_printf
    004012AA            |.  59              POP ECX                          ;  kernel32.7C817067
    004012AB            |.  E8 78190000     CALL vul.getch
    004012B0            |.  33C0            XOR EAX,EAX
    004012B2            |.  59              POP ECX                          ;  kernel32.7C817067
    004012B3            |.  5D              POP EBP                          ;  kernel32.7C817067
    004012B4            \.  C3              RETN
    

    Hier mal die Funktion als Screenshot:

    http://u53.img-up.net/?up=funktionmr72t.JPG



  • Oops ich hab da überall geschrieben Buffer Overflow aber das ist ja ein Stack Overflow sry mein Fehler. -.-



  • buf schrieb:

    Wieso muss ich noch 4 Bytes dazu rechnen damit der return Befehl der Funktion überschrieben wird ?

    Der alte stack frame des callers (EBP) wird unmittelbar nach dem Eintritt in die Funktion auf den Stack abgelegt (push ebp). Du musst also 16+4 Bytes überschreiben - weiter 4 Byte (insgesamt 24) überschreiben dann die Rücksprungaddr.



  • PUSB EBP ; <-- ESP - 4 Byte ok das hab ich verstanden

    Aber dann kommt ja noch meine Variable int ret;

    und deswegen dann nochmal - 4 Byte oder?

    Also 16 + PUSH EBP (4 byte) + int ret; (4 byte) = 24 byte

    So wäre es ja eine erklärung.

    Aber die Frage ist ja warum muss ich die variable int ret; auch mit überschreiben ?



  • nun, die Variablen werden alle auf dem Stack angelegt. Dies geschieht in einem Schritt – "sub esp,x" oder "add esp,-(x)" oder "lea esp,[esp-x]".
    x ist hierbei die Gesamtgröße aller Variablen. Wie viel Bytes du überschreiben musst, um an die Rücksprungaddr. zu gelangen,
    hängt allerdings davon ab, wo der Buffer in Bereich x angesiedelt ist: [EBP-x+y]. In der Regel (sollte man sich aber nicht drauf verlassen da compiler abhänig) geht das nach der Reihenfolge in der sie deklariert sind: Der untersten Deklaration wird in der Regel auch die niedrigste Addr. zu gewiesen (y=0).



  • grad erst gesehen:

    buf schrieb:

    Also 16 + PUSH EBP (4 byte) + int ret; (4 byte) = 24 byte

    so überschreibst du nur den stack frame des callers - 4 weitere bytes überschreiben die Rücksprungaddr.



  • char name[10]; // = 10 Hex = 16 Dezimal
    

    sind 10 dez und 0x0A hex 😉

    ganz interessant:
    http://controllingtheinter.net/BOFMSCPP.php



  • Ty das sieht ganz interssant aus ich werds mir mal durchlesen.


Anmelden zum Antworten