BROP - Blind Return Oriented Programming
Osnovne informacije
Cilj ovog napada je da se zloupotrebi ROP 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 puklo. 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 da 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 tim 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 sledeći i ne sme izvršiti STOP gedžet da 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 može biti pretražena od 0x400000 ili od procurele 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 pada jer je to prvi izvršeni kod.
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đenog stringa. Imajte na umu da je rdx
treći argument i potrebno je da bude veći od 0 kako bi kasnije mogli koristiti write
da procuremo program.
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
Moguće je proveriti ovo 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 želimo ispitati (počevši od nule) da bi se skenirali svi unosi PLT tabele od prvog:
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
-> 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, tako da 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 uobičajene 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 ćemo o tome govoriti:
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 preko našeg soketa.
Međutim, znamo gde se nalazi PLT tabela 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
Automatizovana eksploatacija
Reference
Originalni rad: https://www.scs.stanford.edu/brop/bittau-brop.pdf
Last updated