BROP - Blind Return Oriented Programming
Osnovne informacije
Cilj ovog napada je zloupotreba ROP-a putem prelivanja bafera bez ikakvih informacija o ranjivom binarnom fajlu. Ovaj napad se zasniva na sledećem scenariju:
Ranjivost steka i poznavanje kako je pokrenuti.
Server aplikacija koja se ponovo pokreće nakon pada.
Napad
1. Pronalaženje ranjivog ofseta slanjem još jednog karaktera dok se ne detektuje kvar servera
2. Bruteforsiranje kanara da bi se otkrio
3. Bruteforsiranje smeštenih RBP i RIP adresa na steku da bi se otkrile
Više informacija o ovim procesima možete pronaći ovde (BF Forked & Threaded Stack Canaries) i ovde (BF Adrese na Steku).
4. Pronalaženje stop gedžeta
Ovaj gedžet omogućava potvrdu da je nešto zanimljivo izvršeno pomoću ROP gedžeta jer izvršenje nije dovelo do pada. Obično, ovaj gedžet će biti nešto što zaustavlja izvršenje i biće pozicioniran na kraju ROP lanca prilikom traženja ROP gedžeta kako bi se potvrdilo da je određeni ROP gedžet izvršen.
5. Pronalaženje BROP gedžeta
Ova tehnika koristi ret2csu gedžet. To je zato što ako pristupite ovom gedžetu usred nekih instrukcija, dobijate gedžete za kontrolu rsi
i rdi
:
Ovo bi bili gedžeti:
pop rsi; pop r15; ret
pop rdi; ret
Primetite kako je sa ovim gedžetima moguće kontrolisati 2 argumenta funkcije koja se poziva.
Takođe, primetite da ret2csu gedžet ima vrlo jedinstveni potpis jer će skidati 6 registara sa steka. Dakle, slanjem lanca kao:
'A' * ofset + kanaric + rbp + ADRESA + 0xdead * 6 + STOP
Ako se STOP izvrši, to u osnovi znači da je korišćena adresa koja skida 6 registara sa steka. Ili da je korišćena adresa takođe STOP adresa.
Kako bi se uklonila ova poslednja opcija, izvršava se novi lanac kao što je sledeći i ne sme izvršiti STOP gedžet kako bi se potvrdilo da je prethodni zaista skidao 6 registara:
'A' * ofset + kanaric + rbp + ADRESA
Znajući adresu ret2csu gedžeta, moguće je zaključiti adresu gedžeta za kontrolu rsi
i rdi
.
6. Pronalaženje PLT-a
PLT tabela se može pretraživati od 0x400000 ili od procurle RIP adrese sa steka (ako se koristi PIE). Unosi tabele su razdvojeni sa 16B (0x10B), i kada se pozove jedna funkcija, server ne pada čak i ako argumenti nisu ispravni. Takođe, provera adrese unosa u PLT + 6B takođe ne dovodi do pada jer je to prvi kod koji se izvršava.
Stoga, moguće je pronaći PLT tabelu proveravajući sledeće ponašanje:
'A' * ofset + kanaric + rbp + ADRESA + STOP
-> nema pada'A' * ofset + kanaric + rbp + (ADRESA + 0x6) + STOP
-> nema pada'A' * ofset + kanaric + rbp + (ADRESA + 0x10) + STOP
-> nema pada
7. Pronalaženje strcmp funkcije
Funkcija strcmp
postavlja registar rdx
na dužinu upoređivanog stringa. Imajte na umu da je rdx
treći argument i potrebno je da bude veći od 0 kako bi se kasnije koristio write
za procurivanje programa.
Moguće je pronaći lokaciju strcmp
u PLT-u na osnovu njegovog ponašanja koristeći činjenicu da sada možemo kontrolisati prva 2 argumenta funkcija:
strcmp(<nečitljiva adresa>, <nečitljiva adresa>) -> pad
strcmp(<nečitljiva adresa>, <čitljiva adresa>) -> pad
strcmp(<čitljiva adresa>, <nečitljiva adresa>) -> pad
strcmp(<čitljiva adresa>, <čitljiva adresa>) -> nema pada
Ovo je moguće proveriti pozivanjem svakog unosa u PLT tabeli ili korišćenjem PLT spore putanje koja se u osnovi sastoji od pozivanja unosa u PLT tabeli + 0xb (koji poziva dlresolve
) praćenog na steku brojem unosa koji želite ispitati (počevši od nule) kako bi se skenirali svi unosi PLT tabele:
strcmp(<nečitljiva adresa>, <čitljiva adresa>) -> pad
b'A' * ofset + kanaric + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0x300) + p64(0x0) + (PLT + 0xb ) + p64(UNOS) + STOP
-> Dovesti će do padastrcmp(<čitljiva adresa>, <nečitljiva adresa>) -> pad
b'A' * ofset + kanaric + rbp + (BROP + 0x9) + p64(0x300) + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(UNOS) + STOP
strcmp(<čitljiva adresa>, <čitljiva adresa>) -> nema pada
b'A' * ofset + kanaric + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(UNOS) + STOP
Zapamtite da:
BROP + 0x7 pokazuje na
pop RSI; pop R15; ret;
BROP + 0x9 pokazuje na
pop RDI; ret;
PLT + 0xb pokazuje na poziv dl_resolve.
Nakon što je pronađen strcmp
, moguće je postaviti rdx
na vrednost veću od 0.
Imajte na umu da će obično rdx
već imati vrednost veću od 0, pa ovaj korak možda nije potreban.
### 8. Pronalaženje Write ili ekvivalenta
Konačno, potreban je uređaj koji eksfiltrira podatke kako bi se eksfiltrirao binarni fajl. U ovom trenutku je moguće kontrolisati 2 argumenta i postaviti rdx
veći od 0.
Postoje 3 česte funkcije koje bi mogle biti zloupotrebljene za ovo:
puts(data)
dprintf(fd, data)
write(fd, data, len(data)
Međutim, originalni rad pominje samo write
, pa da pričamo o tome:
Trenutni problem je što ne znamo gde se nalazi funkcija write unutar PLT-a i ne znamo broj fd-a na koji treba poslati podatke ka našem socket-u.
Međutim, znamo gde se nalazi tabela PLT-a i moguće je pronaći write na osnovu njegovog ponašanja. I možemo kreirati više veza sa serverom i koristiti visok FD u nadi da se poklapa sa nekom od naših veza.
Potpisi ponašanja za pronalaženje ovih funkcija:
'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0) + p64(0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> Ako se podaci ispišu, onda je pronađen puts'A' * offset + canary + rbp + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> Ako se podaci ispišu, onda je pronađen dprintf'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + (RIP + 0x1) + p64(0x0) + (PLT + 0xb ) + p64(STRCMP ENTRY) + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> Ako se podaci ispišu, onda je pronađen write
Automatsko iskorišćavanje
Reference
Originalni rad: https://www.scs.stanford.edu/brop/bittau-brop.pdf
Last updated