Skip to content

Latest commit

 

History

History
552 lines (433 loc) · 48.3 KB

README.ru.md

File metadata and controls

552 lines (433 loc) · 48.3 KB

BugBane

🌍 English | Русский

Набор утилит для автоматизации фаззинг-тестирования.

Возможности

Цели BugBane:

  1. Упрощение пайплайна CI-фаззинга путём обобщения типичных этапов тестирования и стандартизации конечных артефактов.
  2. Выполнение фаззинга в эффективной конфигурации с учётом лучших практик.
  3. Генерация отчётных материалов в соответствии с реально выполняемыми действиями.

Возможности BugBane:

  1. Сборка приложений для фаззинг-тестирования, в том числе с санитайзерами и покрытием: AFL++, libFuzzer.
  2. Фаззинг сборок с использованием AFL++, libFuzzer (включая Atheris), dvyukov/go-fuzz, go test на заданном количестве ядер до заданного условия остановки.
  3. Синхронизация тестовых примеров между рабочей директорией фаззера и хранилищем. Включает отсеивание дубликатов и минимизацию на основе инструментов фаззера.
  4. Сбор покрытия тестируемого приложения на семплах, полученных в процессе фаззинг-тестирования, а также генерация HTML-отчётов о покрытии (lcov, go tool cover).
  5. Воспроизведение падений и зависаний, обнаруженных фаззером. Определение места возникновения ошибки и отсеивание дубликатов: C/C++, C#, Go, Python.
  6. Отправка сведений о воспроизводимых багах в систему управления уязвимостями: Defect Dojo.
  7. Получение скриншотов работы фаззера и главной страницы отчёта о покрытии исходного кода.
  8. Генерация отчётов на основе шаблонов Jinja2.

Утилиты BugBane связаны между собой, но использовать их вместе совсем не обязательно.

Установка

Зависимости

UNIX-подобная ОС
Python >= 3.6

Зависимости, используемые утилитами BugBane:
bb-build: компиляторы используемого фаззера в PATH (afl-g++-fast, clang, ...).
bb-corpus: утилита минимизации в соответствии с используемым фаззером в PATH (afl-cmin, ...).
bb-fuzz: используемый фаззер в PATH (afl-fuzz, go-fuzz, ...).
bb-coverage: используемые средства сбора покрытия в PATH (lcov, genhtml, go, ...).
bb-reproduce: утилита timeout, отладчик gdb.
bb-send: -.
bb-screenshot, bb-report: приложения ansifilter и pango-view в PATH, приложение geckodriver в PATH и браузер Firefox (необязательно, только для Selenium), шрифты mono (могут отсутствовать в базовых образах Docker).
Примечания:

  • скриншоты покрытия с Selenium выглядят лучше, чем с WeasyPrint, но требуют установку браузера Firefox и geckodriver;
  • скриншоты покрытия для Go требуют использовать Selenium, потому что Go встраивает в отчёты JavaScript;
  • для просмотра отчётов непосредственно в образе Docker с помощью утилит типа less может потребоваться установка локали с поддержкой UTF-8 и указание переменной LANG.

Установка и удаление пакета

Установить пакет можно локально с помощью pip:

git clone https://github.com/gardatech/bugbane
cd bugbane
pip install .[all]

Проверить выполнение тестов:

pytest
Дополнительные инструкции

Вместо "all" доступны другие группы, позволяющие установить только необходимые Python-зависимости:

Группа pip install Фаззинг* Заведение багов в Defect Dojo Отчёты и скриншоты Тестирование BugBane Разработка BugBane
- + - - - -
dd + + - - -
reporting + - + - -
test + - - + -
all + + + + -
dev + + + + +

* Выполнение сборок, фаззинг, работа с семплами, сбор покрытия и воспроизведение багов.

Таким образом, можно разделить тестирование и работу с его результатами на разные хосты worker и reporter:

pip install .                  # worker
pip install .[dd,reporting]    # reporter

