
Полиморфный шифратор, который преобразует shellcode, PE и COFF файлы в обфусцированные, позиционно-независимые полезные нагрузки с использованием шифрования RC4 и случайного блочного шифра, а также генерацию мусорных инструкций с помощью библиотеки AsmJit.
Представлено на
Shoggoth — это проект с открытым исходным кодом, основанный на C++ и библиотеке asmjit, используемый для полиморфного шифрования заданного шеллкода, PE и COFF файлов.
Shoggoth генерирует выходной файл, который хранит полезную нагрузку и соответствующий загрузчик в обфусцированной форме. Поскольку содержимое выходного файла является позиционно-независимым, оно может быть выполнено непосредственно как шеллкод. Во время выполнения полезной нагрузки она расшифровывает себя во время выполнения. В дополнение к процедуре шифрования, Shoggoth также добавляет мусорные инструкции, которые ничего не меняют, между процедурами.
Я начал разрабатывать этот проект для изучения различных подходов к динамической генерации инструкций, практики ассемблера и обнаружения сигнатур. Я планирую регулярно обновлять репозиторий новыми знаниями.
Текущие возможности перечислены ниже:
Общая схема выполнения Shoggoth для входного файла показана на изображении ниже. Вы можете наблюдать этот поток с конфигурациями по умолчанию.
В основном Shoggoth сначала объединяет предварительно скомпилированный шеллкод загрузчика в соответствии с выбранным режимом (файл COFF или PE) и входной файл. Затем он добавляет несколько мусорных инструкций, которые генерирует, к этой объединенной полезной нагрузке. Стеб, содержащий загрузчик, мусорные инструкции и полезную нагрузку, шифруется сначала с помощью RC4, а затем с помощью случайно сгенерированного блочного шифрования путем объединения соответствующих дешифраторов. Наконец, он добавляет мусорную инструкцию к результирующему блоку.
При случайной генерации инструкций для мусорных стебов или процедур шифрования Shoggoth использует библиотеку AsmJit.
AsmJit — это легковесная библиотека для генерации машинного кода, написанная на языке C++. Она может генерировать машинный код для архитектур X86, X86_64 и AArch64 и поддерживает базовые инструкции и все последние расширения. AsmJit позволяет задавать коды операций, регистры, непосредственные операнды, метки вызовов и встраивать произвольные значения в любое смещение внутри кода. При генерации некоторых ассемблерных инструкций с помощью AsmJit достаточно вызвать функцию API, которая соответствует требуемой операции ассемблера, с значениями операндов ассемблера из класса Assembler. Для каждого вызова API AsmJit хранит информацию о коде и перемещениях в своей внутренней структуре CodeHolder. После вызова функций API всех команд ассемблера, которые нужно сгенерировать, можно использовать его класс JitRuntime для копирования кода из CodeHolder в память с разрешением на выполнение и его перемещения.
Когда я искал библиотеку для генерации кода, я наткнулся на AsmJit и увидел, что она широко используется многими популярными проектами. Поэтому я решил использовать её для своих нужд. Я не знаю, является ли Shoggoth первым проектом, использующим её в контексте red team, но я считаю, что это может стать ориентиром для будущих реализаций.
Shoggoth можно использовать для шифрования заданных файлов PE и COFF, так что оба они могут быть выполнены как шеллкод благодаря предварительно скомпилированным позиционно-независимым загрузчикам. Я просто использовал метод C в шеллкод для получения PIC-версии известных загрузчиков PE и COFF, которые я модифицировал для своих старых проектов. Для компиляции я использовал Makefile из проекта HandleKatz, который представляет собой дампер LSASS в PIC-форме.
В основном, для получения шеллкода с помощью техники C в шеллкод, я удалил все глобальные переменные в исходном коде загрузчика, поместил все строки в стек и разрешил адреса функций Windows API, загружая и анализируя необходимые DLL во время выполнения. После этого я определил точку входа с помощью скрипта компоновщика и скомпилировал код с помощью MinGW с различными флагами компиляции. Я извлек секцию .text из полученного исполняемого файла и получил шеллкод загрузчика. Поскольку полученный после редактирования кода исполняемый файл не содержит других секций, кроме .text, код в этой секции может использоваться как позиционно-независимый.
Исходный код этих загрузчиков можно просмотреть и отредактировать в каталогах COFFLoader и PELoader. Скомпилированные версии этих исходных кодов можно найти в каталоге stub. На данный момент, если вы хотите отредактировать или изменить эти загрузчики, вы должны соблюдать сигнатуры и заменить предварительно скомпилированные бинарники из каталога stub.
Для передачи аргументов в BOF используйте опцию '--coff-arg'. Shoggoth ожидает предварительно отформатированную hex-строку, содержащую упакованные аргументы, которую можно создать с помощью скрипта TrustedSec's beacon_generate.py. Копия этого скрипта включена как COFFArgGenerator/beacon_generate.py. (Большое спасибо @Octoberfest7)
Shoggoth сначала использует один из потоковых шифров, алгоритм RC4, для шифрования полученной полезной нагрузки. После случайной генерации ключа, используемого здесь, он шифрует полезную нагрузку этим ключом. Стеб-дешифратор, который расшифровывает полезную нагрузку во время выполнения, динамически создается и собирается с помощью AsmJit. Регистры, используемые в стебе, случайным образом выбираются для каждого образца.
Я использовал код Nayuki как ссылку для реализации алгоритма RC4, который я применил в Shoggoth.
После выполнения первого шифрования Shoggoth использует второе шифрование, которое представляет собой случайно сгенерированный блочный шифр. С помощью второго шифрования он шифрует как дешифратор RC4, так и опционально стеб, содержащий полезную нагрузку, мусорные инструкции и загрузчик, зашифрованный с помощью RC4. Он делит шифруемый блок на 8-байтовые блоки и использует случайно сгенерированные инструкции для каждого блока. Эти инструкции включают ADD, SUB, XOR, NOT, NEG, INC, DEC, ROL и ROR. Операнды для этих инструкций также выбираются случайным образом.