
Ein blitzschneller™ mehrthreadiger ROP-Gadget-Finder. Alternative zu ropper / ropgadget (derzeit nur x86)
ropr ist ein extrem schneller, multithreaded ROP-Gadget-Finder
ROP (Return Oriented Programming)-Gadgets sind kleine Ausschnitte aus wenigen Assembler-Befehlen, die typischerweise mit einer ret-Anweisung enden und als ausführbarer Code bereits in jeder Binary oder Bibliothek vorhanden sind. Diese Gadgets können zur Binary-Exploitation und zur Umgehung verwundbarer ausführbarer Dateien verwendet werden.
Wenn die Adressen vieler ROP-Gadgets in einen Puffer geschrieben werden, entsteht eine ROP-Chain. Falls ein Angreifer den Stack-Pointer auf diese ROP-Chain umlenken kann, wird die Kontrolle vollständig an den Angreifer übertragen.
Die meisten ausführbaren Dateien enthalten genügend Gadgets, um eine turingvollständige ROP-Chain zu schreiben. Für jene, die das nicht tun, kann man immer noch dynamische Bibliotheken im selben Adressraum verwenden, wie z. B. libc, sobald deren Adressen bekannt sind.
Das Schöne an der Verwendung von ROP-Gadgets ist, dass kein neuer ausführbarer Code irgendwo geschrieben werden muss – ein Angreifer kann sein Ziel allein mit dem bereits im Programm vorhandenen Code erreichen.
Typischerweise ist die erste Voraussetzung für die Verwendung von ROP-Gadgets ein Ort, an den man die ROP-Chain schreiben kann – das kann jeder lesbare Puffer sein. Einfach die Adressen jedes gewünschten Gadgets in diesen Puffer schreiben. Ist der Puffer zu klein, ist möglicherweise nicht genug Platz für eine lange ROP-Chain vorhanden, daher sollte ein Angreifer seine ROP-Chain so effizient gestalten, dass sie in den verfügbaren Platz passt.
Die nächste Voraussetzung ist die Fähigkeit, den Stack zu kontrollieren – dies kann in Form eines Stack-Overflows geschehen, der es erlaubt, die ROP-Chain direkt unter dem Stack-Pointer zu schreiben, oder eines „Stack-Pivots“ – normalerweise ein einzelnes Gadget, das den Stack-Pointer auf den Rest der ROP-Chain verschiebt.
Sobald der Stack-Pointer am Anfang der ROP-Chain steht, löst die nächste ret-Anweisung die sequenzielle Ausführung der Gadgets aus – jedes verwendet das nächste als Rücksprungadresse im eigenen Stack-Frame.
Es ist auch möglich, Funktionszeiger in eine ROP-Chain einzufügen – dabei muss darauf geachtet werden, dass die Funktionsargumente nach dem nächsten Element der ROP-Chain bereitgestellt werden. Dies wird typischerweise mit einem „Pop-Gadget“ kombiniert, das die Argumente vom Stack entfernt, um reibungslos zum nächsten Gadget nach den Funktionsargumenten überzugehen.
Einfache Installation:
cargo install ropr
Die Anwendung wird nach ~/.cargo/bin installiert.
Aus dem Quellcode:
git clone https://github.com/Ben-Lichtman/ropr
cd ropr
cargo build --release
Die resultierende Binary befindet sich in target/release/ropr.
Alternativ:
git clone https://github.com/Ben-Lichtman/ropr
cd ropr
cargo install --path .
Die Anwendung wird nach ~/.cargo/bin installiert.
VERWENDUNG:
ropr [OPTIONEN] <BINARY>
ARGUMENTE:
<BINARY> Der Pfad der zu untersuchenden Datei
OPTIONEN:
-b, --base-pivot Filtert nach Gadgets, die den Basis-Pointer verändern
-c, --colour <FARBE> Erzwingt farbige oder reine Textausgabe (`true` oder `false`)
-h, --help Hilfeinformationen anzeigen
-j, --nojop Entfernt „JOP-Gadgets“ – diese können anstelle eines einfachen
`ret` am Ende einen steuerbaren Sprung, Aufruf usw. haben
-m, --max-instr <MAX_BEFEHLE> Maximale Anzahl von Befehlen in einem Gadget [Standard: 6]
-n, --noisy Bezieht potenziell minderwertige Gadgets wie Präfixe,
bedingte Sprünge und nahe Sprünge ein (findet deutlich mehr Gadgets)
-p, --stack-pivot Filtert nach Gadgets, die den Stack-Pointer verändern
-r, --norop Entfernt normale „ROP-Gadgets“
-R, --regex <REGEX> Führt eine Regex-Suche auf den gefundenen Gadgets zur einfachen
Filterung durch
--range <BEREICH> Sucht zwischen Adressbereichen (hexadezimal), z. B. `0x1234-0x4567`
--raw <RAW> Behandelt die Eingabedatei als Code-Blob (`true` oder `false`)
-s, --nosys Entfernt Syscalls und andere Unterbrechungen
-V, --version Versionsinformationen anzeigen
Wenn ich zum Beispiel einen Weg suche, um rax mit einem Wert aus einem anderen Register zu füllen, könnte ich mit dem Regex ^mov eax, ...; filtern:
❯ ropr /usr/lib/libc.so.6 -R "^mov eax, ...;" > /dev/null
==> Found 197 gadgets in 0.118 seconds
Jetzt kann ich einige Filter zur Befehlszeile hinzufügen, um die hochwertigsten Ergebnisse zu erhalten:
❯ ropr /usr/lib/libc.so.6 -m 2 -j -s -R "^mov eax, ...;"
0x000353e7: mov eax, eax; ret;
0x000788c8: mov eax, ecx; ret;
0x00052252: mov eax, edi; ret;
0x0003ae43: mov eax, edx; ret;
0x000353e6: mov eax, r8d; ret;
0x000788c7: mov eax, r9d; ret;
==> Found 6 gadgets in 0.046 seconds
Jetzt habe ich einen guten mov-Gadget-Kandidaten an Adresse 0x00052252.