
Генерирует позиционно-независимый шелл-код для x86, x64 или AMD64+x86, который загружает сборки .NET, PE-файлы и другие полезные нагрузки Windows из памяти и запускает их с параметрами.

Текущая версия: v1.1
Donut — это позиционно-независимый код, который позволяет выполнять в памяти VBScript, JScript, EXE, DLL и сборки .NET. Модуль, созданный Donut, может быть как загружен с HTTP-сервера, так и встроен непосредственно в загрузчик. Модуль опционально шифруется с помощью блочного шифра Chaskey и 128-битного случайно сгенерированного ключа. После загрузки и выполнения файла в памяти исходная ссылка стирается для затруднения работы сканеров памяти. Генератор и загрузчик поддерживают следующие возможности:
Существуют динамические и статические библиотеки как для Linux, так и для Windows, которые можно интегрировать в ваши собственные проекты. Также есть модуль Python, о котором можно узнать больше в документации по сборке и использованию расширения Python.
Donut содержит отдельные загрузчики для каждого поддерживаемого типа файлов. Для сборок .NET EXE/DLL Donut использует Unmanaged CLR Hosting API для загрузки Common Language Runtime. После загрузки CLR в хост-процесс создаётся новый домен приложения (AppDomain) для возможности запуска сборок в disposable AppDomain. Когда AppDomain готов, сборка .NET загружается через метод AppDomain.Load_3. Наконец, вызывается точка входа для EXE или публичный метод для DLL, указанный пользователем, с любыми дополнительными параметрами. Обратитесь к MSDN за документацией по Unmanaged CLR Hosting API. Пример отдельного CLR Host см. в коде здесь.
Файлы VBScript и JScript выполняются с помощью интерфейса IActiveScript. Также есть минимальная поддержка некоторых методов, предоставляемых Windows Script Host (wscript/cscript). Пример отдельного решения см. в коде здесь. Более подробное описание читайте в: In-Memory Execution of JavaScript, VBScript, JScript and XSL
Неуправляемые (нативные) EXE/DLL-файлы выполняются с помощью пользовательского загрузчика PE с поддержкой отложенных импортов, TLS и патча командной строки. Поддерживаются только файлы с информацией о перемещениях. Подробнее читайте в In-Memory Execution of DLL.
Загрузчик может отключать AMSI и WLDP, чтобы помочь обойти обнаружение вредоносных файлов, выполняемых в памяти. Подробнее читайте в How Red Teams Bypass AMSI and WLDP for .NET Dynamic Code. Также он поддерживает декомпрессию файлов в памяти с помощью aPLib или API RtlDecompressBuffer. Подробнее читайте в Data Compression.
Начиная с версии v1.0 также осуществляется обход ETW. Как и для AMSI/WLDP, это модульная система, позволяющая заменить стандартный обход на свой собственный. Стандартный обход основан на исследовании XPN. Подробнее читайте в Hiding your .NET - ETW.
По умолчанию загрузчик перезаписывает заголовки PE неуправляемых PE (от базового адреса до `IMAGE_OPTIONAL_HEADER.SizeOfHeaders`). Если модуль-приманка не используется (module overloading), заголовки PE обнуляются. Если используется модуль-приманка, заголовки PE модуля-приманки используются для перезаписи заголовков полезной нагрузки. Это делается для затруднения обнаружения путём сравнения заголовков PE модулей в памяти с файлами на диске. Пользователь может запросить сохранение всех заголовков PE в исходном состоянии. Это полезно в сценариях, когда модулю полезной нагрузки требуется доступ к своим заголовкам PE, например, для поиска встроенных PE-ресурсов.
Подробное руководство по использованию генератора и влиянию Donut на тактику см. в Donut - Injecting .NET Assemblies as Shellcode. Дополнительную информацию о загрузчике см. в Loading .NET Assemblies From Memory.
Те, кто хочет узнать больше о внутреннем устройстве, должны обратиться к Заметкам разработчика.
Существует два типа сборки. Если вы хотите отлаживать Donut, обратитесь к документации здесь. Если нет, продолжайте чтение для релизной сборки.
Из командной строки Windows или терминала Linux клонируйте репозиторий.
git clone http://github.com/thewover/donut.git
Следующий шаг зависит от вашей операционной системы и выбранного компилятора. В настоящее время генератор и шаблон загрузчика для Donut успешно компилируются как с Microsoft Visual Studio 2019, так и с MingGW-64. Чтобы использовать библиотеки в вашем собственном проекте C/C++, обратитесь к примерам, приведённым здесь.
Для генерации шаблона загрузчика, динамической библиотеки donut.dll, статической библиотеки donut.lib и генератора donut.exe. Запустите x64 Microsoft Visual Studio Developer Command Prompt, перейдите в каталог, куда вы клонировали репозиторий Donut, и введите следующее:
nmake -f Makefile.msvc
Чтобы сделать то же самое, используя MinGW-64 в Windows или Linux, перейдите в каталог, куда вы клонировали репозиторий Donut, и введите следующее:
make -f Makefile.mingw
Для генерации динамической библиотеки donut.so, статической библиотеки donut.a и генератора donut. Перейдите в каталог, куда вы клонировали репозиторий Donut, и просто введите make.
Donut можно установить и использовать как модуль Python. Для установки из исходников требуется pip для Python3. Сначала убедитесь, что старые версии donut-shellcode не установлены, выполнив следующую команду в терминале Linux или командной строке Microsoft Visual Studio.
pip3 uninstall donut-shellcode
После подтверждения, что старые версии удалены, выполните следующую команду.
pip3 install .
Вы также можете установить Donut как модуль Python, загрузив его из репозитория PyPi.
pip3 install donut-shellcode
Для получения дополнительной информации обратитесь к документации по сборке и использованию расширения Python.
Сборка Docker-контейнера.
docker build -t donut .
Запуск donut.
docker run -it --rm -v "${PWD}:/workdir" donut -h
Donut включает несколько других исполняемых файлов, которые могут быть собраны отдельно. К ним относятся "hash.exe", "encrypt.exe", "inject.exe" и "inject_local.exe". Первые два используются при генерации шелл-кода. Последние два предоставлены для помощи в тестировании шелл-кода donut. "inject.exe" внедряет сырой бинарный файл (loader.bin) в процесс по его PID или имени процесса. "inject_local.exe" внедряет сырой бинарный файл в свой собственный процесс.
Чтобы собрать эти вспомогательные исполняемые файлы отдельно, вы можете использовать makefile MSVC. Например, чтобы собрать "inject_local.exe" для тестирования вашего шелл-кода donut, вы можете выполнить:
nmake inject_local -f Makefile.msvc
Для каждой релизной версии Donut предоставлены теги, содержащие скомпилированные исполняемые файлы.
В настоящее время доступны два других генератора.
В следующей таблице перечислены ключи, поддерживаемые консольной версией генератора.
Существуют определённые требования, которым должна соответствовать ваша полезная нагрузка, чтобы Donut успешно её загрузил.
Исполняемые файлы Cygwin используют процедуры инициализации, которые ожидают, что хост-процесс запущен с диска. При выполнении из памяти хост-процесс, скорее всего, аварийно завершится.
С donut поставляются четыре сопутствующих проекта:
Возможно, вы захотите добавить поддержку дополнительных типов полезных нагрузок, изменить наш набор функций или интегрировать Donut в ваши существующие инструменты. Мы предоставили документацию для разработчика. Дополнительные функции оставлены в качестве упражнения для читателя. Наши предложения:
Если у вас есть вопросы или комментарии о Donut, присоединяйтесь к каналу #Donut в Slack BloodHound Gang.
Мы не несём ответственности за любое неправомерное использование этого программного обеспечения или техники. Donut предоставляется как демонстрация CLR Injection и загрузки в память через шелл-код, чтобы предоставить красным командам (red teamers) возможность эмулировать противников, а защитникам — основу для создания аналитики и мер защиты. Это неизбежно создаёт риск злоупотребления со стороны авторов вредоносного ПО и угроз. Однако мы считаем, что общая польза перевешивает риск. Надеемся, это верно. В случае, если продукты EDR или AV смогут обнаруживать Donut по сигнатурам или поведенческим шаблонам, мы не будем обновлять Donut для противодействия сигнатурам или методам обнаружения. Чтобы не обижаться, пожалуйста, не спрашивайте об этом.
| Ключ | Аргумент | Описание |
|---|---|---|
| -a | архитектура | Целевая архитектура для загрузчика: 1=x86, 2=amd64, 3=x86+amd64 (по умолчанию). |
| -b | уровень | Поведение при обходе AMSI/WLDP: 1=Нет, 2=Прервать при ошибке, 3=Продолжить при ошибке (по умолчанию). |
| -k | заголовки | Сохранить заголовки PE. 1=Перезаписать (по умолчанию), 2=Сохранить все. |
| -j | приманка | Необязательный путь к модулю-приманке для перегрузки модулей (Module Overloading). |
| -c | класс | Необязательное имя класса (требуется для .NET DLL). Может включать пространство имён: например, пространство_имён.класс. |
| -d | имя | Имя AppDomain для создания в .NET. Если включена энтропия, будет сгенерировано случайное. |
| -e | уровень | Уровень энтропии. 1=Нет, 2=Генерировать случайные имена, 3=Генерировать случайные имена + использовать симметричное шифрование (по умолчанию). |
| -f | формат | Формат вывода загрузчика, сохраняемого в файл. 1=Бинарный (по умолчанию), 2=Base64, 3=C, 4=Ruby, 5=Python, 6=PowerShell, 7=C#, 8=Hex. |
| -m | имя | Необязательный метод или функция для DLL (метод обязателен для .NET DLL). |
| -n | имя | Имя модуля для HTTP-стейджинга. Если включена энтропия, генерируется случайное. |
| -o | путь | Указывает, куда Donut должен сохранить загрузчик. По умолчанию "loader.bin" в текущем каталоге. |
| -p | параметры | Необязательные параметры/командная строка в кавычках для метода/функции DLL или EXE. |
| -r | версия | Версия среды выполнения CLR. Используется MetaHeader или v4.0.30319, если нет. |
| -s | сервер | URL HTTP-сервера, который будет хостить модуль Donut. Учётные данные могут быть указаны в следующем формате: https://имя_пользователя:пароль@192.168.0.1/ |
| -t | Запустить точку входа неуправляемого/нативного EXE как поток и ждать завершения потока. | |
| -w | Командная строка передаётся функции неуправляемой DLL в формате UNICODE (по умолчанию ANSI). | |
| -x | опция | Определяет, как загрузчик должен завершить работу. 1=Завершить поток (по умолчанию), 2=Завершить процесс, 3=Не завершать и не очищать, блокироваться бесконечно. |
| -y | адрес | Создаёт новый поток для загрузчика и продолжает выполнение по адресу, который является смещением относительно исполняемого файла хост-процесса. Предоставленное значение — это смещение. Эта опция поддерживает загрузчики, которые хотят возобновить выполнение хост-процесса после завершения donut. |
| -z | движок | Упаковать/сжать входной файл. 1=Нет, 2=aPLib, 3=LZNT1, 4=Xpress, 5=Xpress Huffman. В настоящее время последние три поддерживаются только в Windows. |
| Инструмент | Описание |
|---|---|
| DemoCreateProcess | Образец сборки .NET для использования в тестировании. Принимает два параметра командной строки, каждый из которых указывает программу для запуска. |
| DonutTest | Простой инжектор шелл-кода на C# для тестирования donut. Шелл-код должен быть закодирован в Base64 и вставлен как строка. |
| ModuleMonitor | Инструмент для подтверждения концепции (PoC), который обнаруживает внедрение CLR, как это делают такие инструменты, как Donut и execute-assembly от Cobalt Strike. |
| ProcessManager | Инструмент обнаружения процессов, который может использоваться оперативными (offensive) операторами для определения, во что внедряться, и защитными (defensive) операторами для определения, что выполняется, какие свойства имеют эти процессы, и загружен ли в них CLR. |