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

Привет, Хабр! Меня зовут Алексей Ломай, я младший системный инженер отдела DevOps в IBS. В этой статье расскажу о фаззинге как о мощном инструменте тестирования безопасности веб-приложений. Поговорим об истории и развитии подхода, о доступных инструментах и двух вариантах реализации в CI/CD.

Что такое фаззинг?

Фаззинг (Fuzz-test) — метод тестирования безопасности, при котором система подвергается случайным или специально сгенерированным входным данным с целью выявления уязвимости.

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

Фаззинг-тестирование состоит из пяти основных этапов:

  • Генерация входных данных. Фаззер создает тестовые данные на основе словарей, случайных значений или специальных паттернов для конкретных атак.

  • Отправка данных. Тестовые данные отправляются в тестируемую систему через HTTP-запросы, сетевые пакеты или другие механизмы взаимодействия с ней.

  • Мониторинг реакции системы. Фаззер отслеживает ответы системы, анализируя неожиданное поведение (ошибки обработки, сбои, а также утечку информации).

  • Анализ результатов. Если система реагирует неожиданно — падает, выдает ошибки или нежелательную информацию, — фаззер это фиксирует как потенциальную уязвимость.

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

История фаззинга

История фаззинга началась в 1985 году, когда Билл Пелтон начал экспериментировать со случайными данными для тестирования сетевых протоколов. В 1989 году Барт Миллер и его команда из Университета Висконсина-Мэдисон опубликовала статью «An Empirical Study of the Reliability of UNIX Utilities», в которой они обнаружили, что около четверти утилит Unix были уязвимы к сбоям при обработке некорректных входных данных. А уже в 1996 Microsoft начал активно использовать и развивать фаззинг для тестирования своих продуктов, создав инструмент SAGE. В 2006 году фаззеры начали активно использовать методы анализа покрытия кода для более эффективного поиска уязвимостей. Появился крайне известный на сегодняшний день инструмент American Fuzzy Lop (AFL).

В последние годы наблюдается тенденция внедрения в фаззинг технологий AI и машинного обучения. Появились такие инструменты, как Driller и Vuzzer, а также облачные платформы вроде OSS-Fuzz, для фаззинга открытого исходного кода. Фаззинг начали интегрировать в CI/CD пайплайна, что позволяет автоматически выполнять тесты безопасности на каждом этапе разработки.

Классификация инструментов

Инструменты фаззинга можно классифицировать по различным признакам.

Первый — это подход к генерации входных данных для файзеров:

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

  • Также можно использовать специально сформированные данные. Фаззеры могут опираться на заранее подготовленные паттерны, такие как SQL-инъекции, XSS-атаки, буферные переполнения и другие, чтобы целенаправленно проверить конкретные уязвимости. 

Фаззеры можно разделять по способу отправки данных целевому ресурсу:

  • HTTP-запросы. Для веб-приложений фаззеры могут отправлять HTTP-запросы с различными параметрами, заголовками и телами запросов.

  • Сетевые пакеты. Для сетевых протоколов фаззеры могут отправлять специально сформированные пакеты.

  • Файловые операции. Для файловых систем фаззеры могут создавать, изменять и удалять файлы с различными именами и содержимым.

На самом деле типов данных и способов их отправки гораздо больше; я представил основные.

Еще один метод классификации — по уязвимостям, выявляемым в процессе фаззинга:

  • Ошибки обработки. Система некорректно обрабатывает входные данные.

  • Утечка информации. Система возвращает неожиданные данные.

  • Непредвиденное поведение. Система ведет себя не так, как ожидалось.

Где можно применить инструменты фаззинга

Фаззинг можно применять для веб-приложений. Наверное, это основная и ключевая его цель. Это может быть тестирование форм, API, URL-параметров, заголовков и других элементов. 

Также можно тестировать с помощью фаззинга сетевые протоколы — сервисы, использующие протоколы DNS, HTTP, FTP и другие. 

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

Можно использовать фаззеры для тестирования ПО в более широком смысле, включая приложения, библиотеки и драйверы. 

Основные цели фаззинга

Можно выделить три основные цели фаззинга.

Первое — это выявление уязвимостей в коде. Хороший пример — инструмент sqlmap, который может автоматически тестировать веб-приложения на уязвимости к SQL-инъекциям. Он отправляет специально сформированные SQL-запросы и анализирует ответы сервера. 

