Для реверсера, пывнера и бинари ресерчера очень важно уметь фаззить, поэтому данные статьи посвященны новичкам, которые только начинают фаззить и знакомятся со зверьком - AFL++. Фаззинг (fuzzing) — техника тестирования программного обеспечения, часто автоматическая или полуавтоматическая, заключающаяся в передаче приложению на вход неправильных, неожиданных или случайных данных. Предметом интереса являются падения и зависания, нарушения внутренней логики и проверок в коде приложения, утечки памяти, вызванные такими данными на входе. Фаззинг является разновидностью выборочного тестирования, часто используемого для проверки проблем безопасности в программном обеспечении и компьютерных системах. (Wikipedia) Упражнение 1 - Xpdf В этом упражнении мы проведем фаззинг просмотрщика Xpdf PDF. Цель - найти сбой для CVE-2019-13288 в XPDF 3.02. Чему вы научитесь После выполнения этого упражнения вы будете знать основы фаззинга с помощью AFL, такие как: Компиляция целевого приложения с инструментарием Запуск фаззера (afl-fuzz) Выявление сбоев с помощью отладчика (GDB) Я предлагаю вам попробовать решить упражнение самостоятельно, не проверяя решение. Старайтесь изо всех сил, и только если вы застряли, посмотрите пример решения ниже. AFL использует недетерминированный алгоритм тестирования, поэтому две сессии фаззинга никогда не будут одинаковыми. Вот почему я настоятельно рекомендую установить фиксированное зерно (-s 123). Таким образом, ваши результаты фаззинга будут похожи на те, что показаны здесь, и это позволит вам легче выполнять упражнения. Если вы обнаружили новую уязвимость, пожалуйста, отправьте отчет о безопасности в проект. Если вам нужна помощь или у вас есть сомнения по поводу процесса, GitHub Security Lab  может помочь вам в этом :) Окружение Все упражнения были протестированы на Ubuntu 20.04.2 LTS. Я настоятельно рекомендую вам использовать ту же версию ОС, чтобы избежать различных результатов фаззинга, и запускать AFL++ на пустом оборудовании, а не на виртуальных машинах, для достижения наилучшей производительности. Загрузите и создайте свою цель Давайте сначала получим цель для фаззинга. Создайте новый каталог для проекта, который вы хотите запустить: Чтобы ваша среда была полностью готова, вам может понадобиться установить некоторые дополнительные инструменты (а именно make и gcc): Качаем Xpdf 3.02: Собираем Xpdf: Пришло время протестировать сборку. Прежде всего, вам нужно загрузить несколько примеров в формате PDF: Теперь мы можем протестировать двоичный файл pdfinfo: Первая половина это запуск тулзы, -box означает печать в ограниченых рамках страницы, -meta печать метаданных документа (XML). Вы должны увидеть что-то вроде этого: Установка AFL++ В этом курсе мы будем использовать последнюю версию фаззера AFL++. Вы можете установить все двумя способами: Локальная установка (рекомендуемый вариант) Docker-образ Локальная установка Установите зависимости: Проверка и сборка AFL++ : Docker-образ Устанавливаем докер: Скачайте образ: Запустите докер-контейнер AFLPlusPlus: а затем введите: Теперь, если все прошло хорошо, вы сможете запустить afl-fuzz. Просто введите afl-fuzz и вы должны увидеть что-то вроде этого: AFL - это фаззер, ориентированный на покрытие, что означает, что он собирает информацию о покрытии для каждого измененного входа, чтобы обнаружить новые пути выполнения и потенциальные ошибки. При наличии исходного кода AFL может использовать инструментарий, вставляя вызовы функций в начало каждого базового блока (функции, циклы и т.д.). Чтобы включить инструментарий для нашего целевого приложения, нам нужно скомпилировать код с помощью компиляторов AFL. Прежде всего, мы очистим все ранее скомпилированные объектные файлы и исполняемые файлы: А теперь мы собираем xpdf с помощью компилятора afl-clang-fast: configure находится в папке xpdf и от туда надо запускать соответсвенно Теперь вы можете запустить фаззер с помощью следующей команды: Краткое объяснение каждого флага: -i указывает каталог, куда мы должны поместить входные примеры (они же примеры файлов) -o указывает каталог, в котором AFL++ будет хранить мутировавшие файлы -s указывает статическое случайное зерно для использования @@ это командная строка цели, которую AFL будет подставлять в каждое имя входного файла Итак, в основном, фаззер будет запускаться  командой $HOME/fuzzing_xpdf/install/bin/pdftotext <input-file-name> $HOME/fuzzing_xpdf/output для каждого отдельного входного файла. Если вы получите сообщение типа "Hmm, your system is configured to send core dump notifications to an external utility...", просто сделайте это: Если же возникла ошибка как у меня "Whoops, your system uses on-demand CPU frequency scaling, adjusted between 1558 and 2338 MHz. Unfortunately, the scaling algorithm in the kernel is imperfect and can miss the short-lived processes spawned by afl-fuzz. To keep things moving, run these commands as root: ..." , то я решил эту проблему так: Через несколько минут вы должны увидеть что-то вроде этого: Вы можете увидеть значение "uniq. crashes" красным цветом, показывающее количество найденных уникальных аварий. Вы можете найти эти файлы аварий в папке $HOME/fuzzing_xpdf/out/ . Вы можете остановить фаззер после обнаружения первого сбоя, именно над ним мы и будем работать. В зависимости от производительности вашей машины может пройти до одного-двух часов, прежде чем вы получите сбой. На этом этапе вы уже научились: Как скомпилировать цель с помощью компилятора afl с инструментарием Как запустить afl++ Как обнаружить уникальные сбои вашей цели И что дальше? У нас нет никакой информации об этой ошибке, только крах программы... Пришло время для отладки и устранения! Задание Для того чтобы выполнить это упражнение, вам необходимо: Воспроизвести сбой с помощью указанного файла Отладить сбой, чтобы найти проблему Устранить проблему Решение Воспроизводим сбой Найдите файл, соответствующий краху, в файле, который находится по адресу $HOME/fuzzing_xpdf/out/ . Имя файла выглядит следующим образом id:000000,sig:11,src:001504+000002,time:924544,op:splice,rep:16  (ну или что-то в этом роде). Передайте этот файл в качестве входного файла  pdftotext : Это вызовет ошибку сегментации и приведет к аварийному завершению программы: Triage Используйте gdb для выяснения причин сбоя программы при таком вводе. Вы можете взглянуть на http://people.cs.pitt.edu/~mosse/gdb-note.html для хорошего краткого учебника по GDB. Прежде всего, вам нужно перестроить Xpdf с отладочной информацией, чтобы получить символическую трассировку стека: Сейчас можно запустить GDB: Теперь пишем внутри GDB run . Если все прошло успешно, вы должны увидеть следующий результат (или похожий): Затем введите bt, чтобы получить обратную трассировку (backtrace). Прокрутите стек вызовов и вы увидите множество вызовов метода "Parser::getObj", что, похоже, указывает на бесконечную рекурсию. Если вы перейдете на https://www.cvedetails.com/cve/CVE-2019-13288/, то увидите, что описание совпадает с бэктрейсом, который мы получили из GDB (в моем случае, другая уязвимость не та, которую предполагалось увидеть). Фиксим Последний шаг упражнения - исправление ошибки! Пересоберите цель после исправления и проверьте, что ваш сценарий использования больше не вызывает ошибку сегментации. Эта последняя часть оставлена в качестве упражнения для студента. В качестве альтернативы вы можете загрузить Xpdf 4.02, где ошибка уже исправлена, и проверить, что ошибка сегментации исчезла.