
Полиморфный бинарный кодировщик для полезных нагрузок в сфере наступательной безопасности. Кодирует шеллкод с помощью цепи обратной связи на основе LFSR, внедрения мусорных инструкций и многоитерационной обфускации для обхода статического обнаружения.
SGN — это полиморфный бинарный энкодер для целей наступательной безопасности, например для создания статически необнаруживаемых бинарных полезных нагрузок. В нём используется аддитивный контур обратной связи для кодирования заданных бинарных инструкций, аналогичный LFSR. Этот проект является переработкой оригинального Shikata ga nai на Go со множеством улучшений.
[!WARNING]
Недавно проект был портирован на Rust. Эта версия сохраняет исходный дизайн и поведение, но заменяет текстовый ассемблер keystone на чисто Rust-ассемблерiced-x86, поэтому нет зависимостей от нативных библиотек — сборка выполняется обычной командойcargo build. Для устаревшей версии на Go смотрите ветку sgn-go.
Для сообщества наступательной безопасности оригинальная реализация энкодера Shikata ga nai считалась лучшим шеллкод-энкодером (до сих пор). Но с годами исследователи безопасности нашли несколько недостатков, позволяющих статически обнаруживать заглушку декодера (связанная работа — статья FireEye). Основной мотив этого проекта — создать более совершенный энкодер, который кодирует заданный бинарный файл до состояния полной неотличимости от случайных данных, делая невозможным обнаружение наличия декодера.
Finally properly encoded x64 shellcodes !LFSR key reduced to 1 byteDecoder stub is also encoded with a psudo random schemaStub decodes itself WITHOUT using any loop conditions !!Random garbage instruction generator added with keystoneNon of the registers are clobbered (optional preable, may reduce polimorphism)Каждый проход кодирования:
--plain, дополнительно шифрует саму заглушку случайным схемным шифром (XOR/ADD/SUB/ROL/ROR/NOT над DWORD) и добавляет в начало самолокализующийся декодер схемы, так что даже декодер выглядит как случайные данные;--enc раз с новыми seed-значениями;cargo install sgn
Также вы можете получить готовые скомпилированные бинарные файлы ЗДЕСЬ.
Использование
-h довольно понятен без объяснений, используйте -v, если хотите видеть, что происходит за кулисами ( ͡° ͜ʖ ͡°)_/¯
__ _ __ __ _
___ / / (_) /_____ _/ /____ _ ___ ____ _ ___ ___ _(_)
(_-</ _ \/ / '_/ _ `/ __/ _ `/ / _ `/ _ `/ / _ \/ _ `/ /
/___/_//_/_/_/\_\\_,_/\__/\_,_/ \_, /\_,_/ /_//_/\_,_/_/
========[Author:-Ege-Balcı-]====/___/=======v2.0.2=========
┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ (ノ ゜Д゜)ノ ︵ 仕方がない
sgn [OPTIONS]
Options:
-i, --input <INPUT> Input binary path
-o, --out <OUT> Encoded output binary name (default: <input>.sgn)
-a, --arch <ARCH> Binary architecture (32/64) [default: 64]
-c, --enc <ENC> Number of times to encode the binary [default: 1]
-M, --max <MAX> Maximum bytes per garbage block [default: 50]
--plain Do not encode the decoder stub
--ascii Generate a fully ASCII-printable payload (slow)
-S, --safe Preserve all register values (no clobber)
--badchars <BADCHARS> Avoid these bytes, hex format (e.g. \x00\x0a)
-v, --verbose Verbose mode
-h, --help Print help
-V, --version Print version
Пример:
sgn -i shellcode.bin -o encoded.bin -a 64 --badchars '\x00\x0a\x0d'
На изображении ниже показана базовая схема работы энкодера. Имейте в виду, что размеры, расположение и порядок мусорных инструкций, декодеров и декодеров схем будут меняться на каждой итерации.
Сам по себе LFSR довольно мощный с точки зрения пространства вероятностей. Для ещё большего полиморфизма в начало незакодированной полезной нагрузки добавляются мусорные инструкции. На изображении ниже показана сопровождающая матрица характеристического многочлена LFSR; если обозначить seed как вектор-столбец, она также показывает состояние регистра в конфигурации Фибоначчи через k шагов.
use sgn::Encoder;
let shellcode = std::fs::read("payload.bin")?;
let mut encoder = sgn::Encoder::new(64)?;
let encoded = encoder.encode(&shellcode)?;
println!("encoded {} bytes", encoded.len());
Смотрите examples/encode_binary.rs.
cargo test
Набор тестов включает модульные тесты шифрования round-trip, а также реальные тесты выполнения: закодированный x64 shellcode отображается в исполняемую память и выполняется в процессе, а x86 shellcode выполняется через вспомогательный стенд cc -m32 (автоматически пропускается, если 32-битный тулчейн отсутствует). Обе архитектуры проверяются в режимах plain, schema, multi-layer и safe-register, включая цикл случайных стресс-тестов.
iced-x86 вместо текстового ассемблера keystone; заглушки декодеров были переработаны вокруг RIP-относительной адресации (x64) и двухпроходной схемы call/pop (x86).random_byte теперь покрывает весь диапазон 0..=255, а бюджет размера мусорных данных (--max) теперь последовательно применяется как ограничение на блок.