Результат: на хосте worker не требуются зависимости для генерации отчётов, на хосте reporter не требуется окружение для запуска тестируемых приложений и фаззеров.

Для удаления использовать следующую команду:

pip uninstall bugbane

Запуск

Рекомендуется использовать BugBane в среде Docker.
Подразумевается последовательный запуск инструментов в определённом порядке, например:

  1. bb-build
  2. bb-corpus (import)
  3. bb-fuzz
  4. bb-coverage
  5. bb-reproduce
  6. bb-corpus (export)
  7. bb-send
  8. bb-report

При этом этап №1 является опциональным, покольку сборки могут быть выполнены другими способами, а этапы №7 и №8 могут выполняться в отдельном образе Docker или на отдельной машине.

Большинство инструментов BugBane работают с конфигурационным файлом bugbane.json: получают входные переменные, обновляют их значения и добавляют новые переменные в существующий файл конфигурации.

Пример исходного файла конфигурации, достаточного для последовательного запуска всех инструментов BugBane
{
    "fuzzing": {
        "os_name": "Arch Linux",
        "os_version": "Rolling",

        "product_name": "RE2",
        "product_version": "2022-02-01",
        "module_name": "BugBane RE2 Example",
        "application_name": "re2",

        "is_library": true,
        "is_open_source": true,
        "language": [
            "C++"
        ],
        "parse_format": [
            "RegExp"
        ],
        "tested_source_file": "re2_fuzzer.cc",
        "tested_source_function": "TestOneInput",


        "build_cmd": "./build.sh",
        "build_root": "./build",
        "tested_binary_path": "re2_fuzzer",
        "sanitizers": [
            "ASAN", "UBSAN"
        ],
        "builder_type": "AFL++LLVM",
        "fuzzer_type": "AFL++",

        "run_args": null,
        "run_env": null,
        "timeout": null,

        "fuzz_cores": 16
    }
}

Утилиты corpus, coverage, reproduce и report поддерживают альтернативный режим запуска (manual run mode), утилита screenshot работает только в этом режиме. Режим запуска manual предназначен для более тонкой настройки параметров или для использования отдельно от других инструментов BugBane.

bb-build

Создаёт сборки тестируемого приложения с использованием компиляторов фаззера.
Инструмент предназначен только для C/C++, цели go-fuzz и go-test не поддерживаются.

Пример запуска:

bb-build -i /src -o /fuzz

При этом директория /src должна содержать файл bugbane.json.
В результате в пути /fuzz появляются папки с полученными сборками, например: /fuzz/basic, /fuzz/asan, /fuzz/coverage. Также в папке /fuzz сохраняется журнал выполнения всех сборок с указанием команд запуска и использованных переменных окружения.

Подробности о работе bb-build

На вход инструменту подаются:

  1. Исходный код тестируемого приложения
  2. Команда или скрипт сборки
  3. Файл с переменными bugbane.json

В файле bugbane.json должны быть заданы переменные: builder_type, build_cmd, build_root, sanitizers.

Команда, указанная в переменной build_cmd, должна учитывать значения переменных окружения CC, CXX, LD, CFLAGS, CXXFLAGS, LDFLAGS и при запуске выполнять сборку тестируемого компонента в режиме фаззинг-тестирования. После выполнения одного запуска команды build_cmd в папке build_root должна оказаться сборка тестируемого приложения. Переменная sanitizers должна содержать список санитайзеров, с которыми требуется выполнить сборки. Для каждого санитайзера BugBane выполняет отдельную сборку.

Приложение последовательно выполняет несколько сборок (с различными санитайзерами + для сбора покрытия + дополнительные сборки для фаззинга) и после каждой сборки сохраняет результаты сборки из папки build_root в папку, указанную аргументом запуска -o. При этом обновляются некоторые переменные в файле bugbane.json (в частности, sanitizers - заполняется названиями санитайзеров, для которых удалось выполнить сборку).

Пример скрипта, путь к которому может быть указан в команде сборки build_cmd:

#!/bin/bash
set -x

export CXX="${CXX:-afl-clang-fast++}"

