BROP - Blind Return Oriented Programming

Podržite HackTricks

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 pada

  • strcmp(<č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

Last updated