Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
FormatFuzzer — Шаблонно-управляемый фаззер бинарных форматов, который генерирует и разбирает корректные тестовые входные данные с высокой скоростью, с интеграцией AFL++ для фаззинга, управляемого покрытием. | Kitploit
Инструменты/GitHubGitHub/uds-se/formatfuzzer
ФаззингАнализ Бинарных Файлов
GitHubuds-se/formatfuzzer

FormatFuzzer

Шаблонно-управляемый фаззер бинарных форматов, который генерирует и разбирает корректные тестовые входные данные с высокой скоростью, с интеграцией AFL++ для фаззинга, управляемого покрытием.

РепозиторийСайт
446385 месяцев назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

FormatFuzzer

FormatFuzzer — это фреймворк для высокоэффективной и высококачественной генерации и разбора бинарных входных данных. Он принимает бинарный шаблон, описывающий формат бинарного ввода, и создает исполняемый файл, который производит и разбирает заданный бинарный формат. Например, из бинарного шаблона для GIF FormatFuzzer создает генератор GIF — также известный как фаззер GIF.

Создаваемые FormatFuzzer генераторы чрезвычайно эффективны: они производят тысячи корректных тестовых входных данных в секунду — в резком контрасте с мутационными фаззерами, где подавляющее большинство входных данных является недопустимым. Входные данные, генерируемые FormatFuzzer, не зависят от тестируемой программы (или вообще от любой программы), поэтому их можно использовать и в условиях black-box. Однако FormatFuzzer также интегрируется с AFL++ для создания корректных входных данных, которые также стремятся к максимальному покрытию. В наших экспериментах этот подход «лучшее из двух миров» превзошел все остальные конфигурации; подробности см. в нашей статье.

Бинарные шаблоны, используемые FormatFuzzer, взяты из 010 editor. Существует более 170 бинарных шаблонов, которые можно использовать напрямую для FormatFuzzer или адаптировать для его нужд. «Из коробки» FormatFuzzer поддерживает такие форматы, как AVI, BMP, GIF, JPG, MIDI, MP3, MP4, PCAP, PNG, WAV и ZIP; и мы еженедельно пополняем этот список.

Участники приветствуются! Посетите страницу проекта FormatFuzzer, чтобы оставить идеи и сообщить о проблемах или добавить pull request. Подробности о том, как работает FormatFuzzer и как он сравнивается с другими инструментами, читайте в нашей статье.

Получение

FormatFuzzer доступен на странице проекта FormatFuzzer. Вы можете скачать и распаковать последний релиз со страницы релизов.

Для самого последнего и самого лучшего вы также можете клонировать его git-репозиторий:

root@kitploit:~
git clone https://github.com/uds-se/FormatFuzzer.git

Все дальнейшие действия выполняются в его основной папке:

root@kitploit:~
cd FormatFuzzer

Предварительные требования

Для запуска FormatFuzzer необходимо следующее:

  • Python 3
  • Компилятор C++ с библиотеками GNU (в частности getopt_long()), такой как clang или gcc
  • Пакеты Python py010parser, six и intervaltree
  • Библиотека zlib (для функций сжатия)
  • Библиотека boost (для функций контрольных сумм)

Если вы планируете редактировать сценарии сборки и настройки (файлы .ac и .am), вам также понадобятся

  • GNU autoconf
  • GNU automake

Установка зависимостей в Linux (пакеты Debian, с использованием виртуального окружения python)

root@kitploit:~
sudo apt install git g++ make automake python3-full zlib1g-dev libboost-dev
python3 -m venv ~/fuzz
source ~/fuzz/bin/activate
pip3 install py010parser six intervaltree

Установка зависимостей на MacOS (с Xcode и Homebrew)

root@kitploit:~
xcode-select --install
brew install python3 automake boost
pip3 install py010parser six intervaltree

Установка только пакетов Python (все операционные системы)

На всех системах с помощью pip:

root@kitploit:~
pip install py010parser
pip install six
pip install intervaltree

Сборка

Примечание: все команды сборки требуют, чтобы вы находились в той же папке, где находится этот файл README. Сборка фаззера вне этой папки пока не поддерживается.

Способ 1: Использование скрипта build.sh

Существует скрипт build.sh, который автоматизирует все этапы построения. Просто выполните

root@kitploit:~
./build.sh gif

чтобы создать фаззер GIF.

Это работает для всех форматов файлов, предоставленных в templates/; если есть файл templates/FOO.bt, то ./build.sh FOO соберет фаззер.

Способ 2: Использование Make

