
# ShellcodeFluctuation PoC, portiert auf Nim
Nim-Port des ursprünglichen Repos: https://github.com/mgeeky/ShellcodeFluctuation Alle Kommentare wurden exakt so aus dem ursprünglichen Repository kopiert, da sie mir wirklich geholfen haben, die Technik zu verstehen. Für weitere Informationen über die Technik selbst empfehle ich dringend, das README des ursprünglichen Repos durchzugehen!
Abhängigkeiten installieren:
nimble install winim ptr_math
Mir ist vollkommen bewusst, dass diese Speicherverschlüsselungstechnik in Bezug auf OpSec nicht die beste ist. Sie verschlüsselt nur genau die Regionen, die für sie definiert wurden. So werden z. B. bei einem C2-Implant alle neu ausgeführten Modul-Speicheradressen beim Sleep nicht verschlüsselt. Für Heap-basierte Erkennungen (wie zum Beispiel die für die Cobalt-Strike-Konfiguration) müsste man hier immer noch eine Heap-Verschlüsselung hinzufügen.
Aber dennoch kann die Speicherverschlüsselungstechnik problemlos verwendet werden, um automatische Speicherscanner-Erkennungen beim Sleep for the main C2-Implant zu vermeiden. Ich habe den PoC erfolgreich mit Covenant und einem angepassten stageless Payload wie diesem getestet.
Der Verschlüsselungs-/Entschlüsselungsschlüssel sowie die Shellcode-Adresse und weitere Werte wie der Schutz (RW) müssen in diesem Port manuell definiert werden. Im ursprünglichen Repo wurde die Shellcode-Aufruferadresse automatisch ermittelt.
Die Datei Example.nim enthält alles, was du zum Loslegen brauchst. Wenn du C2-Shellcode verwendest, musst du Sleep natürlich nicht selbst aufrufen (das dient nur dazu, für den PoC alles auszulösen), das sollte dein C2 selbst übernehmen. Derzeit ist dies nur mit C2-Frameworks kompatibel, die die Win32-Sleep-Funktion verwenden. Wenn du den Hook für eine andere Funktion anpasst, funktioniert es auf die gleiche Weise.
import winim
import Fluctuation
echo "Trying to hook Sleep"
if (hookSleep()):
echo "Hooked Sleep successfully!"
type
PocArray = array[12, byte]
let names: PocArray = [byte 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA]
g_fluctuationData.shellcodeAddr = unsafeAddr names[0]
echo "Shellcode address:"
echo repr(g_fluctuationData.shellcodeAddr)
g_fluctuationData.shellcodeSize = size_t(len(names))
echo "Shellcode Size:"
echo repr(g_fluctuationData.shellcodeSize)
when defined(amd64):
g_fluctuationData.encodeKey = 0xDEADB33f
when defined(i386):
g_fluctuationData.encodeKey = 0xDEAD
g_fluctuationData.currentlyEncrypted = false
g_fluctuationData.protect = PAGE_READWRITE
g_fluctuate = FluctuateToRW
echo "Calling Sleep"
Sleep(2500)
echo "Everything went fine and as expected"
else:
echo "Failed to hook Sleep"
quit(1)
Das Testen des Verschlüsselungs-PoCs kann z. B. so erfolgen:
nim c --debuginfo --linedir:on Example.nim
Mit einem Debugger starten:
gdb Example.exe
Breakpoints vor und nach Sleep setzen:
# Before encryption
break Example.nim:31
# After encryption
break Fluctuation.nim:98
# Original value restored
break Example.nim:33
Anschließend den Wert der Shellcode-Adresse für jeden Breakpoint wie folgt überprüfen:

Die Fluktuation zu NA funktioniert noch nicht, da der Vectored Exception Handler in meinem Test nie ausgelöst wurde, sondern die Anwendung abstürzte. Ich muss in Zukunft noch einige weitere Tests/Fehlersuchen durchführen. Teste es gerne selbst! :-)