Второе — обнаружение ошибок и сбоев системы. Ранее упомянутый инструмент American Fuzzy Lop может тестировать бинарные файлы и сложные протоколы, отправляя специально сформированные данные и анализируя поведение программы, чтобы найти буферные переполнения и другие ошибки.

Стоит отметить, что AFL подходит для большего количества целей, не только для обнаружения ошибок и сбоев. 

Третье — тестирование обработки пользовательского ввода. Feroxbuster, о котором я расскажу дальше, может тестировать веб-приложение на наличие скрытых директорий, файлов, отправляя запросы с различными путями и анализируя ответы сервера. 

Классификация относительно знания внутренней структуры системы

Фаззеры можно классифицировать относительно знания внутренней структуры системы. Выделяют три основных уровня: 

  • White-box подразумевает собой полное знание структуры системы и фаззинг на основе этого знания. Это наиболее детальный подход к тестированию безопасности, при котором фаззер имеет полный доступ к исходному коду, архитектуре и внутренним механизмам тестируемой системы. Этот метод позволяет фаззеру анализировать потоки данных, точки входа, алгоритмы обработки и другие внутренние компоненты для создания максимально эффективных тестовых сценариев.

  • Grey-box — это частичное знание структуры системы, когда мы можем протестировать определенную часть веб-приложения. Гибридный подход, который сочетает преимущества black-box и white-box методов. Этот метод использует данные о профилировании, покрытии кода, метриках выполнения и статистике работы для оптимизации процесса фаззинга.

  • Black-box — это когда мы полностью игнорируем внутреннюю структуру тестируемой системы, анализируя только результаты выполнения и ее реакции. В этом подходе фаззер генерирует случайные или специально подобранные входные данные, работая только с внешними интерфейсами.

Реализация в CI/CD

Я поставил себе цель найти фаззер, наиболее подходящий для реализации в Jenkins пайплайне, а заодно поискать уязвимости в приложениях, которые разрабатываются либо используются для работы в инфраструктуре IBS. Для этого подготовил два пайплайна с помощью Jenkins для автоматизации процесса сканирования. Для первого выбрал Feroxbuster и Nuclei, а для второго — FFUF. Сами инструменты и запуск сканеров осуществил с помощью контейнеров Docker.

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

Feroxbuser & Nuclei

Первый пайплайн работает следующим образом:

  • проводит сканирование на наличие скрытых ресурсов с помощью Feroxbuster;

  • анализирует найденные ресурсы на общеизвестные уязвимости с помощью Nuclei;

  • выдает отчет с найденными уязвимостями и нежелательной информацией. 

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

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

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

Использованный в паре с Feroxbuster Nuclei — это open source инструмент с крайне гибкими настройками. С его помощью можно проверять общеизвестные уязвимости по найденным URL. Он может работать по заранее описанным шаблонам уязвимостей (XSS, SQL инъекции, SSRF и LFI и так далее) и имеет большое быстро развивающееся сообщество, которое расширяет его функционал. Nuclei может сканировать URL, IP, домены. На данный момент он считается одним из лучших и максимально универсальных в своем классе. 

Nuclei поддерживает множество шаблонов и позволяет добавлять свои, когда необходим более точечный анализ уязвимостей собственного проекта. Он использует внутренние HTTP-запросы к найденным эндпоинтам. А в моей реализации он отправляет запросы к путям, которые были выявлены с помощью Feroxbuster, выполняя анализ ответов севера и поиск сигнатуры уязвимости. 

FFUF

Во втором пайплайне я использовал только один инструмент — FFUF. Он наиболее простой в настройке и интеграции в CI/CD. FFUF работает по принципу «опроса» сканируемого URL с помощью заранее подготовленных словарей и динамической подстановки параметров. Наверное, можно сказать, что это «чистокровный» фаззер, который:

  • выполняет фаззинг URL-путей, параметров заголовков и тела запроса;

  • поддерживает различные режимы фаззинга (FUZZ — замена слова в URL, HEADERS, BODY, PARAMS — фаззинг заголовков, тела запроса, параметров);

  • использует внутренние шаблоны для определения уязвимостей — в отличие от Feroxbuster шаблон должен присутствовать обязательно, иначе он не запустится;

  • поддерживает фильтрацию результатов.

Второй пайплайн проверяет, как система реагирует на неожиданные входные данные. Он используется для поиска уязвимостей типа XSS, SQLi, LFI, SSRF и так далее. В моем случае процесс работы заключается в том, что изначально задаются словари (wordlists) для фаззинга путей, параметров, заголовков. Определяются параметры сканирования (методы, фильтрация результатов). При этом FFUF может быть использован как полноценный отдельный шаг для полного сканирования на уязвимости, допустим, в каком-нибудь конвейере.