Существует Makefile (исходник в Makefile.am), который автоматизирует все этапы построения. (Требуется GNU make.) Сначала выполните

root@kitploit:~
touch configure Makefile.in

затем

root@kitploit:~
./configure

и затем

root@kitploit:~
make gif-fuzzer

чтобы создать фаззер GIF.

Это работает для всех форматов файлов, предоставленных в templates/; если есть файл templates/FOO.bt, то make FOO-fuzzer соберет фаззер.

Способ 3: Ручные шаги

Если описанный выше метод make не работает или вы хотите больше контроля, возможно, вам придется действовать вручную.

Шаг 1: Компиляция бинарных шаблонов в код C++

Запустите компилятор ffcompile, чтобы скомпилировать бинарный шаблон в код C++. Он принимает два аргумента: файл .bt бинарного шаблона и файл .cpp, который будет сгенерирован.

root@kitploit:~
./ffcompile templates/gif.bt gif.cpp

Шаг 2: Компиляция кода C++

Используйте следующие команды для создания фаззера gif-fuzzer. Сначала скомпилируйте универсальный драйвер командной строки:

root@kitploit:~
g++ -c -I . -std=c++17 -g -O3 -Wall fuzzer.cpp

(-I . указывает расположение файла bt.h; -std=c++17 задает стандарт C++.)

Затем скомпилируйте парсер/генератор бинарного формата:

root@kitploit:~
g++ -c -I . -std=c++17 -g -O3 -Wall gif.cpp

Наконец, скомпонуйте парсер/генератор с драйвером командной строки, чтобы получить исполняемый файл. Если вы используете какие-либо дополнительные библиотеки (например, -lz), обязательно укажите их здесь.

root@kitploit:~
g++ -O3 gif.o fuzzer.o -o gif-fuzzer -lz

Запуск фаззера

FormatFuzzer может использоваться как самостоятельный парсер, генератор или мутатор конкретных форматов. Кроме того, он может вызываться универсальными фаззерами, такими как AFL++, для интеграции функций, специфичных для формата, в процесс фаззинга (см. раздел ниже об интеграции с AFL++).

Сгенерированный фаззер принимает команду в качестве первого аргумента, за которой следуют параметры и аргументы этой команды.

Самой важной командой является fuzz, предназначенная для создания выходных данных. Ее аргументами являются файлы, которые нужно сгенерировать в соответствующем формате.

Запустите генератор как

root@kitploit:~
./gif-fuzzer fuzz output.gif

чтобы создать случайный бинарный файл output.gif, или

root@kitploit:~
./gif-fuzzer fuzz out1.gif out2.gif out3.gif

чтобы создать три файла GIF: out1.gif, out2.gif и out3.gif.

Обратите внимание, что предоставленный нами шаблон gif.bt дополнен специальными функциями, упрощающими создание корректных файлов. Если вы используете оригинальные файлы .bt без адаптации, вы можете получить предупреждения во время генерации и создать некорректные файлы.

Запуск парсеров

Вы также можете запустить фаззер как парсер бинарных файлов, используя команду parse. Это полезно, если вы хотите проверить точность бинарного шаблона или если вы хотите мутировать входные данные (см. раздел «Файлы решений» ниже).

Чтобы запустить парсер, выполните

root@kitploit:~
./gif-fuzzer parse input.gif

Вы увидите сообщения об ошибках, если input.gif не может быть успешно разобран.

Файлы решений

Во время разбора вы также можете сохранить все решения, принимаемые при разборе (т.е. какие альтернативы разбора были выбраны) в файл решений. Это последовательность байтов, перечисляющая принятые решения. Каждый байт представляет собой одно решение о разборе. Значение байта 0 означает, что была выбрана первая альтернатива, значение 1 — вторая, и так далее.

Вы можете сгенерировать такой файл решений при разборе входного файла:

root@kitploit:~
./gif-fuzzer parse --decisions input.dec input.gif

Здесь input.dec сохраняет решения, принятые для разбора input.gif.

Вы также можете использовать такой файл решений при генерации входных данных. Фаззер тогда примет те же самые решения, которые были найдены во время разбора. Следующая команда создает новый файл GIF, используя решения, определенные при разборе input.gif:

root@kitploit:~
./gif-fuzzer fuzz --decisions input.dec input2.gif

Если все работает правильно, оба файла должны быть идентичны:

root@kitploit:~
cmp input.gif input2.gif

