Фа́ззинг (англ. fuzzing или англ. fuzz testing, буквально «испытание пушинками/волосинками»), также тестирование мусорными данными — техника тестирования компонентов веб приложения, часто автоматическая или полуавтоматическая, заключающаяся в передаче приложению на вход неправильных, неожиданных или случайных данных.
Цель фаззинга:
Предметом интереса являются падения и зависания, нарушения внутренней логики и проверок в коде приложения, утечки памяти, вызванные такими данными на входе. Фаззинг является разновидностью выборочного тестирования (random testing), часто используемого для проверки проблем безопасности в программном обеспечении и компьютерных системах.
Как он работает?
Когда мы начинаем работать с фаззером для очередного веб приложения, нам нужно разобраться со следующими вопросами:
Мы генерируем случайные данные, передаем их на вход программе и проверяем, не сломалась ли она. Если не сломалась — генерируем новый ввод. Если сломалась — прекрасно, мы нашли баг. Предполагается, что программа не должна падать от неожиданного ввода, она должна этот ввод корректно обрабатывать.
Когда мы начинаем работать с фаззером для очередного веб приложения, нам нужно разобраться со следующими вопросами:
- Как собрать конечные точки и параметры? Данный пункт является основным, так как от того, на сколько объёмную поверхность атаки мы сможем занять зависит успех фаззинга. Необходимо собрать как можно больше точек входа в приложение.
- Что служит входными данными? Для XML-парсера входные данные — XML-файлы. А, например, для обычных форм можно грузить нагрузки как по формату, так и различные инъекции, HTML/JS код, специальные символы и тому подобное.
- Как входные данные программе передавать? В случае веб приложения всё довольно просто - отправлять запросы по протоколу HTTP в параметры GET/POST запросов. Перед началом работы также необходимо собрать конечные точки, которые будут участвовать в фаззинге.
- Как генерировать вводы? «Вводом» будем называть набор данных, переданный программе на вход. В качестве ввода можно создавать массивы рандомных байтов, а можно делать что‑нибудь более умное.
- Как определять факт ошибки? Если программа упала — это баг. Но существуют ошибки, которые не приводят к падению. Пример: утечка информации. Такие ошибки тоже хочется находить. Для этого можно пропускать трафик фаззера через прокси.
- Как автоматизировать процесс? Можно запускать программу с новыми вводами вручную и смотреть, не упала ли она. А можно написать скрипт, который будет делать это автоматически и упростит работу.
Способ фаззинга №1. Katana + Nuclei
Проблема | Решение |
Как собрать конечные точки и параметры? | Katana |
Что служит входными данными? | Словари для фаззинга + генерация |
Как входные данные программе передавать? | Многопоточная отправка HTTP запросов |
Как генерировать вводы? | По формату на основе регулярок |
Как определять факт ошибки? | Логгировать запросы и фильтровать (Burp Suite Logger++) |
Как автоматизировать процесс? | Написать шаблон автоматизации для Nuclei |
Первым делом необходимо собрать все конечные точки с параметрами. Осуществить это нам поможет инструмент Katana, от создателей нуклея. Стоит заметить что все инструменты projectdiscovery между собой хорошо взаимодействуют, поэтому данная связка может оказаться высокоэффективной и менее затратной по времени. Наша задача при использовании данного инструмента охватить максимальное количество запросов с различными методами и параметрами. К счастью для этого у катаны есть браузерный краулер и функции автозаполнения форм.
Bash:
katana -u http://testphp.vulnweb.com/ -headless -c 50 -kf -jc -aff -j > katana.json
Что примечательно, сохранение запроса в json позволяет включить в список запросов не только GET, но и POST. По какой-то причине в текстовом формате отображаются только параметры передаваемые в URI.
Часто (всегда) когда вы собираете GET параметры, в результате краулинга у вас вырисовывается картина с часто повторяющимися параметрами у которых отличаются только значения. В таком случае необходимо избавиться от повторений и для удобства заменить значения параметра ключевым словом FUZZ (так, при использовании wfuzz в последствии вам не придётся ставить костыль).
Прогнав список через специальные утилиты мы получим довольно приличный вид, без мусора и лишних линков.
Bash:
cat fuzz_list.txt | grep "=" | uro | qsreplace 'FUZZ' | freq
В данном случае используются следующие специальные утилиты:
- uro - очищает список от мусорных повторений параметров (ссылка на гит)
- qsreplace - заменяет значения параметров (ссылка на гит)
- freq - проверяет доступность (ссылка на гит)
Если добавить к этому ещё и waybackurls, то мы получим ещё один не плохой способ собрать конечные точки для фаззинга.
Bash:
echo testphp.vulnweb.com | waybackurls | grep "=" | uro | qsreplace 'FUZZ' | freq
Freq также может в процессе краулинга провести собственные небольшие проверки на наличие XSS и SQL инъекций, для этого необходимо задать в qsreplace соответствующую полезную нагрузку, но сейчас не об этом.
Теперь, собрав список конечных точек для фаззинга, необходимо подготовить прокси, который будет логгировать проходящие через него запросы и ответы для дальнейшего анализа ошибок. Для этого необходимо установить расширение Logger++ в инструменте Burp Suite и подключить его. Теперь в дальнейшем просто оставим его активным и укажем в качестве прокси дефолт `127.0.0.1:8080`.
Помимо основного анализа ошибок мы также можем осуществить часть проверок при написании или использовании непосредственно шаблона для фаззинга. Тогда можно будет исключить варианты багов, явно выделяющихся в общем списке.
Написание шаблона для фаззинга зависит в первую очередь от того, что вы изучаете, форма авторизации ли это, форма загрузки файла, xml парсер, конвертер из html в pdf и всё тому подобное. Описание данных тонкостей требует от вас необходимых знаний о тех или иных уязвимостях, которые могут выстрелить в определённых условиях. Чтобы не распыляться приведу простейший пример шаблона, ориентированного на параметры в GET запросах.
Написание шаблона для фаззинга зависит в первую очередь от того, что вы изучаете, форма авторизации ли это, форма загрузки файла, xml парсер, конвертер из html в pdf и всё тому подобное. Описание данных тонкостей требует от вас необходимых знаний о тех или иных уязвимостях, которые могут выстрелить в определённых условиях. Чтобы не распыляться приведу простейший пример шаблона, ориентированного на параметры в GET запросах.
JSON:
id: reflected-xss
info:
name: Reflected Cross Site Scripting
author: pdteam
severity: medium
tags: xss,rxss,dast
variables:
first: "{{rand_int(10000, 99999)}}"
http:
- pre-condition:
- type: dsl
dsl:
- 'method == "GET"'
payloads:
reflection:
- "'\"><{{first}}"
fuzzing:
- part: query
type: postfix
mode: single
fuzz:
- "{{reflection}}"
stop-at-first-match: true
matchers-condition: and
matchers:
- type: word
part: body
words:
- "{{reflection}}"
- type: word
part: header
words:
- "text/html"
Принцип работы данного темплейта для фаззинга ничуть не отличается от стандартных самописных модулей. Новым является лишь семейство параметров fuzzing, корректирующее процесс обработки параметров запроса. Об этом уже написано в базе знаний (полный гайд по нуклею).
Теперь, когда мы собрали всекамни бесконечности необходимые ресурсы можно приступать непосредственно к процессу фаззинга. На данном этапе всё гораздо проще, необходимо лишь указать нуклею специальную опцию dast, которая позволяет использовать темплейты фаззинга. Просто опция fuzz является устаревшей и не рекомендуется к использованию. Также, при запуске не забываем про наш прокси.
Скорость фаззинга и результаты работы довольно не плохие. Как говорится, результат на лицо. При этом, в логгере отображаются запросы, которые отправлял нуклей. В дальнейшем можно отфильтровать их специальными выражениями Logger++ и уже отправить в повторитель для ручного изучения.
Теперь, когда мы собрали все
Bash:
nuclei -proxy http://127.0.0.1:8080 -t custom-fuzzing-templates -list fuzz_list.txt -dast -im list -irr -je best_fuzzer_result.json
Скорость фаззинга и результаты работы довольно не плохие. Как говорится, результат на лицо. При этом, в логгере отображаются запросы, которые отправлял нуклей. В дальнейшем можно отфильтровать их специальными выражениями Logger++ и уже отправить в повторитель для ручного изучения.
Способ фаззинга №2. Burp + FFUF
Проблема | Решение |
Как собрать конечные точки и параметры? | Burp Crawler |
Что служит входными данными? | Словари для фаззинга (intruder payloads) |
Как входные данные программе передавать? | Многопоточная отправка HTTP запросов |
Как генерировать вводы? | По формату на основе регулярок |
Как определять факт ошибки? | Логгировать запросы в json через ffuf |
Как автоматизировать процесс? | FFUF |
Что же, не рассмотреть старый но не бесполезный метод было бы крайне глупо с моей стороны. У каждого есть свои связки инструментов, которые он использует для фаззинга и в данном мануале я стараюсь рассмотреть самое распространённое, так сказать то, что точно зайдёт многим. Burp сам по себе довольно тяжеловесный инструмент в плане автоматизированного поиска багов и зачастую он жрёт довольно много памяти, однако у него есть довольно удобный краулер, которым грех не воспользоваться. С другой же стороны довольно древний FFUF, который в умелых руках может превратиться в инструмент для мгновенного убийства.
Первым делом приступим к краулингу. В данном случае нет ничего сложного, ведь интерфейс Burp Suite понятен любому ламеру. Выбераем необходимый ресурс и отправляем его на сканирование. В параметрах сканирования выберем только краулинг. При наличии также можно записать процесс авторизации или указать креды вручную для того чтобы краулер прошелся по ресурсу под авторизованным пользователем.
В разделе Target вы можете наблюдать карту запросов, которую выстраивает краулер в результате своей работы. Помимо работы краулера также совету пройтись по ресурсу руками и потыкать разные функции, позаполнять формы, чтобы точно ничего не было упущено.
Теперь наша задача состоит в сборе всех конечных точек (путей и параметров) в отдельные файлы, для дальнейшей подгрузки в WFUZZ. С этим нам поможет замечательное расширение GetAllParams. Отправляем наши результаты на сканирование гапом и наблюдаем выделенные списки конечных точек. Прошу обратить внимание на то где стоят галочки.
Сохраняем полученные результаты в отдельные списки и переходим ко второй части фаззинга и выполняем процедуры избавления от мусора и корректировки результата (в данном кейсе оно немного отличается от использованных ранее методов).
Bash:
ffuf -w "GAPcrawl.txt" -u "FUZZ" -noninteractive -o "results.json" -od "/tmp/bodies/" -of json
Когда установлен -od у нас есть все заголовки и тела HTTP для каждого запрошенного URL-адреса. Ffuf изначально будет анализировать все тела и дополнит JSON-файл первоначальных результатов следующими точками данных:
- количество всех заголовков
- домен перенаправления, если применимо
- количество параметров в перенаправлении, если применимо
- длина и слова заголовка страницы (если существует)
- количество обнаруженных CSS-файлов
- количество обнаруженных js-файлов
- количество тегов в html/xml/json (дикий расчет)
После этого он просканирует весь новый файл результатов и сохранит только те записи, которые уникальны на основе известных типов метаданных. Если окажется, что одно из этих значений всегда разное (например, заголовок страницы может сильно различаться) — этот тип метаданных будут пропущены при проверке уникальности.
В общем, этот инструмент всегда сохраняет небольшое количество записей, которые _не_ являются уникальными. Например, если файл результатов в формате JSON содержит 300x HTTP-статус 403 (со словами, длиной, ... идентичными) и 2 уникальных ответа http-статуса 200, он не удаляет все 300 записей HTTP-статуса 403. Он сохранит X из них в наборе данных.
В следующей части добьём фаззинг вторым методом и изучим принципы анализа логов. Надеюсь вам понравилось это чтиво.