Статья Методология фаззинга Web-ресурсов

Фа́ззинг (англ. fuzzing или англ. fuzz testing, буквально «испытание пушинками/волосинками»), также тестирование мусорными данными — техника тестирования компонентов веб приложения, часто автоматическая или полуавтоматическая, заключающаяся в передаче приложению на вход неправильных, неожиданных или случайных данных.

Цель фаззинга:
Предметом интереса являются падения и зависания, нарушения внутренней логики и проверок в коде приложения, утечки памяти, вызванные такими данными на входе. Фаззинг является разновидностью выборочного тестирования (random testing), часто используемого для проверки проблем безопасности в программном обеспечении и компьютерных системах.

2024-08-02_12-59.png


Как он работает?
Мы генерируем случайные данные, передаем их на вход программе и проверяем, не сломалась ли она. Если не сломалась — генерируем новый ввод. Если сломалась — прекрасно, мы нашли баг. Предполагается, что программа не должна падать от неожиданного ввода, она должна этот ввод корректно обрабатывать.​

Когда мы начинаем работать с фаззером для очередного веб приложения, нам нужно разобраться со следующими вопросами:​
  1. Как собрать конечные точки и параметры? Данный пункт является основным, так как от того, на сколько объёмную поверхность атаки мы сможем занять зависит успех фаззинга. Необходимо собрать как можно больше точек входа в приложение.​
  2. Что служит входными данными? Для XML-парсера входные данные — XML-файлы. А, например, для обычных форм можно грузить нагрузки как по формату, так и различные инъекции, HTML/JS код, специальные символы и тому подобное.​
  3. Как входные данные программе передавать? В случае веб приложения всё довольно просто - отправлять запросы по протоколу HTTP в параметры GET/POST запросов. Перед началом работы также необходимо собрать конечные точки, которые будут участвовать в фаззинге.​
  4. Как генерировать вводы? «Вводом» будем называть набор данных, переданный программе на вход. В качестве ввода можно создавать массивы рандомных байтов, а можно делать что‑нибудь более умное.​
  5. Как определять факт ошибки? Если программа упала — это баг. Но существуют ошибки, которые не приводят к падению. Пример: утечка информации. Такие ошибки тоже хочется находить. Для этого можно пропускать трафик фаззера через прокси.​
  6. Как автоматизировать процесс? Можно запускать программу с новыми вводами вручную и смотреть, не упала ли она. А можно написать скрипт, который будет делать это автоматически и упростит работу.​

Способ фаззинга №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.​

2024-08-02_13-22.png


Часто (всегда) когда вы собираете GET параметры, в результате краулинга у вас вырисовывается картина с часто повторяющимися параметрами у которых отличаются только значения. В таком случае необходимо избавиться от повторений и для удобства заменить значения параметра ключевым словом FUZZ (так, при использовании wfuzz в последствии вам не придётся ставить костыль).​


2024-08-05_10-18.png


Прогнав список через специальные утилиты мы получим довольно приличный вид, без мусора и лишних линков.
Bash:
cat fuzz_list.txt | grep "=" | uro | qsreplace 'FUZZ' | freq

В данном случае используются следующие специальные утилиты:​

2024-08-05_10-36.png


Если добавить к этому ещё и waybackurls, то мы получим ещё один не плохой способ собрать конечные точки для фаззинга.​
Bash:
echo testphp.vulnweb.com | waybackurls | grep "=" | uro | qsreplace 'FUZZ' | freq

2024-08-05_10-40.png


Freq также может в процессе краулинга провести собственные небольшие проверки на наличие XSS и SQL инъекций, для этого необходимо задать в qsreplace соответствующую полезную нагрузку, но сейчас не об этом.
Теперь, собрав список конечных точек для фаззинга, необходимо подготовить прокси, который будет логгировать проходящие через него запросы и ответы для дальнейшего анализа ошибок. Для этого необходимо установить расширение Logger++ в инструменте Burp Suite и подключить его. Теперь в дальнейшем просто оставим его активным и укажем в качестве прокси дефолт `127.0.0.1:8080`.​

2024-08-02_14-03.png


Помимо основного анализа ошибок мы также можем осуществить часть проверок при написании или использовании непосредственно шаблона для фаззинга. Тогда можно будет исключить варианты багов, явно выделяющихся в общем списке.
Написание шаблона для фаззинга зависит в первую очередь от того, что вы изучаете, форма авторизации ли это, форма загрузки файла, 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 является устаревшей и не рекомендуется к использованию. Также, при запуске не забываем про наш прокси.

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


2024-08-05_10-53.png


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

2024-08-05_10-52.png


Способ фаззинга №2. Burp + FFUF
ПроблемаРешение
Как собрать конечные точки и параметры?Burp Crawler
Что служит входными данными?Словари для фаззинга (intruder payloads)
Как входные данные программе передавать?Многопоточная отправка HTTP запросов
Как генерировать вводы?По формату на основе регулярок
Как определять факт ошибки?Логгировать запросы в json через ffuf
Как автоматизировать процесс?FFUF

Что же, не рассмотреть старый но не бесполезный метод было бы крайне глупо с моей стороны. У каждого есть свои связки инструментов, которые он использует для фаззинга и в данном мануале я стараюсь рассмотреть самое распространённое, так сказать то, что точно зайдёт многим. Burp сам по себе довольно тяжеловесный инструмент в плане автоматизированного поиска багов и зачастую он жрёт довольно много памяти, однако у него есть довольно удобный краулер, которым грех не воспользоваться. С другой же стороны довольно древний FFUF, который в умелых руках может превратиться в инструмент для мгновенного убийства.
2024-08-05_11-18.png


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

2024-08-05_11-28.png


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

2024-08-05_11-25.png


Теперь наша задача состоит в сборе всех конечных точек (путей и параметров) в отдельные файлы, для дальнейшей подгрузки в WFUZZ. С этим нам поможет замечательное расширение GetAllParams. Отправляем наши результаты на сканирование гапом и наблюдаем выделенные списки конечных точек. Прошу обратить внимание на то где стоят галочки.

2024-08-05_11-55.png


Сохраняем полученные результаты в отдельные списки и переходим ко второй части фаззинга и выполняем процедуры избавления от мусора и корректировки результата (в данном кейсе оно немного отличается от использованных ранее методов).
Bash:
ffuf -w "GAPcrawl.txt" -u "FUZZ" -noninteractive -o "results.json" -od "/tmp/bodies/" -of json

2024-08-05_12-10.png


Когда установлен -od у нас есть все заголовки и тела HTTP для каждого запрошенного URL-адреса. Ffuf изначально будет анализировать все тела и дополнит JSON-файл первоначальных результатов следующими точками данных:​
  • количество всех заголовков​
  • домен перенаправления, если применимо​
  • количество параметров в перенаправлении, если применимо​
  • длина и слова заголовка страницы (если существует)​
  • количество обнаруженных CSS-файлов​
  • количество обнаруженных js-файлов​
  • количество тегов в html/xml/json (дикий расчет)​

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

В общем, этот инструмент всегда сохраняет небольшое количество записей, которые _не_ являются уникальными. Например, если файл результатов в формате JSON содержит 300x HTTP-статус 403 (со словами, длиной, ... идентичными) и 2 уникальных ответа http-статуса 200, он не удаляет все 300 записей HTTP-статуса 403. Он сохранит X из них в наборе данных.

В следующей части добьём фаззинг вторым методом и изучим принципы анализа логов. Надеюсь вам понравилось это чтиво.​
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!