
Generiert positionsunabhängigen Shellcode für x86, x64 oder AMD64+x86, der .NET-Assemblies, PE-Dateien und andere Windows-Payloads aus dem Speicher lädt und mit Parametern ausführt

Aktuelle Version: v1.1
Donut ist ein positionsunabhängiger Code, der die In-Memory-Ausführung von VBScript-, JScript-, EXE-, DLL-Dateien und .NET-Assemblys ermöglicht. Ein mit Donut erstelltes Modul kann entweder von einem HTTP-Server bereitgestellt oder direkt in den Loader selbst eingebettet werden. Das Modul wird optional mit der Chaskey-Blockchiffre und einem 128-Bit-zufällig generierten Schlüssel verschlüsselt. Nachdem die Datei geladen und im Speicher ausgeführt wurde, wird die ursprüngliche Referenz gelöscht, um Speicherscanner abzuschrecken. Der Generator und Loader unterstützen die folgenden Funktionen:
Es gibt dynamische und statische Bibliotheken für Linux und Windows, die in Ihre eigenen Projekte integriert werden können. Es gibt auch ein Python-Modul, über das Sie in Building and using the Python extension mehr erfahren können.
Donut enthält individuelle Loader für jeden unterstützten Dateityp. Für .NET EXE/DLL-Assemblys verwendet Donut die Unmanaged CLR Hosting API, um die Common Language Runtime zu laden. Sobald die CLR in den Hostprozess geladen ist, wird eine neue Anwendungsdomäne erstellt, um die Ausführung von Assemblys in entsorgbaren AppDomains zu ermöglichen. Wenn die AppDomain bereit ist, wird die .NET-Assembly über die Methode AppDomain.Load_3 geladen. Schließlich wird der Einstiegspunkt für EXEs oder die vom Benutzer festgelegte öffentliche Methode für DLLs mit allen zusätzlichen Parametern aufgerufen. Siehe MSDN für die Dokumentation zur Unmanaged CLR Hosting API. Für ein eigenständiges Beispiel eines CLR-Hosts siehe Code hier.
VBScript- und JScript-Dateien werden über die IActiveScript-Schnittstelle ausgeführt. Es gibt auch minimale Unterstützung für einige der Methoden des Windows Script Host (wscript/cscript). Für ein eigenständiges Beispiel siehe Code hier. Für eine detailliertere Beschreibung lesen Sie: In-Memory Execution of JavaScript, VBScript, JScript and XSL
Nicht verwaltete oder native EXE/DLL-Dateien werden mit einem benutzerdefinierten PE-Loader ausgeführt, der Verzögerte Importe, TLS und das Patchen der Befehlszeile unterstützt. Es werden nur Dateien mit Verschiebeinformationen unterstützt. Lesen Sie In-Memory Execution of DLL für weitere Informationen.
Der Loader kann AMSI und WLDP deaktivieren, um die Erkennung von bösartigen Dateien, die im Speicher ausgeführt werden, zu erschweren. Weitere Informationen finden Sie unter: How Red Teams Bypass AMSI and WLDP for .NET Dynamic Code. Er unterstützt auch die Dekomprimierung von Dateien im Speicher mittels aPLib oder der RtlDecompressBuffer-API. Lesen Sie Data Compression für weitere Informationen.
Seit v1.0 wird auch ETW umgangen. Wie bei AMSI/WLDP handelt es sich um ein modulares System, das es Ihnen ermöglicht, die Standardumgehung durch Ihre eigene zu ersetzen. Die Standardumgehung basiert auf Forschungsergebnissen von XPN. Lesen Sie Hiding your .NET - ETW für weitere Informationen.
Standardmäßig überschreibt der Loader die PE-Header von nicht verwalteten PEs (von der Basisadresse bis zu `IMAGE_OPTIONAL_HEADER.SizeOfHeaders`). Wenn kein Täuschungsmodul verwendet wird (Modulüberlagerung), werden die PE-Header auf Null gesetzt. Wenn ein Täuschungsmodul verwendet wird, werden die PE-Header des Täuschungsmoduls verwendet, um die des Nutzlastmoduls zu überschreiben. Dies dient dazu, eine Erkennung durch Vergleich der PE-Header von Modulen im Speicher mit der Datei auf der Festplatte zu erschweren. Der Benutzer kann verlangen, dass alle PE-Header in ihrem ursprünglichen Zustand erhalten bleiben. Dies ist hilfreich für Szenarien, in denen das Nutzlastmodul auf seine PE-Header zugreifen muss, z. B. beim Nachschlagen eingebetteter PE-Ressourcen.
Für einen detaillierten Leitfaden zur Verwendung des Generators und wie Donut die Arbeitsweise beeinflusst, lesen Sie Donut - Injecting .NET Assemblies as Shellcode. Weitere Informationen zum Loader finden Sie unter Loading .NET Assemblies From Memory.
Diejenigen, die mehr über die Interna erfahren möchten, sollten die Entwicklernotizen lesen.
Es gibt zwei Arten von Builds. Wenn Sie Donut debuggen möchten, lesen Sie bitte die Dokumentation hier. Wenn nicht, lesen Sie weiter für den Release-Build.
Klonen Sie das Repository von einer Windows-Eingabeaufforderung oder einem Linux-Terminal aus.
git clone http://github.com/thewover/donut.git
Der nächste Schritt hängt von Ihrem Betriebssystem und dem von Ihnen gewählten Compiler ab. Derzeit können der Generator und die Loader-Vorlage für Donut sowohl mit Microsoft Visual Studio 2019 als auch mit MinGW-64 erfolgreich kompiliert werden. Informationen zur Verwendung der Bibliotheken in Ihrem eigenen C/C++-Projekt finden Sie in den hier bereitgestellten Beispielen.
Um die Loader-Vorlage, die dynamische Bibliothek donut.dll, die statische Bibliothek donut.lib und den Generator donut.exe zu erstellen, starten Sie eine x64-Eingabeaufforderung für Microsoft Visual Studio Developer, wechseln Sie in das Verzeichnis, in das Sie das Donut-Repository geklont haben, und geben Sie Folgendes ein:
nmake -f Makefile.msvc
Um dasselbe zu tun, jedoch mit MinGW-64 unter Windows oder Linux, wechseln Sie in das Verzeichnis, in das Sie das Donut-Repository geklont haben, und geben Sie Folgendes ein:
make -f Makefile.mingw
Um die dynamische Bibliothek donut.so, die statische Bibliothek donut.a und den Generator donut zu erzeugen, wechseln Sie in das Verzeichnis, in das Sie das Donut-Repository geklont haben, und geben Sie einfach make ein.
Donut kann als Python-Modul installiert und verwendet werden. Für die Installation aus dem Quellcode ist pip für Python3 erforderlich. Stellen Sie zunächst sicher, dass ältere Versionen von donut-shellcode nicht installiert sind, indem Sie den folgenden Befehl in einem Linux-Terminal oder einer Microsoft Visual Studio-Eingabeaufforderung ausführen.
pip3 uninstall donut-shellcode
Nachdem Sie bestätigt haben, dass ältere Versionen nicht mehr installiert sind, führen Sie den folgenden Befehl aus.
pip3 install .
Sie können Donut auch als Python-Modul installieren, indem Sie es aus dem PyPi-Repository beziehen.
pip3 install donut-shellcode
Weitere Informationen finden Sie unter: Building and using the Python extension.
Erstellen des Docker-Containers.
docker build -t donut .
Ausführen von Donut.
docker run -it --rm -v "${PWD}:/workdir" donut -h
Donut enthält mehrere andere ausführbare Dateien, die separat erstellt werden können. Dazu gehören "hash.exe", "encrypt.exe","inject.exe" und "inject_local.exe". Die ersten beiden werden bei der Shellcode-Generierung verwendet. Die letzten beiden werden zur Unterstützung beim Testen von Donut-Shellcode bereitgestellt. "inject.exe" injiziert eine rohe Binärdatei (loader.bin) in einen Prozess anhand seiner PID oder seines Prozessnamens. "inject_local.exe" injiziert eine rohe Binärdatei in den eigenen Prozess.
Um diese Hilfsprogramme separat zu erstellen, können Sie das MSVC-Makefile verwenden. Um beispielsweise "inject_local.exe" zum Testen Ihres Donut-Shellcodes zu erstellen, können Sie Folgendes ausführen:
nmake inject_local -f Makefile.msvc
Für jede Release-Version von Donut wurden Tags bereitgestellt, die die kompilierten ausführbaren Dateien enthalten.
Derzeit gibt es zwei weitere Generatoren.
Die folgende Tabelle listet die Schalter auf, die von der Befehlszeilenversion des Generators unterstützt werden.
Es gibt einige spezifische Anforderungen, die Ihre Nutzlast erfüllen muss, damit Donut sie erfolgreich laden kann.
Cygwin-ausführbare Dateien verwenden Initialisierungsroutinen, die erwarten, dass der Hostprozess von der Festplatte ausgeführt wird. Bei Ausführung aus dem Speicher stürzt der Hostprozess wahrscheinlich ab.
Donut enthält vier Begleitprojekte:
Vielleicht möchten Sie Unterstützung für weitere Nutzlasttypen hinzufügen, unsere Funktionen ändern oder Donut in Ihre vorhandenen Tools integrieren. Wir haben eine Entwicklerdokumentation bereitgestellt. Zusätzliche Funktionen bleiben dem Leser als Übung überlassen. Unsere Vorschläge:
Wenn Sie Fragen oder Kommentare zu Donut haben, treten Sie dem #Donut-Kanal im BloodHound Gang Slack bei.
Wir sind nicht verantwortlich für Missbrauch dieser Software oder Technik. Donut wird als Demonstration der CLR-Injektion und des In-Memory-Ladens durch Shellcode bereitgestellt, um Red Teams eine Möglichkeit zu geben, Gegner zu emulieren, und Verteidigern einen Referenzrahmen für den Aufbau von Analysen und Gegenmaßnahmen zu bieten. Dies birgt unweigerlich das Risiko, dass Malware-Autoren und Bedrohungsakteure es missbrauchen. Wir glauben jedoch, dass der Nettonutzen das Risiko überwiegt. Hoffentlich ist das richtig. Falls EDR- oder AV-Produkte in der Lage sind, Donut über Signaturen oder Verhaltensmuster zu erkennen, werden wir Donut nicht aktualisieren, um Signaturen oder Erkennungsmethoden entgegenzuwirken. Um nicht beleidigt zu sein, bitten Sie bitte nicht darum.
| Schalter | Argument | Beschreibung |
|---|---|---|
| -a | arch | Zielarchitektur für den Loader: 1=x86, 2=amd64, 3=x86+amd64 (Standard). |
| -b | level | Verhalten zum Umgehen von AMSI/WLDP: 1=Kein, 2=Bei Fehler abbrechen, 3=Bei Fehler fortsetzen (Standard). |
| -k | headers | PE-Header beibehalten. 1=Überschreiben (Standard), 2=Alle behalten. |
| -j | decoy | Optionaler Pfad des Täuschungsmoduls für das Modulüberladen. |
| -c | class | Optionaler Klassenname. (erforderlich für .NET-DLL) Kann auch den Namespace enthalten: z. B. namespace.class |
| -d | name | AppDomain-Name, der für .NET erstellt werden soll. Wenn Entropie aktiviert ist, wird einer zufällig generiert. |
| -e | level | Entropiestufe. 1=Keine, 2=Zufällige Namen generieren, 3=Zufällige Namen generieren + symmetrische Verschlüsselung verwenden (Standard) |
| -f | format | Das Ausgabeformat des Loaders, der in eine Datei gespeichert wird. 1=Binär (Standard), 2=Base64, 3=C, 4=Ruby, 5=Python, 6=PowerShell, 7=C#, 8=Hexadezimal |
| -m | name | Optionaler Methoden- oder Funktionsname für DLL. (eine Methode ist für .NET-DLL erforderlich) |
| -n | name | Modulname für HTTP-Staging. Wenn Entropie aktiviert ist, wird einer zufällig generiert. |
| -o | path | Gibt an, wo Donut den Loader speichern soll. Standard ist "loader.bin" im aktuellen Verzeichnis. |
| -p | parameters | Optionale Parameter/Befehlszeile in Anführungszeichen für DLL-Methode/-Funktion oder EXE. |
| -r | version | CLR-Laufzeitversion. Standardmäßig wird MetaHeader verwendet, oder v4.0.30319, falls keiner verfügbar ist. |
| -s | server | URL für den HTTP-Server, der ein Donut-Modul hosten wird. Anmeldeinformationen können im folgenden Format bereitgestellt werden: https://benutzername:[email protected]/ |
| -t | Den Einstiegspunkt einer nicht verwalteten/nativen EXE als Thread ausführen und auf das Ende des Threads warten. | |
| -w | Die Befehlszeile wird im UNICODE-Format an die nicht verwaltete DLL-Funktion übergeben. (Standard ist ANSI) | |
| -x | option | Legt fest, wie der Loader beendet werden soll. 1=Thread beenden (Standard), 2=Prozess beenden, 3=Nicht beenden oder bereinigen und auf unbestimmte Zeit blockieren |
| -y | addr | Erstellt einen neuen Thread für den Loader und setzt die Ausführung an einer Adresse fort, die ein Offset relativ zur ausführbaren Datei des Hostprozesses ist. Der angegebene Wert ist der Offset. Diese Option unterstützt Loader, die nach Abschluss der Donut-Ausführung die Ausführung des Hostprozesses fortsetzen möchten. |
| -z | engine | Paketieren/Komprimieren der Eingabedatei. 1=Keine, 2=aPLib, 3=LZNT1, 4=Xpress, 5=Xpress Huffman. Derzeit werden die letzten drei nur unter Windows unterstützt. |
| Werkzeug | Beschreibung |
|---|---|
| DemoCreateProcess | Eine Beispiel-.NET-Assembly für Tests. Nimmt zwei Befehlszeilenparameter entgegen, die jeweils ein auszuführendes Programm angeben. |
| DonutTest | Ein einfacher C#-Shellcode-Injektor zum Testen von Donut. Der Shellcode muss base64-kodiert und als Zeichenfolge eingefügt werden. |
| ModuleMonitor | Ein Proof-of-Concept-Werkzeug, das die CLR-Injektion erkennt, wie sie von Tools wie Donut und Cobalt Strikes execute-assembly durchgeführt wird. |
| ProcessManager | Ein Werkzeug zur Prozesserkennung, das von Angreifern verwendet werden kann, um zu bestimmen, in was sie injizieren sollen, und von Verteidigern, um zu bestimmen, welche Prozesse ausgeführt werden, welche Eigenschaften diese Prozesse haben und ob sie die CLR geladen haben. |