rm -rf build
mkdir -p build
test -e Makefile && make clean

make -j obj/libre2.a
$CXX $CXXFLAGS --std=c++11 -I. re2/fuzzing/re2_fuzzer.cc /AFLplusplus/libAFLDriver.a obj/libre2.a -lpthread -o build/re2_fuzzer

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

Соответствие сборок и папок

В таблице показано, в какие папки инструмент bb-build сохраняет результаты сборки
Имя папки Описание builder_type
basic Сборка для фаззинга. Это должна быть наиболее производительная сборка: без санитайзеров, без покрытия AFL++GCC, AFL++GCC-PLUGIN, AFL++LLVM, AFL++LLVM-LTO, libFuzzer
gofuzz Сборка для фаззинга с использованием dvyukov/go-fuzz (zip-архив). Не поддерживается bb-build, поддерживается остальными утилитами -
gotest Сборка для фаззинга, скомпилированная с помощью go test. Не поддерживается bb-build, поддерживается остальными утилитами -
laf Сборка для фаззинга, скомпилированная с переменной окружения AFL_LLVM_LAF_ALL AFL++LLVM, AFL++LLVM-LTO
cmplog Сборка для фаззинга, скомпилированная с переменной окружения AFL_USE_CMPLOG AFL++LLVM, AFL++LLVM-LTO
asan Сборка для фаззинга с адресным санитайзером (Address Sanitizer) AFL++GCC, AFL++GCC-PLUGIN, AFL++LLVM, AFL++LLVM-LTO, libFuzzer
ubsan Сборка для фаззинга с санитайзером неопределённого поведения (Undefined Behavior Sanitizer) AFL++GCC, AFL++GCC-PLUGIN, AFL++LLVM, AFL++LLVM-LTO, libFuzzer
cfisan Сборка для фаззинга с санитайзером целостности потока выполнения (Control Flow Integrity Sanitizer) AFL++GCC, AFL++GCC-PLUGIN, AFL++LLVM, AFL++LLVM-LTO, libFuzzer
tsan * Сборка для фаззинга с санитайзером потоков (Thread Sanitizer) AFL++GCC, AFL++GCC-PLUGIN, AFL++LLVM, AFL++LLVM-LTO, libFuzzer
lsan * Сборка для фаззинга с санитайзером утечек памяти (Leak Sanitizer). Этот функционал поддерживается адресным санитайзером, но также может использоваться отдельно AFL++GCC, AFL++GCC-PLUGIN, AFL++LLVM, AFL++LLVM-LTO, libFuzzer
msan * Сборка для фаззинга с санитайзером памяти (Memory Sanitizer) AFL++GCC, AFL++GCC-PLUGIN, AFL++LLVM, AFL++LLVM-LTO, libFuzzer
coverage Сборка для получения информации о покрытии AFL++GCC, AFL++GCC-PLUGIN, AFL++LLVM, AFL++LLVM-LTO, libFuzzer

* Работоспособность не тестировалась.

Выполнение сборок без инструмента bb-build

Не всегда удобно выполнять сборки с помощью bb-build, например, если сборками и фаззингом занимаются разные люди. Также bb-build не поддерживает автоматические сборки для целей на языке Go.

Далее следуют инструкции, позволяющие обеспечить совместимость собственных сборок и утилит BugBane.

C/C++