Мутируя файл решений (например, заменяя отдельные байты), вы можете создавать входные данные, которые похожи на исходный разобранный файл. Это полезно для взаимодействия с конкретными стратегиями тестирования и фаззерами, такими как AFL, где вы можете использовать gif-fuzzer и подобные программы в качестве трансляторов из файлов решений в бинарные файлы и обратно: AFL будет мутировать файлы решений, а тестируемая программа будет запускаться на преобразованных бинарных файлах. В отличие от прямой мутации бинарных файлов (как это обычно делает AFL), это преимущество всегда иметь корректные входные данные и, таким образом, гораздо быстрее продвигаться к покрытию.

Интеграция с AFL++

В дополнение к фаззерам, специфичным для форматов, таким как gif-fuzzer, FormatFuzzer также может быть скомпилирован в разделяемые библиотеки, специфичные для форматов, например, gif.so (для этого просто выполните ./build.sh gif или make gif.so). Эти разделяемые библиотеки могут загружаться универсальными фаззерами, такими как AFL++.

Чтобы запустить AFL++ с FormatFuzzer, просто следуйте инструкциям на нашей модифицированной версии AFL++. Мы поддерживаем различные стратегии фаззинга, в том числе:

  • AFL+FFMut: запускает AFL++ с использованием FormatFuzzer для предоставления умных мутаций, специфичных для формата.

  • AFL+FFGen: использует FormatFuzzer в качестве генератора, специфичного для формата, в то время как AFL++ мутирует его семена решений.

Создание и настройка бинарных шаблонов

Чтобы написать собственные бинарные шаблоны .bt (и, таким образом, создать высокоэффективный фаззер/парсер для этого формата), прочитайте раздел Introduction to Templates and Scripts из Руководства по 010 Editor.

Во многих случаях шаблон нужного вам формата (или похожий) уже может существовать. Загляните в коллекцию бинарных шаблонов редактора 010, чтобы узнать, есть ли что-то, что можно использовать или взять за основу.

Обратите внимание, что файлы .bt, предоставленные в репозитории, в целом ориентированы на разбор файлов. Их можно использовать и для генерации файлов, но часто не хватает точной информации о том, какие части ввода являются обязательными.

В этом разделе мы обсудим некоторые способы настройки файлов .bt для хорошей работы с FormatFuzzer.

Например, для формата GIF файл templates/gif-orig.bt показывает исходный бинарный шаблон, предназначенный только для разбора, а файл templates/gif.bt — это измененная версия, способная генерировать корректные GIF. Сравнивая два файла, мы видим, что для этого потребовалось внести небольшое количество изменений.

Если вы создали gif-fuzzer либо с помощью make gif-fuzzer, либо используя инструмент ffcompile, вы уже получили файл C++ gif.cpp, который содержит реализацию генератора и парсера GIF. Это полезно, чтобы увидеть, как внесенные вами изменения в бинарный шаблон транслируются в исполняемый код. Более подробно о коде C++ рассказывается в следующем разделе.

Бинарный шаблон GIF использует функции опережающего просмотра ReadUByte() и ReadUShort() для предварительного просмотра значений следующих байтов в файле перед их фактическим разбором в поле структуры. Во время генерации мы позволяем этим функциям принимать дополнительный аргумент, задающий набор хороших известных значений для выбора байтов, которые мы просматриваем. Кроме того, мы также позволяем задавать глобальный набор хороших известных значений, которые всегда будут использоваться при вызове конкретной функции опережающего просмотра, такой как ReadUByte(). Они хранятся в векторе ReadUByteInitValues.

По умолчанию наша процедура трансляции ffcompile пытается выявлять интересные значения, которые использовались в сравнениях с байтами опережающего просмотра, и использовать их в качестве глобального набора известных значений. При запуске

root@kitploit:~
./ffcompile templates/gif.bt gif.cpp

отображается сообщение, показывающее обнаруженные функции опережающего просмотра, а также добытые интересные значения:

root@kitploit:~
Finished creating cpp generator.

Lookahead functions found:

ReadUByte
ReadUShort

Mined interesting values:

GlobalColorTableFlag: ['1']
LocalColorTableFlag: ['1']
ReadUByte: ['0x3B', '0x2C']
ReadUShort: ['0xF921', '0xFE21', '0x0121', '0xFF21']
Signature: ['"GIF"']

Однако для генерации GIF лучше задавать набор хороших известных значений для ReadUByte() индивидуально при каждом вызове этой функции. Поэтому мы определяем пустой массив (размером 0)

root@kitploit:~
const local UBYTE ReadUByteInitValues[0];

