
Linux ELF x32/x64 ASLR DEP/NX-Bypass-Exploit mit stack-spraying
Linux ELF x32/x64 ASLR DEP/NX Bypass-Exploit mit Stack-Spraying

Eigenschaften:
Abhängigkeiten:
Einschränkungen:
Du hast vielleicht von Heap Spraying gehört? Nun, Stack Spraying ist ähnlich, galt jedoch in den meisten Fällen als unpraktikabel, insbesondere ASLR auf x86-64.
Meine Arbeit wird das Gegenteil beweisen.
Für 32-Bit gibt es 2^32 (4 294 967 296) theoretische Adressen, dennoch erlaubt der Kernel die Kontrolle über nur etwa die Hälfte der Bits (2^(32/2) = 65 536) für eine Ausführung in einem virtualisierten Speicher. Das bedeutet, dass wir, wenn wir mehr als 50 000 Zeichen auf dem Stack kontrollieren, mit hoher Wahrscheinlichkeit auf unseren Shellcode zeigen, unabhängig von der Adresse, dank Kernel-Umleitung und Neuübersetzung. Meinen Tests zufolge reichen sogar 100 oder 10 Zeichen aus, wenn die aufgerufene Funktion keine weiteren Variablen erstellt, was einen ROP-artigen Angriff ermöglicht.
Dies kann mithilfe von Shell-Variablen erreicht werden, die nicht wirklich auf eine bestimmte Länge begrenzt sind, deren praktisches Limit jedoch bei etwa einhunderttausend liegt, da sonst das TTY gesättigt wird.
Um also mit beliebigem Shellcode erfolgreich auszunutzen, müssen wir einen NOP-Slide nach dem Shellcode in eine Shell-Variable einfügen und das Binary einfach mit einer zufälligen Adresse ausnutzen. Beachte, dass ein NOP-Slide nicht zwingend erforderlich ist, dient aber der Universalisierung des Exploits.
In einem 64-Bit-System ist die Situation anders, aber nicht so sehr, wie ich entdeckt habe.
Natürlich müsste man nicht alle 2^64 Möglichkeiten abdecken; tatsächlich erlaubt der Kernel nur 48 Bits, plus ein Teil davon ist vorhersagbar und statisch, was uns etwa 2^(4x8+5) (137 438 953 472) Möglichkeiten lässt.
Ich habe das Größenlimit der Shell-Variablen erwähnt, aber es gibt auch ein Anzahl-Limit, das bei etwa 10 zu liegen scheint, sodass wir einen 1 000 000 Zeichen langen Shellcode speichern können, was uns nur einige Zehntausend Möglichkeiten lässt, die schnell und automatisch getestet werden können. Diesmal wirst du jedoch bruteforcen und NOP-Slides verwenden müssen, um die Sache zu beschleunigen.
Das bedeutet, dass ASLR sowohl auf 32- als auch auf 64-Bit in wenigen Minuten und mit wenigen Zeilen Shell-Code leicht umgangen werden kann.
Der DEP/NX hingegen kann auf x32 mit der Return-to-libc-Technik umgangen werden, indem man sie mit statistischen Studien verschiedener Betriebssysteme kombiniert, genauer gesagt mit deren ASLR-Einschränkungen und -Implementierungen, was aus zwei Gründen zu einer erfolgreichen Ausnutzung führen kann. Der erste Grund ist, dass ASLR in seiner Wahl nicht so zufällig ist und einige Konstanten sowie eine schlechte Entropie aufweist (einfach zu erratende libC-Adresse und jedes Betriebssystem hat seine eigenen Konstanten). Der zweite Grund ist das Sprühen des Shell-Arguments für libC in die Umgebung (einfach zu finden und an libC zu übergeben).
Zusammenfassend lässt sich sagen, dass DEP/NX auf 32-Bit aufgrund von ASLR geschwächt ist.
Eine detailliertere Beschreibung findest du in der Hakin9-12-14 Ausgabe.
Wenn du bereits mindestens einen Pufferüberlauf in deinem Leben ausgenutzt hast, kannst du diesen Teil überspringen, aber nur für den Fall:
apt install gcc libc6-dev-i386 || kill -9 $$
chmod u+x ASLRay.sh
sudo gcc -z execstack test.c -o test
sudo gcc -m32 -z execstack test.c -o test32
sudo chmod +s test test32
source ASLRay.sh test32 1024
source ASLRay.sh test 1024
source ASLRay.sh test 1024 \x31\x80...your_shellcode_here
sudo gcc -m32 test.c -o test32x
sudo chmod +s test test32
source ASLRay.sh test32x 1024
Um zu beweisen, dass ein NOP-Slide für Debian x32 nicht notwendig ist:
!!! WARNUNG !!! Dies wird deine /etc/passwd ändern und die Berechtigungen von /etc/shadow ändern, VM-Ausführung empfohlen
chmod u+x PoC.sh
source PoC.sh
grep ALI /etc/passwd
Falls es immer noch nicht funktioniert, füge einfach einige NOPs (\x90) am Anfang hinzu.
Um zu beweisen, dass nicht einmal eine Umgebungsvariable für Debian x32 notwendig ist:
chmod u+x PoC2.sh
source PoC2.sh
Somit kannst du deinen Shellcode einfach in eine Variable einfügen und zufällige Adressen an Register für eine Shell mit ASLR übergeben. Dies liegt an dem spezifischen Kontext, in dem die Funktion nur eine Variable hat, die überschrieben wird, sodass der Stack nur mit unserem Shellcode auf den EIP gesprungen wird, was eher einem ROP-Angriff ähnelt.
Für Arch/Ubuntu musst du zusätzlich den Stack-Smashing-Schutz deaktivieren und das Brute-Forcen kann viel länger dauern (Ausführungsverzögerung, wahrscheinlich aufgrund des brk(NULL/0)-Syscalls und/oder Canary):
sudo gcc -z execstack -fno-stack-protector test.c -o test
sudo gcc -m32 -z execstack -fno-stack-protector test.c -o test32
sudo gcc -m32 -fno-stack-protector test.c -o test32x
Unter Debian 10 wurde dieses Problem teilweise gepatcht, insbesondere aufgrund von AppArmor.
Verlasse dich immer auf mehrere Schutzmechanismen und nicht nur auf einen einzigen.
Wir brauchen neue Systemsicherheitsmechanismen.
"Von wo wir stehen, scheint der Regen zufällig. Wenn wir woanders stehen könnten, würden wir die Ordnung darin sehen."
Tony Hillerman, Coyote Waits