Все сборки рекомендуется выполнять компиляторами фаззера, в том числе сборку для получения информации о покрытии.
Все сборки должны выполняться с отладочной информацией, содержащей сведения о строках исходного кода (-g для gcc, -g или -gline-tables-only - для clang).
Все сборки должны выполняться с флагом -fno-omit-frame-pointer для получения более точных стеков вызовов в случае обнаружения багов или при ручной отладке.
Если компиляторы фаззера поддерживают переменные окружения для включения санитайзеров (AFL_USE_ASAN и т.д.), то использование этих переменных предпочтительнее ручного указания флагов компиляции.
Сборки следует размещать в папках под соответствующими названиями. Например, если фаззинг запускается из директории /fuzz, то сборка с ASAN должна быть сохранена в папке /fuzz/asan. Сборку, в которой одновременно присутствуют несколько санитайзеров, достаточно разместить в одном экземпляре в любой одной папке для сборки с санитайзером. Например, сборку с ASAN+UBSAN+CFISAN можно разместить в любой из папок: asan, ubsan, cfisan, lsan, tsan или msan - это не снизит эффективность фаззинга и воспроизведения падений. При этом рекомендуется создать несколько копий или символьных ссылок в соответствии с санитайзерами (/fuzz/asan, /fuzz/ubsan, ...).
Если процесс сборки в CI занимает время, сопоставимое с временем фаззинг-тестирования, то можно обойтись единственной сборкой, одновременно включающей инструментацию фаззера, покрытия и санитайзеров. Это негативно скажется на скорости фаззинга, а также создаст дополнительную нагрузку на диск в процессе тестирования, но может быть предпочтительнее выполнения нескольких сборок. Чтобы использовать единственную сборку приложения, скомпилированную одновременно с ASAN и с покрытием, её можно разместить в папке /fuzz/asan, а затем скопировать её (или создать символьную ссылку) в путь /fuzz/coverage.

Go

dvyukov/go-fuzz

Перейти в папку тестируемого проекта и выполнить:

go-fuzz-build

Дополнительная информация доступна на странице проекта.

go test

Следующие инструкции относятся ко встроенному фаззеру, появившемуся с выходом go1.18.
Перейти в папку проекта и выполнить:

go test . -fuzz=FuzzMyFunc -o fuzz -c -cover

Вместо FuzzMyFunc следует подставить название любого фаззинг-теста, присутствующего в кодовой базе. Название функции обязано начинаться с "Fuzz" (см. документацию фаззера).
В результате получится исполняемый файл fuzz с возможностью запуска любого из доступных фаззинг-тестов. Например, если в коде есть тесты FuzzHttp и FuzzJson, то можно выполнить сборку с опцией -fuzz=FuzzHttp, а в результате можно будет запускать фаззинг как с опцией -test.fuzz=FuzzHttp, так и с -test.fuzz=FuzzJson.
Опция сборки -cover пока не даёт никакого эффекта, поскольку фаззинг и покрытие в Go временно несовместимы. Использование опции необязательно, но позволит не вносить изменения в будущем, когда разработчики Go вернут совместимость фаззинга и покрытия.

bb-corpus

Синхронизирует тестовые примеры в рабочей директории фаззера с хранилищем.

Пример импорта входных тестовых примеров перед фаззинг-тестированием:

bb-corpus suite /fuzz import-from /storage

Папка /fuzz в данном случае является рабочей директорией фаззера (содержит bugbane.json), папка /storage - директория хранилища, в которой присутствует папка samples. Папка /storage/samples содержит файлы тестовых примеров.

После фаззинг-тестирования следует добавить новые тестовые примеры в хранилище:

bb-corpus suite /fuzz export-to /storage
Поддержка встроенного фаззера Go (go test) ограничена

Экспорт в хранилище функционирует нормально, а для импорта придётся использовать один из следующих вариантов:

  • использовать bb-corpus manual и указать выходной директорией папку конкретного фаззинг-теста (out/FuzzXxx)
  • использовать bb-corpus suite, но предварительно определить переменную fuzz_in_dir в конфигурационном файле (как в примере выше: out/FuzzXxx)
  • копировать семплы другими средствами (rsync, cp)
Подробности о работе bb-corpus

Инструмент поддерживает импорт тестовых примеров из хранилища в папку фаззера и экспорт из папки фаззера в хранилище.
Хранилище является примонтированной папкой и в свою очередь может быть каталогом Samba, NFS и т.д.

Синхронизация происходит в два этапа:

  1. Копирование (в случае импорта) или перемещение (в случае экспорта) из папки-источника во временную папку без создания дубликатов по содержимому (вычисляются хэш-суммы SHA1).
  2. Минимизация семплов из временной папки в конечную папку с использованием инструментов фаззера (например, afl-cmin).

