BROP - Blind Return Oriented Programming

Erlernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

Grundlegende Informationen

Das Ziel dieses Angriffs ist es, einen ROP über einen Pufferüberlauf ohne Informationen über das verwundbare Binärprogramm zu missbrauchen. Dieser Angriff basiert auf dem folgenden Szenario:

  • Eine Stapelverwundbarkeit und das Wissen darüber, wie man sie auslöst.

  • Eine Serveranwendung, die nach einem Absturz neu startet.

Angriff

1. Finden Sie den verwundbaren Offset, indem Sie ein weiteres Zeichen senden, bis ein Fehler des Servers erkannt wird

2. Brute-Force-Canary, um ihn zu leaken

3. Brute-Force gespeicherte RBP- und RIP-Adressen im Stapel, um sie zu leaken

Weitere Informationen zu diesen Prozessen finden Sie hier (BF Forked & Threaded Stack Canaries) und hier (BF Addresses in the Stack).

4. Finden Sie das Stop-Gadget

Dieses Gadget ermöglicht im Wesentlichen die Bestätigung, dass etwas Interessantes vom ROP-Gadget ausgeführt wurde, da die Ausführung nicht abgestürzt ist. Normalerweise handelt es sich bei diesem Gadget um etwas, 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. Finden Sie das BROP-Gadget

Diese Technik verwendet das ret2csu Gadget. Und das liegt daran, dass, wenn Sie auf dieses Gadget inmitten einiger Anweisungen zugreifen, Gadgets erhalten, um rsi und rdi zu steuern:

Dies 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 eindeutige Signatur hat, da es 6 Register vom Stapel abruft. Daher wird eine Kette wie folgt gesendet:

'A' * Offset + Canary + RBP + ADDR + 0xdead * 6 + STOP

Wenn das STOP ausgeführt wird, bedeutet dies im Grunde genommen, dass eine Adresse, die 6 Register vom Stapel abruft, 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 Gadget 6 Register abgerufen hat:

'A' * Offset + Canary + RBP + ADDR

Nachdem die Adresse des ret2csu-Gadgets gefunden wurde, ist es möglich, die Adresse der Gadgets zur Steuerung von rsi und rdi zu ableiten.

6. Finden Sie PLT

Die PLT-Tabelle kann ab 0x400000 oder von der geleakten RIP-Adresse vom Stapel aus durchsucht werden (wenn PIE verwendet wird). Die Einträge der Tabelle sind getrennt durch 16B (0x10B), und wenn eine Funktion aufgerufen wird, stürzt der Server nicht ab, auch wenn die Argumente nicht korrekt sind. Außerdem stürzt das Überprüfen der Adresse eines Eintrags in der PLT + 6B auch nicht ab, da es der erste ausgeführte Code ist.

Daher ist es möglich, die PLT-Tabelle anhand der folgenden Verhaltensweisen zu finden:

  • '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 Sie strcmp

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 möchten, dass es größer als 0 ist, um später write zum Leaken des Programms verwenden zu können.

Es ist möglich, den Speicherort von strcmp in der PLT anhand seines Verhaltens zu finden, wobei berücksichtigt wird, dass wir jetzt die ersten 2 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

Dies kann überprüft werden, indem jeder Eintrag der PLT-Tabelle aufgerufen wird oder indem der PLT-Slow-Path verwendet wird, der im Wesentlichen darin besteht, einen Eintrag in der PLT-Tabelle + 0xb (der zu dlresolve aufruft) aufzurufen, gefolgt im Stapel von der Eintragsnummer, die man prüfen möchte (beginnend bei null), um alle PLT-Einträge vom ersten zu durchsuchen:

  • 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

Denken Sie daran:

  • BROP + 0x7 zeigt auf pop RSI; pop R15; ret;

  • BROP + 0x9 zeigt auf pop RDI; ret;

  • PLT + 0xb zeigt auf einen Aufruf von dl_resolve.

Nachdem strcmp gefunden wurde, ist es möglich, rdx auf einen Wert größer als 0 zu setzen.

Beachten Sie, dass rdx normalerweise bereits einen Wert größer als 0 enthält, sodass dieser Schritt möglicherweise nicht erforderlich ist.

### 8. Finden von Write oder Äquivalent

Schließlich wird ein Gadget benötigt, das Daten exfiltriert, um das Binärprogramm zu exfiltrieren. Und zu diesem Zeitpunkt ist es möglich, 2 Argumente zu kontrollieren und rdx größer als 0 zu setzen.

Es gibt 3 gängige Funktionen, die dafür missbraucht werden könnten:

  • puts(data)

  • dprintf(fd, data)

  • write(fd, data, len(data)

Jedoch erwähnt das Originaldokument nur die write Funktion, also lassen Sie uns darüber sprechen:

Das aktuelle Problem ist, dass wir nicht wissen, wo sich die write-Funktion im PLT befindet und wir nicht wissen 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 einen hohen FD verwenden, in der Hoffnung, dass er mit einigen unserer Verbindungen übereinstimmt.

Verhaltenssignaturen zum Auffinden dieser Funktionen:

  • '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

Last updated