BROP - Blind Return Oriented Programming

Lerne & übe AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Lerne & übe GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Grundinformationen

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.

Angriff

1. Finde verwundbaren Offset indem du ein weiteres Zeichen sendest, 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 findest du hier (BF Forked & Threaded Stack Canaries) und hier (BF Adressen im Stack).

4. Finde das Stop-Gadget

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.

5. Finde BROP-Gadget

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 folgt 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.

6. Finde PLT

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. Finden von strcmp

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) aufzurufen, 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 haben wird, sodass dieser Schritt möglicherweise nicht notwendig ist.

8. Finden von Write oder Äquivalent

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

Automatische Ausnutzung

Referenzen

Lerne & übe AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Lerne & übe GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Last updated