BROP - Blind Return Oriented Programming
Reading time: 7 minutes
tip
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Grundinformationen
Das Ziel dieses Angriffs ist es, einen ROP über einen Buffer Overflow auszunutzen, ohne Informationen über die verwundbare Binärdatei zu haben.
Dieser Angriff basiert auf folgendem Szenario:
- Eine Stack-Sicherheitsanfälligkeit und Wissen darüber, wie man sie auslöst.
- Eine Serveranwendung, die nach einem Absturz neu gestartet wird.
Angriff
1. Verwundbaren Offset finden durch das Senden eines weiteren Zeichens, bis ein Fehler des Servers erkannt wird
2. Brute-Force Canary um ihn zu leaken
3. Brute-Force gespeicherte RBP- und RIP-Adressen im Stack, um sie zu leaken
Weitere Informationen zu diesen Prozessen finden Sie hier (BF Forked & Threaded Stack Canaries) und hier (BF Adressen im Stack).
4. Stop-Gadget finden
Dieses Gadget ermöglicht es im Wesentlichen zu bestätigen, dass etwas Interessantes durch das ROP-Gadget ausgeführt wurde, da die Ausführung nicht abgestürzt ist. Normalerweise wird dieses Gadget etwas sein, das die Ausführung stoppt und es befindet sich am Ende der ROP-Kette, wenn nach ROP-Gadgets gesucht wird, um zu bestätigen, dass ein bestimmtes ROP-Gadget ausgeführt wurde.
5. BROP-Gadget finden
Diese Technik verwendet das ret2csu Gadget. Und das liegt daran, dass man, wenn man auf dieses Gadget in der Mitte einiger Anweisungen zugreift, Gadgets erhält, um rsi
und rdi
zu steuern:
Das wären die Gadgets:
pop rsi; pop r15; ret
pop rdi; ret
Beachten Sie, wie es mit diesen Gadgets möglich ist, 2 Argumente einer Funktion zu steuern.
Beachten Sie auch, dass das ret2csu-Gadget eine sehr einzigartige Signatur hat, da es 6 Register vom Stack poppt. Daher wird eine Kette wie folgt gesendet:
'A' * offset + canary + rbp + ADDR + 0xdead * 6 + STOP
Wenn das STOP ausgeführt wird, bedeutet dies im Wesentlichen, dass eine Adresse, die 6 Register vom Stack poppt, verwendet wurde. Oder dass die verwendete Adresse auch eine STOP-Adresse war.
Um diese letzte Option zu entfernen, wird eine neue Kette wie die folgende ausgeführt, und sie darf das STOP-Gadget nicht ausführen, um zu bestätigen, dass das vorherige 6 Register gepoppt hat:
'A' * offset + canary + rbp + ADDR
Wenn die Adresse des ret2csu-Gadgets bekannt ist, ist es möglich, die Adresse der Gadgets zur Steuerung von rsi
und rdi
abzuleiten.
6. PLT finden
Die PLT-Tabelle kann von 0x400000 oder von der geleakten RIP-Adresse aus dem Stack (wenn PIE verwendet wird) durchsucht werden. Die Einträge der Tabelle sind durch 16B (0x10B) getrennt, und wenn eine Funktion aufgerufen wird, stürzt der Server nicht ab, selbst wenn die Argumente nicht korrekt sind. Außerdem stürzt das Überprüfen der Adresse eines Eintrags in der PLT + 6B ebenfalls nicht ab, da es der erste ausgeführte Code ist.
Daher ist es möglich, die PLT-Tabelle zu finden, indem man die folgenden Verhaltensweisen überprüft:
'A' * offset + canary + rbp + ADDR + STOP
-> kein Absturz'A' * offset + canary + rbp + (ADDR + 0x6) + STOP
-> kein Absturz'A' * offset + canary + rbp + (ADDR + 0x10) + STOP
-> kein Absturz
7. strcmp finden
Die strcmp
Funktion setzt das Register rdx
auf die Länge des zu vergleichenden Strings. Beachten Sie, dass rdx
das dritte Argument ist und wir es größer als 0 haben müssen, um später write
zu verwenden, um das Programm zu leaken.
Es ist möglich, den Standort von strcmp
in der PLT basierend auf seinem Verhalten zu finden, indem man die Tatsache nutzt, dass wir jetzt die 2 ersten Argumente von Funktionen steuern können:
- strcmp(<non read addr>, <non read addr>) -> Absturz
- strcmp(<non read addr>, <read addr>) -> Absturz
- strcmp(<read addr>, <non read addr>) -> Absturz
- strcmp(<read addr>, <read addr>) -> kein Absturz
Es ist möglich, dies zu überprüfen, indem man jeden Eintrag der PLT-Tabelle aufruft oder den PLT-Slow-Path verwendet, der im Wesentlichen darin besteht, einen Eintrag in der PLT-Tabelle + 0xb (was zu dlresolve
aufruft) gefolgt im Stack von der Eintragsnummer, die man testen möchte (beginnend bei null), um alle PLT-Einträge vom ersten an zu scannen:
- strcmp(<non read addr>, <read addr>) -> Absturz
b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0x300) + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
-> Wird abstürzen- strcmp(<read addr>, <non read addr>) -> Absturz
b'A' * offset + canary + rbp + (BROP + 0x9) + p64(0x300) + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
- strcmp(<read addr>, <read addr>) -> kein Absturz
b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
Denken Sie daran, dass:
- BROP + 0x7 auf
pop RSI; pop R15; ret;
zeigt - BROP + 0x9 auf
pop RDI; ret;
zeigt - PLT + 0xb auf einen Aufruf zu dl_resolve zeigt.
Nachdem strcmp
gefunden wurde, ist es möglich, rdx
auf einen Wert größer als 0 zu setzen.
tip
Beachten Sie, dass rdx
normalerweise bereits einen Wert größer als 0 enthält, sodass dieser Schritt möglicherweise nicht erforderlich ist.
8. Write oder Äquivalentes finden
Schließlich wird ein Gadget benötigt, das Daten exfiltriert, um die Binärdatei zu exfiltrieren. Und zu diesem Zeitpunkt ist es möglich, 2 Argumente zu steuern und rdx
größer als 0 zu setzen.
Es gibt 3 gängige Funktionen, die dafür ausgenutzt werden könnten:
puts(data)
dprintf(fd, data)
write(fd, data, len(data)
Das ursprüngliche Papier erwähnt jedoch nur die write
-Funktion, also lassen Sie uns darüber sprechen:
Das aktuelle Problem ist, dass wir nicht wissen, wo sich die Write-Funktion innerhalb der PLT befindet und wir wissen nicht, eine fd-Nummer, um die Daten an unseren Socket zu senden.
Wir wissen jedoch, wo sich die PLT-Tabelle befindet, und es ist möglich, write basierend auf seinem Verhalten zu finden. Und wir können mehrere Verbindungen mit dem Server herstellen und eine hohe FD verwenden, in der Hoffnung, dass sie mit einigen unserer Verbindungen übereinstimmt.
Verhaltenssignaturen, um diese Funktionen zu finden:
'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0) + p64(0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> Wenn Daten gedruckt werden, wurde puts gefunden'A' * offset + canary + rbp + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> Wenn Daten gedruckt werden, wurde dprintf gefunden'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
-> Wenn Daten gedruckt werden, wurde write gefunden
Automatische Ausnutzung
Referenzen
- Originalpapier: 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
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.