чтобы переопределить набор глобальных ReadUByteInitValues, и для каждого вызова ReadUByte() мы используем дополнительный аргумент, чтобы указать набор хороших значений для данного конкретного места. Язык бинарных шаблонов также достаточно мощный, чтобы позволить выбирать этот набор на основе условий времени выполнения. Например, в следующем коде показано, как выбор подходящих значений для вызова ReadUByte() может зависеть от текущей версии GIF, которую мы генерируем. Версия GIF 89a допускает одно дополнительное возможное значение для байта (0x21).

root@kitploit:~
	if(GifHeader.Version == "89a")
		local UBYTE values[] = { 0x3B, 0x2C, 0x21 };
	else
		local UBYTE values[] = { 0x3B, 0x2C };

	while (ReadUByte(FTell(), values) != 0x3B) {
		...
	}

Остальные правки, необходимые для бинарного шаблона GIF, аналогичны. Например, для каждого поля структуры также можно указать набор известных хороших значений. Например, это задает корректные значения для поля Version: 87a и 89a.

root@kitploit:~
	char	Version[3] = { {"87a"}, {"89a"} };

Понимание сгенерированного кода C++

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

Код C++ создает класс для каждой struct и union, определенной в бинарном шаблоне, а также для встроенных типов, таких как int.

Во время конструирования, при инициализации переменной, мы можем определить набор хороших известных значений, которые может принимать эта переменная. Например, вызов конструктора

root@kitploit:~
char_array_class cname(cname_element, { "IHDR", "tEXt", "PLTE", "cHRM", "sRGB", "iEXt", "zEXt", "tIME", "pHYs", "bKGD", "sBIT", "sPLT", "acTL", "fcTL", "fdAT", "IHDR", "IEND" });

задает 17 хороших значений для переменной cname. Но этого часто недостаточно, поскольку выбор подходящего типа блока зависит от контекста. Поэтому мы также позволяем задавать набор хороших значений во время генерации при создании нового блока. Например, этот вызов может использоваться для создания экземпляра chunk для первого блока, который обязательно должен иметь тип IHDR.

root@kitploit:~
GENERATE(chunk, ::g->chunk.generate({ "IHDR" }, false));

При генерации второго блока мы можем использовать этот длинный список возможных блоков, которые могут находиться между блоком IHDR и блоком PLTE:

root@kitploit:~
GENERATE(chunk, ::g->chunk.generate({ "iCCP", "sRGB", "sBIT", "gAMA", "cHRM", "pHYs", "sPLT", "tIME", "zTXt", "tEXt", "iTXt", "eXIf", "oFFs", "pCAL", "sCAL", "acTL", "fcTL", "fdAT", "fRAc", "gIFg", "gIFt", "gIFx", "sTER" }, true));

Генератор затем равномерно выберет одно из хороших известных значений для использования в новом экземпляре. Мы также позволяем выбирать «злое» значение, не входящее в список хороших известных значений, с небольшой вероятностью 1/128. Эту функцию можно включать или отключать в любой момент с помощью метода set_evil_bit.

Все случайные выборы, выполняемые генератором, осуществляются путем вызова метода rand_int().

root@kitploit:~
long long rand_int(unsigned long long x, std::function<long long (unsigned char*)> parse);

При запуске программы в качестве генератора этот метод выбирает целое число от 0 до x-1, читая байты из случайного буфера. При запуске программы в качестве парсера этот метод использует функцию parse() для выяснения того, какие случайные байты должны присутствовать в случайном буфере, чтобы сгенерировать целевой файл, а затем записывает эти байты в случайный буфер. Функция parse получает в качестве аргумента буфер на текущей позиции файла и должна вернуть значение, которое должно быть возвращено текущим вызовом rand_int(), чтобы сгенерировать именно такую конфигурацию файла.

Авторы

FormatFuzzer был спроектирован и написан Рафаэлем Дутра <[email protected]>.

Концепция компилятора фаззера была предложена Рахулом Гопинатом <[email protected]> и Андреасом Целлером <[email protected]>.

Авторские права и лицензии

FormatFuzzer защищен авторским правом © 2020, 2021 Центра информационной безопасности CISPA имени Гельмгольца. Применяются следующие лицензии:

  • Код FormatFuzzer (в частности, весь код C++ и код, связанный с его генерацией) подчиняется GNU GENERAL PUBLIC LICENSE, как указано в COPYING.

  • В качестве исключения из вышесказанного, код C++, сгенерированный FormatFuzzer (т.е. фаззеры и парсеры для конкретных форматов) находится в общественном достоянии.

  • Исходный код pfp, на котором основан FormatFuzzer, распространяется по лицензии MIT, как указано в LICENSE-pfp.

Скачать инструмент