В конфигурационном файле bugbane.json должна быть объявлена переменная fuzzer_type.
Для минимизации с использованием afl-cmin на диске должны присутствовать сборки тестируемого приложения. Наиболее предпочтительной сборкой для минимизации семплов является сборка в папке laf, т.к. она "различает" больше путей выполнения, но, если она отсутствует, то для минимизации используются другие сборки.

Имена результирующих файлов соответствуют хэш-сумме SHA1 их содержимого. При совпадении имён в конечной папке перезапись не происходит.

bb-fuzz

Запускает фаззинг тестируемого приложения на указанном количестве ядер, останавливает фаззинг при наступлении указанного условия остановки.

Пример запуска:

FUZZ_DURATION=1800 bb-fuzz --max-cpus $(nproc) suite /fuzz

В результате запускаются несколько экземпляров фаззера в сессии tmux.
Инструмент bb-fuzz будет периодически печатать статистику работы фаззера, пока не обнаружит наступление условия остановки, в данном случае, пока не накопится время работы 1800 секунд (30 минут).
Затем в папку /fuzz/screens будут сохранены дампы (текстовые представления) экранов фаззера. Эти дампы используются на следующих этапах приложениями bb-report или bb-screenshot для создания скриншотов.

Подробности о работе bb-fuzz

Инструмент обнаруживает сборки приложения на диске и распределяет их по разным ядрам процессора.
Алгоритм распределения сборок C/C++:

  • сборкам с санитайзерами выделяется по одному ядру;
  • вспомогательные сборки (AFL_LLVM_LAF_ALL, AFL_USE_CMPLOG) назначаются на определённую долю от доступных ядер;
  • сборка basic (без санитайзеров) занимает остальные ядра;
  • сборки для определения покрытия исходного кода в фаззинг-тестировании участие не принимают (см. bb-coverage).

Для Go используется единственная сборка (в папке gofuzz или gotest), которая назначается на все доступные ядра.
Для встроенного фаззера go test работа bb-fuzz завершается сразу же, как только будет обнаружен первый баг. Это вызвано особенностями работы фаззера. В случае отсутствия обнаруженных багов работа продолжается до наступления условия остановки.

В конфигурационном файле bugbane.json должны быть определены переменные fuzzer_type, tested_binary_path, fuzz_cores, src_root, run_args, run_env и timeout. Переменная timeout указывается в миллисекундах.
На диске должны присутствовать сборки приложения, размещённые в папках, соответствующих названию сборки, точно так же, как их размещает инструмент bb-build. Также на диске могут присутствовать файлы словарей с расширением ".dict" в папке "dictionaries". Они объединяются в один общий словарь, который передаётся фаззеру при условии поддержки со стороны фаззера.

