BROP - Blind Return Oriented Programming
Last updated
Last updated
Lerne & übe AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Lerne & übe GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Das Ziel dieses Angriffs ist es, einen ROP über einen Buffer Overflow ohne Informationen über die verwundbare Binärdatei auszunutzen. 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 startet.
Weitere Informationen zu diesen Prozessen findest du hier (BF Forked & Threaded Stack Canaries) und hier (BF Adressen im Stack).
Dieses Gadget ermöglicht es im Grunde, zu bestätigen, dass etwas Interessantes vom 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 man nach ROP-Gadgets sucht, um zu bestätigen, dass ein bestimmtes ROP-Gadget ausgeführt wurde.
Diese Technik verwendet das ret2csu Gadget. Und das liegt daran, dass du, wenn du auf dieses Gadget in der Mitte einiger Anweisungen zugreifst, Gadgets erhältst, um rsi
und rdi
zu steuern:
Das wären die Gadgets:
pop rsi; pop r15; ret
pop rdi; ret
Beachte, wie es mit diesen Gadgets möglich ist, 2 Argumente einer Funktion zu steuern.
Beachte 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 das im Grunde, 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 zu inferieren, um rsi
und rdi
zu steuern.
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
Die strcmp
Funktion setzt das Register rdx
auf die Länge des zu vergleichenden Strings. Beachte, 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 wir die Tatsache nutzen, dass wir jetzt die 2 ersten Argumente von Funktionen steuern können:
strcmp(<nicht lesbare Adresse>, <nicht lesbare Adresse>) -> Absturz
strcmp(<nicht lesbare Adresse>, <lesbare Adresse>) -> Absturz
strcmp(<lesbare Adresse>, <nicht lesbare Adresse>) -> Absturz
strcmp(<lesbare Adresse>, <lesbare Adresse>) -> 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 Grunde 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(<nicht lesbare Adresse>, <lesbare Adresse>) -> Absturz
b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0x300) + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
-> Wird abstürzen
strcmp(<lesbare Adresse>, <nicht lesbare Adresse>) -> Absturz
b'A' * offset + canary + rbp + (BROP + 0x9) + p64(0x300) + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
strcmp(<lesbare Adresse>, <lesbare Adresse>) -> kein Absturz
b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
Denke 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.
Beachte, dass rdx
normalerweise bereits einen Wert größer als 0 enthält, sodass dieser Schritt möglicherweise nicht notwendig ist.
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 lass 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
Originalpapier: https://www.scs.stanford.edu/brop/bittau-brop.pdf
Lerne & übe AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Lerne & übe GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)