Тут хочу отметить, что у FFUF командой разработки выпущено несколько словарей, которые отличаются друг от друга по размеру. Они достаточно универсальны — их можно использовать для большого количества веб-приложений. В одном из запусков я использовал самую крупную библиотеку от разработчика, которая содержит в себе 600 млн записей.

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

Сравнение пайплайнов

Я собрал основные отличия в таблице.

Основное — это разница в целях. Если Feroxbuster и Nuclei используются сначала для поиска скрытых путей, а потом уже для их анализа на общеизвестные уязвимости, то FFUF представляет собой прямой фаззер. Мы вводим с помощью инструмента данные и в результате находим уязвимости, не прогоняя его по каким-либо шаблонам и базам. Если первый пайплайн дает более широкий охват, то второй — это более точечный поиск.

Два пайплайна в CI/CD нужны, чтобы:

  • Задействовать разные уровни сканирования. Feroxbuster и Nuclei больше подходят для общего сканирования и выявления проблем веб-ресурса, а FFUF выявляет уязвимости ввода данных.

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

Найденные уязвимости

Для анализа работы двух пайплайнов я выбрал внутренний ресурс — хранилище артефактов Nexus. После сканирования двумя описанными методами я получил целый ряд уязвимостей. Наиболее интересные перечислю:

  • Уязвимость в Apache Struts, фреймворке для разработки веб-приложений на языке Java. Она относится к категории Remote Code Execution (RCE), то есть злоумышленник может выполнить произвольный код на сервере, если ему удастся отправить специально подготовленные данные. Эта уязвимость была найдена Nuclei после прогонов по шаблонам. Важный момент: разработчик знает об этой ошибке, и в более свежей версии уязвимость уже исправлена. 

  • В одном из файлов инициализации отражена версия nginx 118, что может дать возможность злоумышленнику атаковать ресурс, используя известную уязвимость данной версии. В целом, nginx стоит не самой свежей версией, поэтому уязвимости там достаточно. 

  • Была найдена в открытом доступе API документация ресурса. Открытая публикация этих данных может привести к получению атакующим полной карты API и к дальнейшей атаке с ее применением.

  • FFUF нашел страницу с токеном Docker для доступа к хранилищу docker-образов, что может позволить злоумышленникам завладеть конфиденциальной информацией, связанной с содержимым репозитория. 

  • FFUF также нашел URL, по которому гипотетически возможно выполнение PHP кода на странице (если сервер выполняет переданное в строке как вызов функции). 

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

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

Кроме того, в процессе работы фаззер повредил хранилище артефактов для Docker. Это говорит об уязвимостях в открытом доступе к конфиденциальной информации, которой могли завладеть злоумышленники и нанести ущерб компании.

Выводы

В условиях, когда веб-приложение используется в критически важных системах, наличие уязвимости может привести к серьезным последствиям. Фаззинг-сканирование — мощный инструмент для выявления скрытых уязвимостей, которые могут быть использованы злоумышленником.

Внедренные инструменты достаточно гибкие и лояльны к настройке в рамках пайплайна Jenkins (это стало важным аспектом выбора). Они не требуют каких-либо дополнительных действий для обеспечения работоспособности, при этом имеют обширный функционал. Для реализации достаточно Jenkins и Docker c базовыми образами. 

Автоматизация процесса сканирования с помощью Jenkins позволила значительно повысить скорость и надежность тестирования безопасности. Использование конкретно Jenkins Pipeline обеспечило интеграцию фаззинга в стандартный процесс разработки, что делает его частью регулярной проверки безопасности. Проверка с помощью FFUF на не самом большом словаре занимает порядка 5-7 минут, то есть код можно проверять чаще. 

Есть только один нюанс. Сейчас я сканировал данные, доступные снаружи. Но если используется более сложная система аутентификации, например SSO, фаззер ее не пройдет. Потребуется либо ручное тестирование, либо придется потратить время на настройку сканера. Но в целом фаззинг обычно используется еще на этапе разработки — на защищенный прод встраивать его нет смысла. А вообще веб-приложениями сфера применения подхода не ограничивается. Для любого стека есть свои инструменты фаззинга — это очень обширная методика. Даже ГОСТ 56939 предполагает наличие фаззинга.