diff --git a/src/binary-exploitation/basic-stack-binary-exploitation-methodology/elf-tricks.md b/src/binary-exploitation/basic-stack-binary-exploitation-methodology/elf-tricks.md index f4edb44d9..588cecf18 100644 --- a/src/binary-exploitation/basic-stack-binary-exploitation-methodology/elf-tricks.md +++ b/src/binary-exploitation/basic-stack-binary-exploitation-methodology/elf-tricks.md @@ -2,7 +2,7 @@ {{#include ../../banners/hacktricks-training.md}} -## Program Headers +## Programski Headeri Oni opisuju loader-u kako da učita **ELF** u memoriju: ```bash @@ -37,20 +37,22 @@ Segment Sections... 07 08 .init_array .fini_array .dynamic .got ``` -Prethodni program ima **9 zaglavlja programa**, zatim, **mapiranje segmenata** ukazuje u kojem zaglavlju programa (od 00 do 08) **se nalazi svaka sekcija**. +The previous program has **9 program headers**, then, the **segment mapping** indicates in which program header (from 00 to 08) **each section is located**. ### PHDR - Program HeaDeR -Sadrži tabele zaglavlja programa i samu metapodatke. +Sadrži tabele programskih zaglavlja i samu metapodatke. ### INTERP -Ukazuje putanju učitavača koji treba koristiti za učitavanje binarnog fajla u memoriju. +Ukazuje na putanju učitača koji se koristi za učitavanje binarnog fajla u memoriju. + +> Tip: Staticki povezani ili statički-PIE binarni fajlovi neće imati `INTERP` unos. U tim slučajevima nema dinamičkog učitača, što onemogućava tehnike koje se oslanjaju na njega (npr., `ret2dlresolve`). ### LOAD Ova zaglavlja se koriste za označavanje **kako učitati binarni fajl u memoriju.**\ -Svako **LOAD** zaglavlje označava region **memorije** (veličina, dozvole i poravnanje) i ukazuje na bajtove ELF **binarne datoteke koje treba kopirati tamo**. +Svako **LOAD** zaglavlje označava region **memorije** (veličina, dozvole i poravnanje) i označava bajtove ELF **binarne datoteke koje treba kopirati tamo**. Na primer, drugo ima veličinu od 0x1190, treba da bude locirano na 0x1fc48 sa dozvolama za čitanje i pisanje i biće popunjeno sa 0x528 sa ofseta 0xfc48 (ne popunjava sav rezervisani prostor). Ova memorija će sadržati sekcije `.init_array .fini_array .dynamic .got .data .bss`. @@ -60,31 +62,45 @@ Ovo zaglavlje pomaže u povezivanju programa sa njihovim zavisnostima biblioteka ### NOTE -Ovo čuva informacije o metapodacima dobavljača o binarnom fajlu. +Ovo čuva informacije o metapodacima dobavljača o binarnoj datoteci. + +- Na x86-64, `readelf -n` će prikazati `GNU_PROPERTY_X86_FEATURE_1_*` zastavice unutar `.note.gnu.property`. Ako vidite `IBT` i/ili `SHSTK`, binarni fajl je izgrađen sa CET (Indirektno praćenje grananja i/ili Senka steka). Ovo utiče na ROP/JOP jer ciljevi indirektnog grananja moraju početi sa `ENDBR64` instrukcijom, a povratci se proveravaju protiv senke steka. Pogledajte CET stranicu za detalje i beleške o zaobilaženju. + +{{#ref}} +../common-binary-protections-and-bypasses/cet-and-shadow-stack.md +{{#endref}} ### GNU_EH_FRAME -Definiše lokaciju tabela za odmotavanje steka, koje koriste debageri i C++ funkcije za rukovanje izuzecima. +Definiše lokaciju tabela za razotkrivanje steka, koje koriste debageri i C++ funkcije za rukovanje izuzecima. ### GNU_STACK -Sadrži konfiguraciju zaštite od izvršavanja na steku. Ako je omogućeno, binarni fajl neće moći da izvršava kod sa steka. +Sadrži konfiguraciju zaštite od izvršavanja na steku. Ako je omogućena, binarni fajl neće moći da izvršava kod sa steka. + +- Proverite sa `readelf -l ./bin | grep GNU_STACK`. Da biste prisilno prebacili tokom testova, možete koristiti `execstack -s|-c ./bin`. ### GNU_RELRO -Ukazuje na RELRO (Relocation Read-Only) konfiguraciju binarnog fajla. Ova zaštita će označiti kao samo za čitanje određene sekcije memorije (kao što su `GOT` ili `init` i `fini` tabele) nakon što se program učita i pre nego što počne da se izvršava. +Ukazuje na RELRO (Relokacija samo za čitanje) konfiguraciju binarnog fajla. Ova zaštita će označiti kao samo za čitanje određene sekcije memorije (kao što su `GOT` ili `init` i `fini` tabele) nakon što se program učita i pre nego što počne da se izvršava. U prethodnom primeru kopira 0x3b8 bajtova na 0x1fc48 kao samo za čitanje, utičući na sekcije `.init_array .fini_array .dynamic .got .data .bss`. -Napomena da RELRO može biti delimičan ili potpun, delimična verzija ne štiti sekciju **`.plt.got`**, koja se koristi za **lenjo povezivanje** i treba ovaj prostor u memoriji da ima **dozvole za pisanje** da bi zapisala adresu biblioteka kada se prvi put traži njihova lokacija. +Napomena da RELRO može biti delimičan ili potpun, delimična verzija ne štiti sekciju **`.plt.got`**, koja se koristi za **lenjo povezivanje** i treba da ima **dozvole za pisanje** da bi zapisala adresu biblioteka prvi put kada se traži njihova lokacija. + +> Za tehnike eksploatacije i ažurirane beleške o zaobilaženju, proverite posvećenu stranicu: + +{{#ref}} +../common-binary-protections-and-bypasses/relro.md +{{#endref}} ### TLS -Definiše tabelu TLS unosa, koja čuva informacije o lokalnim promenljivama niti. +Definiše tabelu TLS unosa, koja čuva informacije o varijablama lokalnim za niti. -## Zaglavlja sekcija +## Section Headers -Zaglavlja sekcija daju detaljniji pregled ELF binarnog fajla. +Zaglavlja sekcija daju detaljniji pregled ELF binarne datoteke. ``` objdump lnstat -h @@ -145,15 +161,15 @@ CONTENTS, READONLY 25 .gnu_debuglink 00000034 0000000000000000 0000000000000000 000101bc 2**2 CONTENTS, READONLY ``` -To takođe ukazuje na lokaciju, ofset, dozvole, ali i na **tip podataka** koji sekcija ima. +It also indicates the location, offset, permissions but also the **type of data** it section has. -### Meta Sekcije +### Meta Sections -- **String tabela**: Sadrži sve stringove potrebne ELF datoteci (ali ne i one koje program zapravo koristi). Na primer, sadrži imena sekcija kao što su `.text` ili `.data`. I ako je `.text` na ofsetu 45 u string tabeli, koristiće broj **45** u polju **ime**. -- Da bi se pronašlo gde se nalazi string tabela, ELF sadrži pokazivač na string tabelu. -- **Symbol tabela**: Sadrži informacije o simbolima kao što su ime (ofset u string tabeli), adresa, veličina i više metapodataka o simbolu. +- **String table**: Sadrži sve stringove potrebne ELF datoteci (ali ne i one koje program zapravo koristi). Na primer, sadrži imena sekcija kao što su `.text` ili `.data`. I ako je `.text` na offsetu 45 u tabeli stringova, koristiće broj **45** u polju **name**. +- Da bi se pronašlo gde se nalazi tabela stringova, ELF sadrži pokazivač na tabelu stringova. +- **Symbol table**: Sadrži informacije o simbolima kao što su ime (offset u tabeli stringova), adresa, veličina i više metapodataka o simbolu. -### Glavne Sekcije +### Main Sections - **`.text`**: Instrukcija programa koja se izvršava. - **`.data`**: Globalne promenljive sa definisanom vrednošću u programu. @@ -162,9 +178,9 @@ To takođe ukazuje na lokaciju, ofset, dozvole, ali i na **tip podataka** koji s - **`.tdata`** i **`.tbss`**: Kao .data i .bss kada se koriste promenljive lokalne za nit (`__thread_local` u C++ ili `__thread` u C). - **`.dynamic`**: Vidi ispod. -## Simboli +## Symbols -Simboli su imenovane lokacije u programu koje mogu biti funkcija, globalni objekat podataka, promenljive lokalne za nit... +Symbols je imenovana lokacija u programu koja može biti funkcija, globalni objekat podataka, promenljive lokalne za nit... ``` readelf -s lnstat @@ -194,7 +210,11 @@ Svaki unos simbola sadrži: - **Vrednost** (adresa u memoriji) - **Veličina** -## Dinamička sekcija +#### GNU Verzija Simbola (dynsym/dynstr/gnu.version) + +Moderna glibc koristi verzije simbola. Videćete unose u `.gnu.version` i `.gnu.version_r` i imena simbola kao što je `strlen@GLIBC_2.17`. Dinamički linker može zahtevati specifičnu verziju prilikom rešavanja simbola. Kada pravite ručne relokacije (npr. ret2dlresolve) morate dostaviti ispravan indeks verzije, inače rešavanje ne uspeva. + +## Dinamička Sekcija ``` readelf -d lnstat @@ -229,11 +249,28 @@ Tag Type Name/Value 0x000000006ffffff9 (RELACOUNT) 15 0x0000000000000000 (NULL) 0x0 ``` -Direktorijum NEEDED ukazuje da program **treba da učita pomenutu biblioteku** kako bi nastavio. Direktorijum NEEDED se završava kada je deljena **biblioteka potpuno operativna i spremna** za korišćenje. +Direktorijum NEEDED označava da program **treba da učita pomenutu biblioteku** kako bi nastavio. Direktorijum NEEDED se završava kada je deljena **biblioteka potpuno operativna i spremna** za upotrebu. + +### Redosled pretrage dinamičkog učitavača (RPATH/RUNPATH, $ORIGIN) + +Unosi `DT_RPATH` (deprecated) i/ili `DT_RUNPATH` utiču na to gde dinamički učitavač traži zavisnosti. Grubi redosled: + +- `LD_LIBRARY_PATH` (ignorisan za setuid/sgid ili na drugi način "sigurne izvršne" programe) +- `DT_RPATH` (samo ako `DT_RUNPATH` nije prisutan) +- `DT_RUNPATH` +- `ld.so.cache` +- podrazumevani direktorijumi kao što su `/lib64`, `/usr/lib64`, itd. + +`$ORIGIN` se može koristiti unutar RPATH/RUNPATH da se odnosi na direktorijum glavnog objekta. Sa stanovišta napadača, ovo je važno kada kontrolišete raspored datotečnog sistema ili okruženje. Za ojačane binarne datoteke (AT_SECURE) većina promenljivih okruženja se ignoriše od strane učitavača. + +- Istražite sa: `readelf -d ./bin | egrep -i 'r(path|unpath)'` +- Brzi test: `LD_DEBUG=libs ./bin 2>&1 | grep -i find` (prikazuje odluke o pretrazi) + +> Priv-esc savet: Preferirajte zloupotrebu zapisivih RUNPATH-ova ili pogrešno konfigurisane putanje relativne na `$ORIGIN` koje su u vašem vlasništvu. LD_PRELOAD/LD_AUDIT se ignorišu u kontekstima sigurnog izvršavanja (setuid). ## Relokacije -Loader takođe mora da relokira zavisnosti nakon što ih učita. Ove relokacije su označene u tabeli relokacija u formatima REL ili RELA, a broj relokacija je dat u dinamičkim sekcijama RELSZ ili RELASZ. +Učitavač takođe mora relokirati zavisnosti nakon što ih učita. Ove relokacije su naznačene u tabeli relokacija u formatima REL ili RELA, a broj relokacija je dat u dinamičkim sekcijama RELSZ ili RELASZ. ``` readelf -r lnstat @@ -274,7 +311,6 @@ Offset Info Type Sym. Value Sym. Name + Addend 00000001fea0 000900000402 R_AARCH64_JUMP_SL 0000000000000000 perror@GLIBC_2.17 + 0 00000001fea8 000b00000402 R_AARCH64_JUMP_SL 0000000000000000 __cxa_finalize@GLIBC_2.17 + 0 00000001feb0 000c00000402 R_AARCH64_JUMP_SL 0000000000000000 putc@GLIBC_2.17 + 0 -00000001feb8 000d00000402 R_AARCH64_JUMP_SL 0000000000000000 opendir@GLIBC_2.17 + 0 00000001fec0 000e00000402 R_AARCH64_JUMP_SL 0000000000000000 fputc@GLIBC_2.17 + 0 00000001fec8 001100000402 R_AARCH64_JUMP_SL 0000000000000000 snprintf@GLIBC_2.17 + 0 00000001fed0 001200000402 R_AARCH64_JUMP_SL 0000000000000000 __snprintf_chk@GLIBC_2.17 + 0 @@ -310,17 +346,35 @@ Offset Info Type Sym. Value Sym. Name + Addend Ako je **program učitan na mestu koje se razlikuje** od preferirane adrese (obično 0x400000) zato što je adresa već zauzeta ili zbog **ASLR** ili bilo kog drugog razloga, statička relokacija **ispravlja pokazivače** koji su imali vrednosti očekujući da će binarni fajl biti učitan na preferiranoj adresi. -Na primer, svaka sekcija tipa `R_AARCH64_RELATIV` treba da ima modifikovanu adresu na relokacionom pristrasnosti plus vrednost adenda. +Na primer, svaka sekcija tipa `R_AARCH64_RELATIV` treba da ima modifikovanu adresu na relokacionom pomeraju plus vrednost adenda. ### Dinamičke Relokacije i GOT -Relokacija može takođe referencirati spoljašnji simbol (kao što je funkcija iz zavisnosti). Kao što je funkcija malloc iz libC. Tada, učitavač prilikom učitavanja libC na adresu proverava gde je učitana funkcija malloc, i upisuje ovu adresu u GOT (Global Offset Table) tabelu (naznačenu u relokacionoj tabeli) gde bi adresa malloc trebala biti specificirana. +Relokacija može takođe referencirati spoljašnji simbol (kao što je funkcija iz zavisnosti). Kao što je funkcija malloc iz libC. Tada, učitavač prilikom učitavanja libC na adresu proverava gde je učitana funkcija malloc, i upisuje ovu adresu u GOT (Global Offset Table) tabelu (naznačeno u relokacionoj tabeli) gde bi adresa malloc trebala biti specificirana. ### Tabela Povezivanja Procedura PLT sekcija omogućava obavljanje lenjog povezivanja, što znači da će se rešavanje lokacije funkcije obaviti prvi put kada se pristupi. -Dakle, kada program poziva malloc, zapravo poziva odgovarajuću lokaciju `malloc` u PLT (`malloc@plt`). Prvi put kada se pozove, rešava adresu `malloc` i čuva je tako da se sledeći put kada se pozove `malloc`, ta adresa koristi umesto PLT koda. +Dakle, kada program poziva malloc, zapravo poziva odgovarajuću lokaciju `malloc` u PLT (`malloc@plt`). Prvi put kada se pozove, rešava adresu `malloc` i čuva je, tako da sledeći put kada se pozove `malloc`, ta adresa se koristi umesto PLT koda. + +#### Moderni obrasci povezivanja koji utiču na eksploataciju + +- `-z now` (Full RELRO) onemogućava lenjo povezivanje; PLT unosi i dalje postoje, ali je GOT/PLT mapiran kao samo za čitanje, tako da tehnike poput **GOT overwrite** i **ret2dlresolve** neće raditi protiv glavnog binarnog fajla (biblioteke mogu i dalje biti delimično RELRO). Vidi: + +{{#ref}} +../common-binary-protections-and-bypasses/relro.md +{{#endref}} + +- `-fno-plt` čini da kompajler poziva spoljne funkcije kroz **GOT unos direktno** umesto da ide kroz PLT stub. Videćete sekvence poziva kao `mov reg, [got]; call reg` umesto `call func@plt`. Ovo smanjuje zloupotrebu spekulativne izvršavanja i malo menja lov na ROP gadgete oko PLT stubova. + +- PIE vs static-PIE: PIE (ET_DYN sa `INTERP`) zahteva dinamički učitavač i podržava uobičajenu PLT/GOT mašineriju. Static-PIE (ET_DYN bez `INTERP`) ima relokacije koje primenjuje kernel učitavač i nema `ld.so`; očekujte da nema PLT rešavanja u vreme izvršavanja. + +> Ako GOT/PLT nije opcija, pređite na druge pisive pokazivače koda ili koristite klasični ROP/SROP u libc. + +{{#ref}} +../arbitrary-write-2-exec/aw2exec-got-plt.md +{{#endref}} ## Inicijalizacija Programa @@ -356,7 +410,17 @@ Sa perspektive kompajlera, da bi se izvršile ove radnje pre i posle izvršavanj Druga opcija, kao što je pomenuto, je da se referenciraju liste **`__CTOR_LIST__`** i **`__DTOR_LIST__`** u **`INIT_ARRAY`** i **`FINI_ARRAY`** stavkama u dinamičkom odeljku, a dužina ovih stavki je označena sa **`INIT_ARRAYSZ`** i **`FINI_ARRAYSZ`**. Svaka stavka je pokazivač na funkciju koja će biti pozvana bez argumenata. -Štaviše, moguće je imati i **`PREINIT_ARRAY`** sa **pokazivačima** koji će biti izvršeni **pre** **`INIT_ARRAY`** pokazivača. +Štaviše, takođe je moguće imati **`PREINIT_ARRAY`** sa **pokazivačima** koji će biti izvršeni **pre** pokazivača **`INIT_ARRAY`**. + +#### Napomena o eksploataciji + +- Pod Partial RELRO, ovi nizovi žive u stranicama koje su još uvek zapisive pre nego što `ld.so` prebacuje `PT_GNU_RELRO` u samo za čitanje. Ako dobijete proizvoljno pisanje dovoljno rano ili možete ciljati zapisive nizove biblioteke, možete preuzeti kontrolu nad tokom izvršavanja prepisivanjem stavke sa funkcijom po vašem izboru. Pod Full RELRO, oni su samo za čitanje u vreme izvršavanja. + +- Za zloupotrebu lenjog povezivanja dinamičkog linkera za rešavanje proizvoljnih simbola u vreme izvršavanja, pogledajte posvećenu stranicu: + +{{#ref}} +../rop-return-oriented-programing/ret2dlresolve.md +{{#endref}} ### Redosled inicijalizacije @@ -365,18 +429,45 @@ Druga opcija, kao što je pomenuto, je da se referenciraju liste **`__CTOR_LIST_ 3. **`PREINIT_ARRAY`** funkcije se izvršavaju. 4. **`INIT_ARRAY`** funkcije se izvršavaju. 5. Ako postoji **`INIT`** stavka, ona se poziva. -6. Ako je u pitanju biblioteka, dlopen ovde završava, ako je program, vreme je da se pozove **pravi ulazni tačka** (`main` funkcija). +6. Ako je u pitanju biblioteka, dlopen ovde završava, ako je u pitanju program, vreme je da se pozove **pravi ulazni tačka** (`main` funkcija). ## Thread-Local Storage (TLS) -Definišu se korišćenjem ključne reči **`__thread_local`** u C++ ili GNU ekstenzije **`__thread`**. +Oni se definišu koristeći ključnu reč **`__thread_local`** u C++ ili GNU ekstenziju **`__thread`**. -Svaki nit će održavati jedinstvenu lokaciju za ovu promenljivu tako da samo nit može pristupiti svojoj promenljivoj. +Svaka nit će održavati jedinstvenu lokaciju za ovu promenljivu tako da samo ta nit može pristupiti svojoj promenljivoj. Kada se ovo koristi, odeljci **`.tdata`** i **`.tbss`** se koriste u ELF-u. Koji su slični `.data` (inicijalizovano) i `.bss` (neinicijalizovano) ali za TLS. -Svaka promenljiva će imati stavku u TLS headeru koja specificira veličinu i TLS offset, što je offset koji će koristiti u lokalnom području podataka niti. +Svaka promenljiva će imati stavku u TLS zaglavlju koja specificira veličinu i TLS offset, što je offset koji će koristiti u lokalnom području podataka niti. -`__TLS_MODULE_BASE` je simbol koji se koristi za referenciranje osnovne adrese skladišta lokalnih niti i ukazuje na područje u memoriji koje sadrži sve podatke lokalne za niti modula. +`__TLS_MODULE_BASE` je simbol koji se koristi za referenciranje osnovne adrese skladišta lokalnih niti i ukazuje na područje u memoriji koje sadrži sve podatke lokalnih niti modula. +## Auxiliary Vector (auxv) i vDSO + +Linux kernel prosleđuje pomoćni vektor procesima koji sadrži korisne adrese i zastavice za vreme izvršavanja: + +- `AT_RANDOM`: ukazuje na 16 nasumičnih bajtova koje koristi glibc za stack canary i druge PRNG semena. +- `AT_SYSINFO_EHDR`: osnovna adresa vDSO mapiranja (korisno za pronalaženje `__kernel_*` sistemskih poziva i gadgeta). +- `AT_EXECFN`, `AT_BASE`, `AT_PAGESZ`, itd. + +Kao napadač, ako možete čitati memoriju ili datoteke pod `/proc`, često možete procuriti ove informacije bez infoleaka u ciljanom procesu: +```bash +# Show the auxv of a running process +cat /proc/$(pidof target)/auxv | xxd + +# From your own process (helper snippet) +#include +#include +int main(){ +printf("AT_RANDOM=%p\n", (void*)getauxval(AT_RANDOM)); +printf("AT_SYSINFO_EHDR=%p\n", (void*)getauxval(AT_SYSINFO_EHDR)); +} +``` +Curenje `AT_RANDOM` vam daje vrednost kanarija ako možete dereferencirati tu pokazivač; `AT_SYSINFO_EHDR` vam daje vDSO osnovu za pronalaženje gadgeta ili za direktno pozivanje brzih sistemskih poziva. + +## References + +- ld.so(8) – Dynamic Loader search order, RPATH/RUNPATH, secure-execution rules (AT_SECURE): https://man7.org/linux/man-pages/man8/ld.so.8.html +- getauxval(3) – Auxiliary vector and AT_* constants: https://man7.org/linux/man-pages/man3/getauxval.3.html {{#include ../../banners/hacktricks-training.md}}