
PoC-Implementierung eines vollständig dynamischen Call-Stack-Spoofers
PoC-Implementierung eines vollständig dynamischen Call-Stack-Spoofers
SilentMoonwalk ist eine PoC-Implementierung eines vollständig dynamischen Call-Stack-Spoofers, der eine Technik implementiert, um den ursprünglichen Aufrufer aus dem Call-Stack zu entfernen, indem ROP verwendet wird, um das Unwinding vom Kontrollfluss zu desynchronisieren.
Diese PoC ist das Ergebnis einer gemeinsamen Forschung zum Thema Stack-Spoofing. Die Autoren der Forschung sind:
Ich möchte betonen, dass diese Arbeit ohne die Arbeit von Waldo-IRC und Trickster0 unmöglich gewesen wäre, die beide zu den frühen Phasen der PoC und zur Forschung hinter der PoC beigetragen haben.
Dieses Repository demonstriert eine PoC-Implementierung zum Spoofen des Call-Stacks beim Aufruf beliebiger Windows-APIs.
Dieser Versuch wurde inspiriert von diesem Twitter-Thread und diesem Twitter-Thread, in denen Sensei namazso zeigte und vorschlug, den Stack-Unwinding-Ansatz mit einer ROP-Kette zu erweitern, um sowohl das Unwinding vom echten Kontrollfluss zu desynchronisieren als auch den ursprünglichen Stack danach wiederherzustellen.
Diese PoC versucht, etwas Ähnliches wie oben zu tun, und verwendet einen Desync-Stack, um den ursprünglichen Aufrufstapel vollständig zu verbergen, wobei auch die EXE-Imagebasis daraus entfernt wird. Bei der Rückkehr wird ein ROP-Gadget aufgerufen, um den ursprünglichen Stack wiederherzustellen. Im Code wird dieser Prozess 10 Mal in einer Schleife wiederholt, wobei bei jeder Iteration unterschiedliche Frames verwendet werden, um die Stabilität zu beweisen.
Das Tool unterstützt derzeit 2 Modi, wobei einer eigentlich ein falscher Patch für einen nicht funktionierenden Pop-RBP-Frame ist, der erkannt wurde, und funktioniert, indem der aktuelle RSP verschoben und zwei gefälschte Frames zum Aufrufstapel hinzugefügt werden. Da es mit synthetischen Frames arbeitet, bezeichne ich diesen Modus als "SYNTHETIC".
Wenn der Frame ausgewählt wird, der durch Poppen des RBP-Registers vom Stack entlädt, könnte das Tool einen ungeeigneten Frame auswählen, was zu einem abrupt abgeschnittenen Aufrufstapel führt, wie unten zu sehen.

Eine alberne Lösung für das Problem wäre es, zwei gefälschte Frames zu erstellen und sie wieder mit dem abgeschnittenen Aufrufstapel zu verknüpfen. Dies würde eine Art scheinbar legitimen Aufrufstapel erzeugen, selbst ohne einen geeigneten Frame, der durch Aufrufen von POP RBP entlädt, aber:
Das Ergebnis des _synthetischen Spoofs kann im folgenden Bild beobachtet werden:

Abbildung 1: Windows 10 - Scheinbar legitimer, nicht entladbarer Aufrufstapel, bei dem das EXE-Modul vollständig entfernt wurde (Aufruf der parameterlosen Funktion getchar)
Hinweis: Dieser Betriebsmodus ist standardmäßig deaktiviert. Um diesen Modus zu aktivieren, ändern Sie CALLSTACK_TYPE auf 1
Dieser Modus ist die richtige Lösung für das obige Problem, wobei der ungeeignete Frame einfach durch einen anderen, geeigneten ersetzt wird.

Abbildung 2: Windows 10 - Legitimer, entladbarer Aufrufstapel, bei dem das EXE-Modul vollständig entfernt wurde (Aufruf der 4-Parameter-Funktion MessageBoxA)
Im Repository finden Sie auch ein kleines Hilfsprogramm zur Inspektion von Laufzeitfunktionen, das nützlich sein kann, um Laufzeitfunktionseinträge zu analysieren.
UnwindInspector.exe -h
Unwind Inspector v0.100000
Mandatory args:
-m <module>: Target DLL
-f <function>: Target Function
-a <function-address>: Target Function Address
Beispielausgabe:
UnwindInspector.exe -m kernelbase -a 0x7FFAAE12182C
[*] Using function address 0x7ffaae12182c
Runtime Function (0x000000000000182C, 0x00000000000019ED)
Unwind Info Address: 0x000000000026AA88
Version: 0
Ver + Flags: 00000000
SizeOfProlog: 0x1f
CountOfCodes: 0xc
FrameRegister: 0x0
FrameOffset: 0x0
UnwindCodes:
[00h] Frame: 0x741f - 0x04 - UWOP_SAVE_NONVOL (RDI, 0x001f)
[01h] Frame: 0x0015 - 0x00 - UWOP_PUSH_NONVOL (RAX, 0x0015)
[02h] Frame: 0x641f - 0x04 - UWOP_SAVE_NONVOL (RSI, 0x001f)
[03h] Frame: 0x0014 - 0x00 - UWOP_PUSH_NONVOL (RAX, 0x0014)
[04h] Frame: 0x341f - 0x04 - UWOP_SAVE_NONVOL (RBX, 0x001f)
[05h] Frame: 0x0012 - 0x00 - UWOP_PUSH_NONVOL (RAX, 0x0012)
[06h] Frame: 0xb21f - 0x02 - UWOP_ALLOC_SMALL (R11, 0x001f)
[07h] Frame: 0xf018 - 0x00 - UWOP_PUSH_NONVOL (R15, 0x0018)
[08h] Frame: 0xe016 - 0x00 - UWOP_PUSH_NONVOL (R14, 0x0016)
[09h] Frame: 0xd014 - 0x00 - UWOP_PUSH_NONVOL (R13, 0x0014)
[0ah] Frame: 0xc012 - 0x00 - UWOP_PUSH_NONVOL (R12, 0x0012)
[0bh] Frame: 0x5010 - 0x00 - UWOP_PUSH_NONVOL (RBP, 0x0010)
Um die PoC zu bauen und ein ähnliches Verhalten wie im Bild zu beobachten, stellen Sie sicher, dass Sie:
/GS-)/Od)/GL entfernen)/Os, /Ot entfernen)/Oi)Es lohnt sich, frühere Arbeiten zu diesem Thema zu erwähnen, die die Grundlage für diese Arbeit bildeten.