BROP - Blind Return Oriented Programming
Reading time: 6 minutes
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.
Podstawowe informacje
Celem tego ataku jest wykorzystanie ROP za pomocą przepełnienia bufora bez jakiejkolwiek informacji o podatnym binarnym.
Atak oparty jest na następującym scenariuszu:
- Wrażliwość na stosie i wiedza, jak ją wywołać.
- Aplikacja serwerowa, która restartuje się po awarii.
Atak
1. Znajdź wrażliwy offset wysyłając jeden dodatkowy znak, aż zostanie wykryta awaria serwera
2. Bruteforce canary aby go wyciekł
3. Bruteforce przechowywanych adresów RBP i RIP na stosie, aby je wyciekł
Możesz znaleźć więcej informacji na temat tych procesów tutaj (BF Forked & Threaded Stack Canaries) i tutaj (BF Addresses in the Stack).
4. Znajdź gadget stop
Ten gadget zasadniczo pozwala potwierdzić, że coś interesującego zostało wykonane przez gadget ROP, ponieważ wykonanie nie spowodowało awarii. Zwykle ten gadget będzie czymś, co zatrzymuje wykonanie i jest umieszczone na końcu łańcucha ROP, gdy szuka się gadgetów ROP, aby potwierdzić, że konkretny gadget ROP został wykonany.
5. Znajdź gadget BROP
Ta technika wykorzystuje gadget ret2csu. I to dlatego, że jeśli uzyskasz dostęp do tego gadgetu w trakcie niektórych instrukcji, otrzymasz gadgety do kontrolowania rsi
i rdi
:
To byłyby gadgety:
pop rsi; pop r15; ret
pop rdi; ret
Zauważ, jak z tymi gadgetami można kontrolować 2 argumenty funkcji do wywołania.
Zauważ również, że gadget ret2csu ma bardzo unikalny podpis, ponieważ będzie wyciągał 6 rejestrów ze stosu. Więc wysyłając łańcuch taki jak:
'A' * offset + canary + rbp + ADDR + 0xdead * 6 + STOP
Jeśli STOP zostanie wykonany, oznacza to zasadniczo, że adres, który wyciąga 6 rejestrów ze stosu został użyty. Lub że użyty adres był również adresem STOP.
Aby usunąć tę ostatnią opcję, wykonuje się nowy łańcuch taki jak poniżej i nie może on wykonać gadgetu STOP, aby potwierdzić, że poprzedni rzeczywiście wyciągnął 6 rejestrów:
'A' * offset + canary + rbp + ADDR
Znając adres gadgetu ret2csu, można wnioskować adresy gadgetów do kontrolowania rsi
i rdi
.
6. Znajdź PLT
Tabela PLT może być przeszukiwana od 0x400000 lub z wyciekłego adresu RIP ze stosu (jeśli PIE jest używane). Wpisy tabeli są oddzielone o 16B (0x10B), a gdy jedna funkcja jest wywoływana, serwer nie zawiesza się, nawet jeśli argumenty nie są poprawne. Ponadto, sprawdzanie adresu wpisu w PLT + 6B również nie powoduje awarii, ponieważ jest to pierwszy kod wykonywany.
Dlatego można znaleźć tabelę PLT, sprawdzając następujące zachowania:
'A' * offset + canary + rbp + ADDR + STOP
-> brak awarii'A' * offset + canary + rbp + (ADDR + 0x6) + STOP
-> brak awarii'A' * offset + canary + rbp + (ADDR + 0x10) + STOP
-> brak awarii
7. Znajdowanie strcmp
Funkcja strcmp
ustawia rejestr rdx
na długość porównywanego ciągu. Zauważ, że rdx
jest trzecim argumentem i musimy, aby był większy niż 0, aby później użyć write
, aby wyciekł program.
Można znaleźć lokalizację strcmp
w PLT na podstawie jej zachowania, wykorzystując fakt, że teraz możemy kontrolować 2 pierwsze argumenty funkcji:
- strcmp(<non read addr>, <non read addr>) -> awaria
- strcmp(<non read addr>, <read addr>) -> awaria
- strcmp(<read addr>, <non read addr>) -> awaria
- strcmp(<read addr>, <read addr>) -> brak awarii
Można to sprawdzić, wywołując każdy wpis w tabeli PLT lub używając wolnej ścieżki PLT, która zasadniczo polega na wywołaniu wpisu w tabeli PLT + 0xb (co wywołuje dlresolve
) a następnie na stosie przez numer wpisu, który chce się zbadać (zaczynając od zera), aby przeskanować wszystkie wpisy PLT od pierwszego:
- strcmp(<non read addr>, <read addr>) -> awaria
b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0x300) + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
-> Spowoduje awarię- strcmp(<read addr>, <non read addr>) -> awaria
b'A' * offset + canary + rbp + (BROP + 0x9) + p64(0x300) + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
- strcmp(<read addr>, <read addr>) -> brak awarii
b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
Pamiętaj, że:
- BROP + 0x7 wskazuje na
pop RSI; pop R15; ret;
- BROP + 0x9 wskazuje na
pop RDI; ret;
- PLT + 0xb wskazuje na wywołanie dl_resolve.
Po znalezieniu strcmp
można ustawić rdx
na wartość większą niż 0.
tip
Zauważ, że zazwyczaj rdx
będzie już miało wartość większą niż 0, więc ten krok może nie być konieczny.
8. Znajdowanie Write lub ekwiwalentu
Na koniec potrzebny jest gadget, który eksfiltruje dane, aby wyeksportować binarny. A w tym momencie można kontrolować 2 argumenty i ustawić rdx
większe niż 0.
Istnieją 3 powszechne funkcje, które można wykorzystać do tego:
puts(data)
dprintf(fd, data)
write(fd, data, len(data)
Jednak oryginalny artykuł wspomina tylko o funkcji write
, więc porozmawiajmy o niej:
Obecnym problemem jest to, że nie wiemy gdzie funkcja write znajduje się w PLT i nie znamy numeru fd, aby wysłać dane do naszego gniazda.
Jednak wiemy gdzie znajduje się tabela PLT i można znaleźć write na podstawie jej zachowania. Możemy stworzyć wiele połączeń z serwerem i użyć wysokiego FD, mając nadzieję, że pasuje do niektórych naszych połączeń.
Podpisy zachowań do znalezienia tych funkcji:
'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0) + p64(0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> Jeśli dane są drukowane, to znaczy, że znaleziono puts'A' * offset + canary + rbp + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> Jeśli dane są drukowane, to znaczy, że znaleziono 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
-> Jeśli dane są drukowane, to znaczy, że znaleziono write
Automatyczna eksploatacja
Odniesienia
- Oryginalny artykuł: https://www.scs.stanford.edu/brop/bittau-brop.pdf
- https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/blind-return-oriented-programming-brop
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.