Pull to refresh
63.15
Swordfish Security
Информационная безопасность, DevSecOps, SSDL

Как провести фаззинг REST API с помощью RESTler

Reading time7 min
Views3.9K

Вступление

Привет, Хабр! С вами Владимир Исабеков, руководитель группы статического тестирования безопасности приложений в Swordfish Security. Современная разработка программного обеспечения требует не только функционального, но и безопасного API. Сегодня мы расскажем, как провести фаззинг-тестирование API c помощью инструмента RESTler, имея на руках только спецификацию API. Статья написана в соавторстве с нашим инженером по безопасности, Артемом Мурадяном @TOKYOBOY0701.

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

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

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

На вкус и цвет все фаззеры разные, методы их классификации также отличаются. Рассмотрим примеры некоторых вариантов:

  • По методу генерации новых входных значений:

    1. Mutation-based Fuzzers. Мутируют существующие входные данные, чтобы создать новые тестовые случаи;

    2. Generation-based Fuzzers. Создают новые входные данные с нуля (или не совсем), основываясь на грамматиках.

  • По типу обратной связи:

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

    2. Код ответа. Для анализа API фаззеры используют ответ от сервера, поскольку при фаззинге веб-приложений не всегда можно эффективно получать информацию о покрытии кода;

    3. Без обратной связи или брутфорс. Осуществляют систематический перебор значений.

  • По цели фаззинга:

    1. Protocol-based Fuzzers. Фокусируются на тестировании безопасности сетевых протоколов и программ, обрабатывающих конкретные файловые форматы (изображения, архивы и документы и другое);

    2. Library and Framework Fuzzers. Предназначаются для тестирования функций из готовых библиотек и пакетов;

    3. Binary Fuzzers. Осуществляют проверку безопасности исполняемого бинарного кода;

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

Фаззинг REST API

Теперь поговорим конкретно о Stateful REST API-фаззинге с применением инструмента RESTler. Этот метод фокусируется на тестировании безопасности REST API. Stateful-фаззинг учитывает состояние сервера и предыдущие запросы, в отличие от Stateless-теста, который рассматривает каждый запрос к API как изолированный случай.

Воспользоваться методом Stateful REST API Fuzzing можно с помощью инструмента RESTler, разработанного компанией Microsoft. Он может фаззить веб-приложения с REST API, изучая спецификацию OpenAPI. RESTler генерирует тесты с помощью анализа обратной связи из ответов, полученных во время выполнений цепочек запросов. Инструмент выявляет зависимости между типами запросов, объявленных в OpenAPI.

Начало работы

RESTler может работать под Windows, Linux и macOS. Собрать его можно в виде докер-образа или классического бинарника. Рассмотрим основные этапы работы фаззера и его настройки на примере тестового сервера из самого RESTler-a (он находится в каталоге demo_server). Первый этап работы – генерирование грамматики на основании OpenAPI Specification (в формате JSON или YAML). Для этого скомпилируем спецификацию тестового сервера:

C:\restler_bin\restler\Restler.exe compile --api_spec C:\demo_server\swagger.json

Так мы создаем новый каталог Compile в директории, откуда производится запуск команды. Результаты компиляции сохраняются в нескольких файлах:

  • grammar.py и grammar.json. В грамматике содержится информация о параметрах запросов и различных зависимостях между ними. На первом скриншоте можно увидеть функции, которые будут сохранять результаты ответов сервера для их использования в последующих цепочках запросов (второе изображение);

  • dict.json— словарь, связывающий типы параметров запросов с наборами значений. Можно редактировать этот файл по своему усмотрению, например, добавить кастомные пейлоады через свойство restler_custom_payload и указать в нем константные значения. На изображении ниже мы видим поле restler_fuzzable_string, значит, этот параметр в запросе будет фаззиться. Аналогично и для других типов, начинающихся с restler_fuzzable. Можем наблюдать на скриншотах, что все эти параметры используются в грамматике;

  • Config.json – файл, с помощью которого можно кастомизировать настройки компилятора рестлера, например, подключить в нем заранее подготовленные грамматики или указать несколько спецификаций;

  • Engine_settings. Используется для указания настраиваемых параметров RESTler. Позволяет редактировать IP и порт тестируемой цели, кастомный генератор входных данных и последовательность запросов, а также многие другие форматы. Их можно указывать для каждого эндпоинта.

Тестирование спецификации

Второй этап работы с RESTler – это выполнение всех запросов в спецификации OpenAPI хотя бы один раз и получение в ответ кода состояния «200». Делается это для того, чтобы определить, какие запросы невозможно выполнить при текущей настройке фаззера. Запускаем тест командой:

C:\restler_bin\restler\restler.exe test --grammar_file C:\demo_server\Compile\grammar.py --dictionary_file C:\demo_server\Compile\dict.json --settings C:\demo_server\Compile\engine_settings.json —no_ssl

В консоли можно увидеть, сколько эндпоинтов было протестировано успешно:

В результате работы создается каталог Test\RestlerResults\experiment{...}\logs, в котором находятся файлы:

  • speccov.json – результаты тестирования для каждого запроса в грамматике;

  • main.txt – журнал, в котором документируются попытки выполнения каждого запроса;

  • network.testing.{threadID}.txt – файл, в котором регистрируется весь HTTP(S)-трафик, генерируемый RESTler, включая все выполненные запросы REST API и их ответы. Он может помочь в случае, если покрытие тестами неполное. Это позволяет проверить сгенерированные запросы и ответы, и, при необходимости, изменить спецификацию OpenAPI (если она неполная), добавить нужные значения в словарь или отредактировать грамматику вручную. Тестовый режим по умолчанию попытается успешно выполнить каждый запрос один раз. Например, если параметр запроса имеет несколько возможных значений и успешно выполняется при передаче первого, то остальные не будут проверяться. Если же необходимо проверить все значения параметров запросов, то это можно сделать с помощью аргумента test_all_combinations. Результаты для всех комбинаций параметров будут указаны в файле speccov.json.

Фаззинг (ezmode)

Когда уровень покрытия тестами спецификации нас устраивает, можно переходить непосредственно к фаззингу. Здесь есть два возможных варианта. По сути, такое тестирование – бесконечный процесс, поэтому можно воспользоваться режимом RESTler-а под названием Fuzz-lean. Он предполагает однократное выполнение эндпоинта и метода из грамматики для быстрого обнаружения возможных багов. Второй вариант – режим Fuzz, при котором проводится полное тестирование RestAPI.

Для запуска теста нашего примера в режиме Fuzz-lean выполним команду:

C:\restler_bin\restler\restler.exe fuzz-lean --grammar_file C:\demo_server\Compile\grammar.py --dictionary_file C:\demo_server\Compile\dict.json --settings C:\demo_server\Compile\engine_settings.json --no_ssl

В консоли можно увидеть, сколько протестировано эндпоинтов и какие найдены баги:

Баги
Баги

Результаты находятся в новом каталоге FuzzLean\RestlerResults\experiment{...}, схожем с тем, что создавался при фазе Test с результатами покрытия. Но сейчас он содержит еще и bug_buckets со списком уникальных последовательностей запросов, которые привели к багам. Если мы получаем в качестве ответа коды состояния «500», их нужно рассматривать как ошибки. Баги группируются по последовательности запросов, даже если она создает более одной ошибки в ходе фаззинга. Исключением является ситуация, в которой новая проблема была обнаружена из-за другого кода состояния, например, если первая ошибка была «500», а вторая – «503». Уникальные последовательности с запросами и ответами хранятся в файле bug_buckets.txt и имеют отдельный журнал.

Триаж багов

Помимо ошибок с кодом 500, фаззер умеет находить и другие типы багов. За это отвечают чекеры – специально подготовленные правила, анализирующие цепочку запросов и выявляющие события/уязвимости, на которые они были заточены.

Рассмотрим некоторые баги, которые нашлись с помощью чекеров. В файле InvalidDynamicObjectChecker_20x_1.replay.txt мы видим сначала POST-запрос, который создает пост в блоге. Затем наблюдаем GET-запрос, который пытается получить только что созданный пост. Можно заметить, что чекер недопустимых динамических объектов заменил идентификатор сообщения в блоге с 94 на 94?injected_query_string=123, а сервер это проигнорировал. Так как данный чекер предполагает, что любой недопустимый динамический объект должен вызывать ошибку (например, выдать код состояния ответа "HTTP 400 Bad Request", а не возвращать код 20x), он помечает это как баг.

В файле UseAfterFreeChecker_20x_1.replay.txt содержится POST-запрос на создание поста с id=108, затем DELETE-запрос на его удаление, а в конце GET-запрос на пост с id=108. Чекер «Use after free» выявил, что ресурс (в данном случае пост с id=108) был успешно удален, но к нему всё еще можно получить доступ. Это было помечено как баг.

Фаззинг (hardcore)

Теперь испытаем режим Fuzz. Для этого воспользуемся командой:

C:\restler_bin\restler\restler.exe fuzz --grammar_file C:\demo_server\Compile\grammar.py --dictionary_file C:\demo_server\Compile\dict.json --settings C:\demo_server\Compile\engine_settings.json --no_ssl --time_budget 1

Новый параметр time_budget – это продолжительность выполнения фаззинга в часах. Результаты тестирования находятся в новом каталоге Fuzz\RestlerResults\experiment{…}. Баги будут аналогичны FuzzLean, но если изучить файл logs\network.testing.{…}.1.txt, можно заметить еще несколько случаев, в которых возникали одинаковые ошибки. Однако фаззер сгруппировал их по запросам и не дублировал, как упоминалось выше. Так как это простейший API, Fuzz не смог обнаружить дополнительных багов.

Заключение

Сегодня мы поговорили о Stateful REST API-фаззинге с применением RESTler-а. В следующих статьях продемонстрируем возможности этого инструмента на более сложных API, а также покажем дополнительные возможности его настройки. Оставайтесь с нами!

Tags:
Hubs:
Total votes 12: ↑12 and ↓0+12
Comments3

Articles

Information

Website
swordfish-security.ru
Registered
Founded
Employees
101–200 employees
Location
Россия
Representative
SwordfishTeam