
Фреймворк статического анализа, который выявляет цели для фаззинга в исходном коде и бинарных файлах, генерирует шаблоны обёрток и интегрируется с AFL++ и libFuzzer для автоматического обнаружения уязвимостей.
Фреймворк для автоматизации Fuzzable поиска целей с помощью статического анализа

Исследователи уязвимостей, проводящие оценку безопасности программного обеспечения, часто используют возможности фаззинга с покрытием кода с помощью мощных инструментов, таких как AFL++ и libFuzzer. Это важно, поскольку автоматизирует процесс поиска ошибок и быстро выявляет эксплуатируемые условия в целях. Однако при работе с большими и сложными кодовыми базами или закрытыми бинарными файлами исследователям приходится тратить время на ручной аудит и реверс-инжиниринг, чтобы определить функции, в которых может быть полезен фаззинг.
Fuzzable — это фреймворк, который интегрируется как с исходным кодом C/C++, так и с бинарными файлами, помогая исследователям уязвимостей выявлять функции-цели, пригодные для фаззинга. Это достигается применением нескольких эвристик на основе статического анализа, которые выявляют рискованное поведение в программном обеспечении и функции, его выполняющие. Затем исследователи могут использовать фреймворк для генерации базовых шаблонов обвязок, которые можно применять для поиска уязвимостей или интегрировать в конвейер непрерывного фаззинга, такой как проект Google oss-fuzz.
Помимо использования в качестве отдельного инструмента, Fuzzable также интегрирован в виде плагина для дизассемблера Binary Ninja; в настоящее время разрабатывается поддержка других бэкендов дизассемблирования.
Ознакомьтесь с оригинальной статьёй в блоге, подробно описывающей инструмент здесь; в ней освещены технические характеристики эвристик статического анализа и история создания этого инструмента. Этот инструмент также был представлен на Black Hat Arsenal USA 2022.
Некоторые бинарные цели могут требовать очистки (например, сопоставления сигнатур или идентификации функций после инлайнинга), поэтому fuzzable в первую очередь использует Binary Ninja в качестве бэкенда дизассемблирования из-за его способности эффективно решать эти задачи. Таким образом, его можно использовать как отдельный инструмент, так и плагин.
Поскольку Binary Ninja доступен не всем и может потребоваться для оценки безопасности и масштабирования в облаке, также поддерживается запасной бэкенд angr. В будущем планируется добавление других дизассемблеров (в первую очередь Ghidra).
Если у вас есть Binary Ninja Commercial, обязательно установите API для автономного использования:
$ python3 /Applications/Binary\ Ninja.app/Contents/Resources/scripts/install_api.py
Установка с помощью pip:
$ pip install fuzzable
Для управления зависимостями и сборки мы используем poetry. Чтобы выполнить ручную сборку, клонируйте репозиторий вместе со сторонними модулями:
$ git clone --recursive https://github.com/ex0dus-0x/fuzzable
Для ручной установки:
$ cd fuzzable/
# без poetry
$ pip install .
# с poetry
$ poetry install
# с poetry для виртуального окружения разработки
$ poetry shell
Теперь вы можете анализировать бинарные файлы и/или исходный код с помощью инструмента!
# анализ одной библиотеки в виде shared object
$ fuzzable analyze examples/binaries/libbasic.so
# анализ одного файла исходного кода на C
$ fuzzable analyze examples/source/libbasic.c
# анализ рабочей области с несколькими файлами C/C++ и заголовками
$ fuzzable analyze examples/source/source_bundle/
fuzzable можно легко установить через маркетплейс плагинов Binary Ninja, перейдя в Binary Ninja > Manage Plugins и выполнив поиск. Вот пример работы плагина fuzzable,
точно определяющего цели для фаззинга и дальнейшей оценки уязвимостей:

fuzzable предоставляет различные опции для более точной настройки анализа. В будущих планах и по запросам будет добавлена дополнительная поддержка.
Для определения пригодности к фаззингу fuzzable использует несколько эвристик, которые определяют наиболее жизнеспособные цели для динамического анализа. Все эти эвристики взвешены по-разному с помощью библиотеки scikit-criteria, которая использует многокритериальный анализ решений для выбора наилучших кандидатов. Эти метрики и их веса представлены ниже:
Как упоминалось, ознакомьтесь с технической статьёй в блоге для более глубокого понимания того, почему и как используются эти метрики.
Многие метрики были вдохновлены оригинальной работой Винченцо Иоццо по фаззингу с нулевым знанием.
Каждая анализируемая цель уникальна, и fuzzable не сможет учесть все граничные случаи поведения программы. Поэтому во время анализа может быть важно настроить эти веса соответствующим образом, чтобы увидеть, не дают ли другие результаты больше смысла для вашего сценария. Чтобы настроить веса в CLI, просто укажите аргумент --score-weights:
$ fuzzable analyze <ЦЕЛЬ> --score-weights=0.2,0.2,0.2,0.2,0.2
По умолчанию fuzzable фильтрует функции-цели по следующим критериям:
static и не доступные через заголовки.Чтобы увидеть вызовы, отфильтрованные fuzzable, установите флаг --list_ignored:
$ fuzzable analyze --list-ignored <ЦЕЛЬ>
В Binary Ninja эту настройку можно включить в Settings > Fuzzable > List Ignored Calls.
В случае, если fuzzable ошибочно отфильтровывает важные вызовы, которые следует анализировать, рекомендуется использовать аргументы --include-*, чтобы включить их во время выполнения:
# включить ВСЕ вызовы не верхнего уровня, которые были отфильтрованы
$ fuzzable analyze --include-nontop <ЦЕЛЬ>
# включить конкретные символы, которые были отфильтрованы
$ fuzzable analyze --include-sym <СИМВОЛ> <ЦЕЛЬ>
В Binary Ninja это поддерживается через Settings > Fuzzable > Include non-top level calls и Symbols to Exclude.
Теперь, когда вы нашли идеальных кандидатов для фаззинга, fuzzable также поможет сгенерировать обвязки для фаззинга, которые (почти) готовы к инструментированию и компиляции для использования с файловым фаззером (например, AFL++, Honggfuzz) или фаззером в памяти (libFuzzer). Для этого в CLI:
# сгенерировать обвязку из кандидата
$ fuzzable create-harness цель --symbol-name=some_unsafe_call
# внести минимальные и необходимые изменения в обвязку
$ vim target_some_unsafe_call_harness.cpp
# пример компиляции для AFL-QEMU (указано в комментариях сгенерированной обвязки)
$ clang target_some_unsafe_call_harness.cpp -no-pie -o target_some_unsafe_call_harness -ldl
# создать базовые сиды (в идеале они должны быть более хорошо сформированы для ввода)
$ mkdir in/
$ echo "seed" >> in/seed
# запустить фаззинг в чёрном ящике
$ afl-fuzz -Q -m none -i in/ -o out/ -- ./target_some_unsafe_call_harness
Если цель является кодовой базой исходного кода, будет использован шаблон для исходного кода.
Если цель — бинарный файл, будет использован общий шаблон для чёрного ящика, который в идеале можно применить с режимом эмуляции фаззинга, например AFL-QEMU. Копия бинарного файла также будет создана в виде shared object, если символ не экспортируется напрямую для dlopen с помощью LIEF.
На данный момент эта функция довольно примитивна: она просто создаёт автономную обвязку на C++ с соответствующими параметрами и не генерирует автоматически код, необходимый для поведения во время выполнения (например, создание и освобождение структур). Однако созданные для fuzzable шаблоны всё же должны помочь быстро приступить к работе. Вот некоторые амбициозные функции, которые я хотел бы реализовать в будущем:
fuzzable поддерживает генерацию отчётов в различных форматах. В настоящее время поддерживаются JSON, CSV и Markdown. Это может быть полезно, если вы используете этот инструмент в рамках автоматизации, где требуется получить вывод в сериализуемом формате.
В CLI просто передайте аргумент --export с именем файла с соответствующим расширением:
$ fuzzable analyze --export=report.json <ЦЕЛЬ>
В Binary Ninja перейдите в Plugins > Fuzzable > Export Fuzzability Report > ... и выберите формат, в который вы хотите экспортировать, и путь для записи.
Этот инструмент будет постоянно развиваться, и любая помощь внешних мейнтейнеров приветствуется!
Fuzzable распространяется под лицензией MIT.
| Эвристика | Описание | Вес |
|---|
| Имя, дружественное к фаззингу | Имя символа указывает на поведение, принимающее файловый/буферный ввод | 0.3 |
| Опасные стоки | Аргументы, попадающие в опасные вызовы (например, memcpy) | 0.3 |
| Естественные циклы | Количество циклов, обнаруженных с помощью границы доминирования | 0.05 |
| Цикломатическая сложность | Сложность функции-цели на основе рёбер и узлов | 0.05 |
| Глубина покрытия | Количество вызываемых функций, в которые углубляется цель | 0.3 |