Доступные значения переменной fuzzer_type: AFL++, libFuzzer, go-fuzz, go-test. Для фаззинга с помощью SharpFuzz следует указывать значение AFL++, для Atheris - libFuzzer.
Переменная tested_binary_path содержит путь к тестируемому приложению относительно входной папки (где будет осуществлён поиск сборок). Пример: есть папка "build" с результатом сборки, исполняемый файл "app" сохранён по пути build/test/app, инструмент bb-build последовательно выполнил несколько сборок, каждый раз копируя папку "build" в путь /fuzz, т.е. получились пути /fuzz/basic/test/app, /fuzz/coverage/test/app и т.д. В этом случае переменная tested_binary_path должна равняться "test/app". Для Atheris tested_binary_path должна содержать имя исполняемого Python-скрипта, в начале которого присутствует shebang интерпретатора Python (строка запуска интерпретатора, такая как #!/usr/bin/env python3).
Переменная src_root не используется напрямую, но без её указания потерпят неудачу утилиты, подлежащие запуску после bb-fuzz.
run_args - строка с аргументами запуска тестируемого приложения. Переменная может включать последовательность "@@", вместо которой фаззер может подставлять тестовые примеры на вход тестируемой программе.
Для встроенного фаззера Go переменная run_args обязана содержать опцию запуска -test.fuzz с указанием конкретного фаззинг-теста, например, -test.fuzz=FuzzHttp.
run_env - переменные окружения, которые необходимо установить для запуска тестируемого приложения. Переменная LD_PRELOAD будет автоматически заменена на соответствующую переменную фаззера (например, AFL_PRELOAD для AFL++).
Пример переменной run_env в конфигурационном файле:

"run_env": {
    "LD_PRELOAD": "/src/mylib.so",
    "ENABLE_FUZZ_TARGETS": "1"
}

Доступные условия остановки фаззинг-тестирования:

  • реальная продолжительность фаззинга достигла X секунд (затраченное время независимо от количества ядер / экземпляров фаззера);
  • новые пути выполнения кода не обнаруживались в течение последних X секунд среди всех экземпляров фаззера.

Условие остановки задаётся с помощью переменных окружения:

  • CERT_FUZZ_DURATION=X - X определяет количество секунд, в течение которых не должны обнаруживаться новые пути выполнения; переменная имеет наивысший приоритет, если установлены другие переменные;
  • CERT_FUZZ_LEVEL=X - X определяет уровень контроля, что в свою очередь определяет время, в течение которого не должны обнаруживаться новые пути выполнения; допустимые значения X: 2, 3, 4; средний приоритет;
  • FUZZ_DURATION=X - X определяет реальную продолжительность тестирования; низший приоритет.

Переменные CERT_FUZZ_* подходят для сертификационных испытаний, FUZZ_* - для использования в CI/CD.
Если не объявлена ни одна из указанных переменных, используется FUZZ_DURATION=600.

Количество используемых ядер процессора определяется минимальным значением среди перечисленных:

  1. Количество доступных в системе ядер.
  2. Значение переменной fuzz_cores в файле конфигурации. Если значение не указано, будет выбрано 8 ядер.
  3. Аргумент запуска --max-cpus (значение по умолчанию: 16).

Таким образом, ограничение на количество ядер накладывает как автор конфигурационного файла (предположительно, разработчик тестируемого ПО), так и конечный пользователь bb-fuzz (предположительно, команда AppSec).

bb-coverage

Собирает покрытие тестируемого приложения на семплах, сгенерированных фаззером.

Пример запуска:

bb-coverage suite /fuzz

В результате в папке /fuzz/coverage_report появляются файлы отчёта о покрытии, в том числе /fuzz/coverage_report/index.html - главная страница отчёта.
Инструмент не работает для встроенного фаззера Go (go test). Это вызвано особенностями работы фаззера.
Также не реализован сбор покрытия с фаззинг-целей Python.

Подробности о работе bb-coverage

Работа инструмента для C/C++-приложений:

  1. Запускает тестируемое приложение на семплах в директории синхронизации фаззера
  2. Строит отчёт о покрытии

Для приложений на языке Go инструмент работает иначе:

  1. Строит отчёт о покрытии с использованием данных, полученных при фаззинге с ключом запуска -dumpcover *
  2. Изменяет цвет фона в отчёте о покрытии с чёрного на белый

* Инструмент bb-fuzz использует этот ключ.

В конфигурационном файле bugbane.json должны быть объявлены переменные tested_binary_path, run_args, run_env, coverage_type, fuzzer_type, fuzz_sync_dir и src_root.
Переменная coverage_type заполняется приложением bb-build и соответствует использованному сборщику.
src_root - путь к исходному коду тестируемого приложения на момент выполнения сборок; путь не обязан реально существовать в файловой системе: если директория не существует, отчёт о покрытии будет содержать проценты, но не исходный код.

Возможные значения coverage_type

coverage_type Описание
lcov Для целей, собранных компиляторами GCC с флагом --coverage
lcov-llvm Для целей, собранных компиляторами LLVM с флагом --coverage
go-tool-cover Для целей на языке Go

bb-reproduce

Воспроизводит обнаруженные фаззером падения и зависания и обобщает результаты работы фаззера.

Пример запуска:

bb-reproduce suite /fuzz

В результате формируется файл /fuzz/bb_results.json, содержащий статистику работы фаззера и сведения о воспроизводимых багах. Семплы, соответствующие воспроизводимым багам, сохраняются в папке /fuzz/bug_samples.

Подробности о работе bb-reproduce

Инструмент bb-reproduce выполняет следующие действия:

  1. Получает общую статистику работы фаззеров
  2. Минимизирует падения и зависания путём их воспроизведения
  3. Составляет информацию о каждом уникальном воспроизводимом баге
  4. Формирует JSON-файл со статистикой и данными о багах
  5. Сохраняет на диск тестовые примеры, приводящие к воспроизводимым падениям и зависаниям

Для каждого бага сохраняются такие сведения как заголовок issue/бага, место возникновения бага в исходном коде, команда запуска с конкретным семплом, вывод приложения (stdout+stderr), переменные окружения и т.д.
Поддерживаются цели, инструментированные с помощью SharpFuzz.

В конфигурационном файле bugbane.json должны быть определены переменные src_root, fuzz_sync_dir, fuzzer_type, reproduce_specs, run_args и run_env. Переменные fuzz_sync_dir и reproduce_specs добавляются инструментом bb-fuzz.
fuzz_sync_dir - директория синхронизации фаззера; bb-fuzz использует директорию "out".
src_root - путь к исходному коду тестируемого приложения на момент выполнения сборок; не обязан реально существовать в файловой системе, используется для более точного определения места падений/зависаний в исходном коде.
reproduce_specs - словарь, определяющий тип фаззера, и задающий соответствие между сборками приложения и папками, на которых требуется выполнить воспроизведение:

"fuzz_sync_dir": "/fuzz/out",
"reproduce_specs": {
    "AFL++": {
        "/fuzz/basic/app": [
            "test1"
        ],
        "/fuzz/ubsan/app": [
            "test2",
            "test3"
        ]
    }
}

В данном случае сборка basic (/fuzz/basic/app) будет запущена на семплах /fuzz/out/test1/{crashes,hangs}/id*, а сборка ubsan (/fuzz/ubsan/app) - на семплах /fuzz/out/test{2,3}/{crashes,hangs}/id*.

При каждом запуске анализируется вывод приложения в терминал, например, инструмент ищет сообщения санитайзеров. Каждый баг воспроизводится до успешного воспроизведения, но не более N раз. Число N определяется аргументом запуска bb-reproduce --num-reruns (значение по умолчанию: 3). Если при воспроизведении падения не обнаруживается стек вызовов, приложение запускается под отладчиком gdb. Зависания воспроизводятся сразу под отладчиком gdb.

Просмотр информации о багах

Информацию о найденных багах можно вывести в терминал с использованием утилиты jq (устанавливается отдельно).
Это позволяет просматривать и заводить баги вручную, например, если не используется система Defect Dojo или утилита bb-send.

Простой текстовый формат для удобного просмотра в терминале:

jq '.issue_cards[] | "-" * 79, .title, .reproduce_cmd, .output, "Saved sample name", .sample, ""' -rM bb_results.json

Готовое описание issue для GitHub:

jq '.issue_cards[] | "## \(.title)", "Originally reproduced by executing: \n```shell\n\(.reproduce_cmd)\n```", "Output:\n```\n\(.output)```", "Saved sample name: \(.sample)", ""' -rM bb_results.json

Готовое описание issue для Jira:

jq '.issue_cards[] | "h1. \(.title)", "Originally reproduced by executing: \n{noformat}\n\(.reproduce_cmd)\n{noformat}", "Output:\n{noformat}\n\(.output){noformat}", "Saved sample name: \(.sample)", ""' -rM bb_results.json

Рекомендуется заводить issue на каждый отдельный баг, поскольку баги уже прошли дедупликацию с помощью bb-reproduce и с высокой долей вероятности являются уникальными.
Если предпочтительнее создавать одно issue на все обнаруженные баги, то к нему достаточно приложить архив с директорией bug_samples.

bb-send

Заводит воспроизводимые баги в системе управления уязвимостями Defect Dojo.
Входные данные берутся из файла bb_results.json, полученного в результате работы инструмента bb-reproduce.
Файл bugbane.json не используется.

Пример запуска:

export BB_DEFECT_DOJO_SECRET="DD_TOKEN"
bb-send --host https://dojo.local \
    --user-name ci_fuzz_user --user-id 2 \
    --engagement 1 --test-type 141 \
    --results-file bb_results.json

В результате на сервере Defect Dojo по адресу https://dojo.local будет создан новый тест с типом 141 в engagement 1. Каждый баг будет заведён отдельно в пределах нового теста.

Описание некоторых аргументов запуска bb-send

Здесь и далее в качестве адреса сервера Defect Dojo используется https://dojo.local.
--user-id: id указанного в --user-name пользователя; можно посмотреть в адресной строке Defect Dojo, выбрав нужного пользователя на странице https://dojo.local/user.
--engagement: engagement id; также можно посмотреть в адресной строке в браузере (выбрать нужный engagement на странице https://dojo.local/engagement).
--test-type: id вида теста; брать также из адресной строки (выбрать нужный тест на странице https://dojo.local/test_type).
--token: ключ API; берётся из Defect Dojo по ссылке: https://dojo.local/api/key-v2 (нужно быть авторизованным от имени, указанного в --user-name, ключ нужен из раздела "Your current API key is ....").
Рекомендуется вместо опций --user-name и --token использовать переменные окружения BB_DEFECT_DOJO_LOGIN и BB_DEFECT_DOJO_SECRET.

Если подлинность сертификата сервера Defect Dojo не может быть проверена, то следует добавить аргумент запуска --no-ssl.

bb-report

Создаёт отчёт о выполненном фаззинг-тестировании в формате Markdown на основе указанного шаблона Jinja2.
По умолчанию используется шаблон с описанием процесса фаззинга на русском языке и включает команды, использованные для запуска фаззеров, скриншоты фаззеров, статистику работы и т.д.

Инструмент создаёт скриншоты:

  1. Окон фаззера - из дампов tmux, сохранённых инструментом bb-fuzz
  2. Главной страницы отчёта о покрытии кода, созданного инструментов bb-coverage

Скриншоты сохраняются в папку screenshots и вставляются в отчёт в виде ссылок.
В файле конфигурации bugbane.json должны быть объявлены переменные fuzzer_type, coverage_type и fuzz_sync_dir.

Пример запуска:

bb-report --name myapp_fuzz suite /fuzz

Запуск с использованием Selenium:

bb-report --html-screener selenium --name myapp_fuzz suite /fuzz

В результате в папке /fuzz появляется директория screenshots с изображениями и файл с отчётом myapp_fuzz.md.

Для создания документа в формате DOCX можно использовать утилиту pandoc (устанавливается отдельно):

pandoc -f markdown -t docx myapp_fuzz.md -o myapp_fuzz.docx

bb-screenshot

Создаёт скриншоты из указанных пользователем HTML-файлов, текстовых файлов, а также из файлов, содержащих ANSI-последовательности. Изображения создаются так же, как в приложении bb-report, но пользователь может указать имена входного и выходного файлов.

Примеры запуска:

bb-screenshot -S pango -i tmux_dump.txt -o tmux_screenshot.png
bb-screenshot -S weasyprint -i index.html -o coverage.png
bb-screenshot -S selenium -i index.html -o coverage2.png

Развитие

Планы по улучшению BugBane:

  • поддержка других фаззеров
  • добавление других утилит
  • генерация отчётов в других форматах и по другим шаблонам

Для разработчиков

Установка в режиме editable в виртуальное окружение:

python -m venv .venv
. .venv/bin/activate
pip install -e .[dev]

Запуск юнит-тестов pytest:

pytest

Благодарности

Спасибо всем участникам проекта!

Отдельные благодарности: