что такое фаззинг тестирование

Автоматическое тестирование программ

Введение

Долгое время считалось, что динамический анализ программ является слишком тяжеловесным подходом к обнаружению программных дефектов, и полученные результаты не оправдывают затраченных усилий и ресурсов. Однако, две важные тенденции развития современной индустрии производства программного обеспечения позволяют по-новому взглянуть на эту проблему. С одной стороны, при постоянном увеличении объема и сложности ПО любые автоматические средства обнаружения ошибок и контроля качества могут оказаться полезными и востребованными. С другой – непрерывный рост производительности современных вычислительных систем позволяет эффективно решать все более сложные вычислительные задачи. Последние исследовательские работы в области динамического анализа такие, как SAGE, KLEE и Avalanche, демонстрируют, что несмотря на присущую этому подходу сложность, его использование оправдано, по крайней мере, для некоторого класса программ.

Динамический vs Статический анализ

Применение

Автоматическое тестирование в первую очередь предназначено для программ, для которых работоспособность и безопасность при любых входных данных являются наиважнейшими приоритетами: веб-сервер, клиент/сервер SSH, sandboxing, сетевые протоколы.

Fuzz testing (фаззинг)

Фаззинг – методика тестирования, при которой на вход программы подаются невалидные, непредусмотренные или случайные данные.

Фаззеры нового поколения (обзор)

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

Отслеживание помеченных данных в программе

Вводится понятие символических или помеченных (tainted) данных – данных, полученных программой из внешнего источника (стандартный поток ввода, файлы, переменные окружения и т. д.). Распространенным решением этой задачи является перехват набора системных вызовов: open, close, read, write, lseek (Avalanche,KLEE).

Инструментация кода

Код исследуемой программы приводится к виду, удобному для анализа. Например, используется внутреннее независимое от аппаратной платформы представление valgrind (Avalanche) или анализируется удобный для разбора сам по себе llvm-байткод программы(KLEE).

Инструментированный код позволяет легко находить потенциально опасные инструкции (например, деление на ноль или разыменование нулевого указателя) и их операнды, а также инструкции ветвления, зависящие от помеченных данных. Анализируя инструкции, инструмент составляет логические условия на помеченные данные и передает запрос на выполнимость “решателю” булевских формул (SAT Solver).

Решение булевских ограничений

SAT Solvers – решают задачи выполнимости булевых формул. Отвечают на вопрос: всегда ли выполнена заданная формула, и если не всегда, то выдается набор значений, на котором она ложна. Результаты работы подобных решателей используется широким набором анализирующих программ, от theorem provers до анализаторов генетического кода в биоинформатике. Подобные программы интересны сами по себе и требуют отдельного рассмотрения. Примеры: STP, MiniSAT.

Моделирование окружения
Перебор путей в программе

O(2^n), где n – количество условных переходов, зависящих от входных данных), но все еще остается значительной. Анализаторы вынуждены использовать различные эвристики для приоритезации анализа некоторых путей. В частности, различают выбор пути, покрывающего наибольшее количество непокрытых (новых) базовых блоков (Avalanche, KLEE) и выбор случайного пути (KLEE).

Avalanche

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

Общая схема работы

Инструмент Avalanche состоит из 4 основных компонент: двух модулей расширения (плагинов) Valgrind – Tracegrind и Covgrind, инструмента проверки выполнимости ограничений STP и управляющего модуля.

Ограничения
Результаты

unsigned mod_opt ( unsigned x, unsigned y ) <
if ( ( y & −y ) == y ) // power of two?
return x & ( y− 1 ) ;
else
return x % y ;
>
unsigned mod ( unsigned x, unsigned y ) <
return x % y ;
>
int main ( ) <
unsigned x,y ;
make symbolic ( & x, sizeof ( x ) ) ;
make symbolic ( & y, sizeof ( y ) ) ;
assert ( mod ( x,y ) == mod_opt ( x,y ) ) ;
return 0 ;
>

Запустив KLEE на данном примере, можно убедится в эквивалентности двух функций во всем диапазоне входных значений (y!=0). Решая задачу на невыполнение условия в ассерте, KLEE на основе перебора всех возможных путей приходит к выводу об эквивалентности двух функций на всем диапазоне значений.

Результаты

Для получения реальных результатов тестирования авторы проанализировали весь набор программ пакета coreutils 6.11. Средней процент покрытия кода составил 94%. Всего программа сгенерировала 3321 набор входных данных, позволяющих покрыть весь указанный процент кода. Так же было найдено 10 уникальных ошибок, которые были признаны разработчиками пакета как реальные дефекты в программах, что является очень хорошим достижением, так как этот набор программ разрабатывается более 20 лет и большинство ошибок было устранено.

Ограничения

Предварительные выводы

Безусловно, динамический анализ найдет свою нишу среди инструментов помогающих отдельным программистам и командам программистов решать поставленную задачу, т.к. является эффективным способом нахождения ошибок в программах, а так же доказательством их отсутствия! В в некоторых случаях подобные инструменты просто жизненно необходимы (Mission critical software: RTOS, системы управления производством, авиационное программное обеспечение и так далее).

Источник

Поиск уязвимости методом фаззинга и разработка шеллкода для её эксплуатации

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестированиеДля поиска уязвимостей все средства хороши, а чем хорош фаззинг? Ответ прост: тем, что он дает возможность проверить, как себя поведёт программа, получившая на вход заведомо некорректные (а зачастую и вообще случайные) данные, которые не всегда входят во множество тестов разработчика.

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

«Прощупываем» порт

Пробуем соединение по указанному адресу и порту. Для этого пользуемся широко известной утилитой netcat – «швейцарским ножом» для работы с сетью. Не забываем про завершающий нуль-терминатор в запросе:

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

Судя по этим ответам сервера, он распознает в качестве значений целые числа, но не распознает булевы значения.

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

Эти ответы сервера говорят о том, что он распознает в качестве значений непустые массивы.

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

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

В случае, если формат запроса корректно распознан, сервер проверяет наличие тега «pass» в главном ассоциативном массиве:

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

Если такой тег есть, проверяется его значение и, по-видимому, его хеш сверяется со значением в памяти.

Как получить корректное значение пароля? Можно попробовать простой перебор поля с паролем в запросах. Впрочем, результатов такая примитивная атака не дала.

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

Используем фаззинг!

Единственный источник информации – ответы сервера на наши запросы. В отсутствии бинарного кода и исходников используем фаззинг. Более подробно про сам подход к тестированию читаем тут и там, и узнаем, что есть два основных метода фаззинга:

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

1. Замена служебных символов корректного запроса на неправильные

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

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

Результатов такая проверка не дала. Значит, будем проверять другие случаи.

2. Проверка на большой уровень вложенности объектов и списков JSON друг в друга

Пример фаззера для проверки:

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

Опять сервер корректно обрабатывает все запросы. Аналогично проверяются списки большой вложенности. Их сервер также корректно обрабатывает. Будем проверять дальше!

3. Проверка на запросы, в которых чего-то «много»

Проверим длинные строки в ключах и значениях, объекты с большим количеством пар ключ-значение, длинные списки.

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

Как видим, длинные строки обрабатываются нормально. Длинные списки тоже. А как насчет длинных объектов?

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

Вот оно! При достаточно длинном объекте ответ сервера неполный – пользователю не выдается exit code. Это начинает происходить, когда объект содержит больше 257 пар «ключ-значение». Если сделать их количество еще больше, мы увидим, что ответ вообще не приходит:

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

Судя по всему, перед нами классическое переполнение буфера. Пары «ключ-значение» при разборе входного запроса помещаются в константный буфер на стеке без предварительной проверки их количества в запросе.

При этом, если число пар лежит в диапазоне от 257 до 281, перетирается адрес возврата из функции-обработчика запроса, а если их больше 281, вероятно, перетираются какие-то локальные переменные за адресом возврата. Это приводит к тому, что до пользователя не доходит и первая часть сообщения об ошибке.

Эксплуатируем уязвимость

Чтобы выполнить задание и получить заветный токен, необходимо понять, чем перетирается адрес возврата. Логично предположить, что на стек последовательно складываются не сами строки (ключи и значения объекта в запросе), а указатели на них. Если это так, можно не беспокоиться о размещении шеллкода в памяти и передаче на него управления. ASLR также в таком случае перестает быть помехой.

Сильно испортить жизнь нам может DEP, ведь память под строки выделяется в куче. Но не будем торопиться с выводами и проверим наши идеи на практике. Для этого возьмем какой-нибудь проверочный шеллкод под нашу платформу с целью понять, исполняема ли память в куче у процесса сервера?

Для этого возьмем обыкновенный bindshell на порт 4444 отсюда:

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

Поскольку у нас нет сведений о точном размере буфера, о наличии прочих локальных переменных, выравнивании памяти на стеке и т.д., необходимо размещать шеллкод немного с запасом. Разместим его в четырёх значениях у пар после 256, им предшествующих:

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

Ура, все работает! Память с шеллкодом исполняема, и адрес возврата из функции-обработчика запросов перезаписывается указателем на строку с шеллкодом автоматически. У нас появился удаленный шелл на сервере. Попробуем развить успех и получить доступ к бинарному коду JSON-обработчика:

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

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

Пишем шеллкод и получаем токен

Отчаиваться рано. Вспомним, что в данном случае наша цель – не бинарник как таковой, а значение в памяти процесса /neoquest/vuln.

Зная, что файл бинарника зашифрован, и что bindshell замещает текущий процесс сервера в памяти процессом bash, пойдём другим путем. Напишем свой egg hunt шеллкод, который найдет в памяти процесса нужное значение по известному префиксу («hash:») и выдаст его пользователю.

Вариант нашего шеллкода (длинного!) под спойлером:

Что делает этот шеллкод:

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

Сработало! При подключении на 4444 порт мы видим искомые 32 символа хеша пароля. Осталось получить пароль. Воспользуемся Google:

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

Искомый пароль: ABAB865A15B15538D81C066574449597. Осталось получить заветный токен:

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

Искомый токен: 795944475660c18d83551b51a568baba

Преимущества и недостатки фаззинга

Большое разнообразие возможных точек входа (текстовая строка, вводимая посредством GUI, бинарные данные из файла, значение поля сетевого запроса) и тестируемых приложений (можно фаззить файлы, протоколы, драйверы, веб-приложения, исходники. ) делает фаззинг довольно эффективным подходом к поиску проблем безопасности программного кода.

В данной статье мы продемонстрировали довольно простой пример фаззинга, в котором мутация генерируемых тестовых данных была сведена к минимуму, однако современные фаззеры (Peach, Sulley, HotFuzz и другие ) обладают гораздо более богатым функционалом, реализуя множество алгоритмов мутации.

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

А на NeoQUEST-2017 — еще больше интересных заданий!

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

В заданиях NeoQUEST-2017, который пройдет с 1 по 10 марта, несомненно, тоже будет чему научиться, поэтому смело регистрируйтесь!

Источник

Фаззинг — важный этап безопасной разработки

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

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

И это при том, что в мире разработки достаточно давно появились такие понятия, как Security Development Life Cycle (SDLC), и сравнительно недавно такие, как DevSecOps или SecDevOps, но используются эти техники далеко не всеми. Суть у них одна — внедрять подходы к повышению безопасности с первых этапов разработки, а лучше начинать с обучения сотрудников. И, конечно, важно уделять внимание защищенности продукта от атак на протяжении всего его жизненного цикла. За подробностями — добро пожаловать под кат.

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

Как раз во время написания статьи в ленте твиттера мелькнули заметки на тему использования фаззинга от Дмитрия Вьюкова.

Axiom 1. Untested code contains bugs.

Corollary 1. If only few basic scenarios are tested, that’s all that works.

Corollary 2. Fuzzing/sanitizing always finds bugs.

Corollary 3. If absence of bugs wasn’t proactively ensured, there are bugs.#winrar

Axiom 2. Bugs don’t die of old age.

Corollary 4. Waiting is not a strategy.

Он как раз обращает внимание на то, что с помощью фаззинга можно обнаружить большое количество ошибок в коде, которые в противном случае никуда не исчезнут даже по прошествии времени.

Обычно фаззингом завершают процесс разработки, но фаззить можно и отдельные функции разрабатываемого продукта.

Преимущества фаззинга перед другими методами тестирования:

Одним из нашумевших случаев, когда фаззинг сделал своё доброе дело, можно назвать обнаружение пятидесяти CVE в Adobe Reader за 50 дней. Исследователи смогли найти такое количество уязвимостей, не имея доступа к исходному коду, и трудно предположить, сколько их обнаружилось бы, будь у них исходники.

Если поискать в открытых источниках информацию на тему использования фаззинга среди разработчиков, то первым попадется Microsoft. Эта компания — одна из пионеров фаззинга в SDLC. У них есть Security Risk Detection — сервис, позволяющий пользователям загружать бинарные файлы для их фаззинга. То, какие данные будут подаваться на вход, решает пользователь. Итогом работы фаззера являются найденные ошибки и данные, которые их породили.

Google тоже использует фаззинг, и у них есть очень много инструментов в открытом доступе. Наиболее интересный из них — OSS-Fuzz. Его суть в том, что любой человек может сделать пулл реквест со своим фаззером. Обычно это фаззеры, когда-то созданные разработчиками для своих небольших проектов. Помимо этих фаззеров, Google использует ClusterFuzz для обнаружения ошибок в Chrome. За несколько лет было обнаружено более 16 тысяч уязвимостей в браузере и более 11 тысяч в 160 опенсурсных проектах.

Некоторые компании, разрабатывающие софт, предоставляют всем желающим ночные сборки для фаззинга. Так делает Mozilla и VLC. Любой желающий может скачать сборку и попробовать поискать в ней ошибки и уязвимости.

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

Вопросы мы задали следующие:

Используете ли вы fuzzing в процессе разработки своих продуктов?

На этот вопрос положительно ответила треть респондентов.

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

Если не используете, то почему? Или что, на ваш взгляд, обычно останавливает от включения этапа fuzzing в процесс разработки продукта?

Возможные варианты ответа:

Респонденты могли выбрать сразу несколько причин отказа от использования фаззинга в процессе разработки.

На диаграмме показано процентное соотношение актуальности причин отказа от фаззинга в процессе разработки.

что такое фаззинг тестирование. Смотреть фото что такое фаззинг тестирование. Смотреть картинку что такое фаззинг тестирование. Картинка про что такое фаззинг тестирование. Фото что такое фаззинг тестирование

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

Некоторые из опрошенных, выбравшие вариант ответа «Другое», дали интересные развернутые ответы. Вот некоторые из причин отказа от фаззинга:

Среди ответов были и уточнения о том, что используются AFL-фаззеры и libfuzzer-ы, что не может не радовать.

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

Источник

Фаззинг, фаззить, фаззер: ищем уязвимости в программах, сетевых сервисах, драйверах

Содержание статьи

Каждый год в Канаде на конференции CanSecWest проходит конкурс PWN2OWN по
поиску багов с современных ОС и браузерах. За каждый успешный сплойт
предлагается серьезное вознаграждение. И каждый год от участников, имеющих
готовые решения, нет отбоя. Для поиска критических уязвимостей в столь
популярном софте есть много техник и ноу-хау, но большинство из них строятся на
такой простой технике как фаззинг.

Термин Fuzzing появился еще в 1988 году в работе «The Fuzz Generator»,
опубликованной Бартом Миллером. Именно в эту светлую голову впервые пришла идея
подсовывать программе заведомо некорректные и зачастую вообще случайные данные,
отлавливая ситуации, когда та не сможет их обработать и вылетит. Эффективность
такого подхода до сих пор велика. Точки ввода данных в программу могут быть
самые разные: текстовая строка, введенная через графический интерфейс, бинарные
данные из файла или, например, значение поля в каком-нибудь сетевом запросе.
Вместо программы может быть драйвер, ActiveX-компонент или, например,
SWF-приложение. В той или иной мере фаззинг сейчас является одним из наиболее
эффективных средств выявления проблем безопасности кода.

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

В зависимости от того, где осуществляется манипуляции с данными, фаззинг
разделяется на множество категорий. Один из самых простых видов — файловый
фаззинг, подразумевающий, что некой программе предлагается открыть некорректно
составленный файл. Возьмем, к примеру, прогу для просмотра картинок. Если взять
JPEG-файл и интересным образом поменять несколько байтов, то эта программа
вполне возможно выругается: «Что это ты мне подсунул?». А, возможно, вообще не
сможет его переварить и вылетит, к примеру, с проблемой переполнения
буфера. Значит, ее теоретически можно расковырять, доведя дело до рабочего
эксплойта.

Если говорить о способе манипуляции с данными, то фаззинг распределяется на
генерацию и мутацию. Генерация — это случайным образом придуманный набор байтов,
который подсовывается той же проге для просмотра картинок со словами: «Это на
самом деле JPEG-файл, читай его». Мутация — прием намного более изящный,
подразумевающий внесение изменений в «хороший», то есть вполне корректный файл.
Если в случае с файловым фаззингом еще можно использовать «генерацию», то в
таких вещах, как сетевые протоколы, имеет смысл применять исключительно подход
мутации. Более того, крайне желательно иметь представление, за что отвечает то
или иное поле пакета и намеренно манипулировать с теми данными, которые могут
быть некорректно обработаны. В зависимости от интеллекта, фаззеры бывают глупые
и умные:

Фаззим файлы

Одна из простейших утилит для реализации глупого фаззинга —

MiniFuzz. Проект разработан внутри Microsoft для тестирования своих
собственных проектов. Дело в том, что использование фаззеров является
обязательным этапом методологии SDL (Security
Development Lifecycle), принятой в Microsoft для разработчиков безопасного
кода, включающей помимо прочего обильное fuzz-тестирование. Minifuzz можно
натравить на любое приложение; главное, чтобы в качестве параметра для запуска
оно воспринимало указание на файл, который ему необходимо открыть (скажем,
winword.exe test_sample.doc). Для начала работы необходимо набрать несколько
образцов «правильных» файлов и положить их каталог, обозначенный как Template
files, а также выбрать приложение для проверки, указав формат параметров для его
запуска. Когда ты нажмешь на кнопку Start Fuzzing, программа возьмет один из
образцов, изменит некоторые байты внутри него (количество изменяемых данных
зависит от параметра Aggressiveness) и скормит его исследуемому приложению. Если
тестируемая программа не вылетит через некоторый таймаут (по умолчанию 2
секунды), значит, тест пройден успешно.

Фаззим протоколы

Если MiniFuzz — это очень простой (хотя и эффективный)
dump-фаззер, то проект Peach
(в переводе — персик), разработанный Майком Эддингтоном — это уже мощное решение
для smart-фаззинга, поддерживающее как режим мутации, так и генерации. Для
проведения умного фаззинга программе необходимо знать структуру данных, с
которыми она будет экспериментировать. Поэтому на вход фаззера подаются так
называемые PeachPit’ы («косточки от персика») — специальные XML-конфиги, в
которых задается структура данных, описание взаимоотношений между различными ее
элементами, а также подходы для реализации мутаций. В отличие от Minifuzz, Peach
может фаззить не только файлы, но и сетевые сервисы, RPC, COM/DCOM, SQL-хранимые
процедуры и многое другое. Правда, такая универсальность приводит и к некоторым
трудностям в использовании.

Сразу предупреждаю: это не та программа, которую запускаешь и
сразу понимаешь, что к чему. Чтобы внести ясность, предлагаю разобраться с Peach
на конкретном примере, но вместо фаззинга файлов обратиться к другой области, а
именно — поиску уязвимостей в сетевых сервисах. Для успеха придется
дополнительно установить WinDBG в качестве отладчика, а также снифер Wireshark и
драйвер Winpcap, чтобы иметь возможность перехватывать сетевые пакеты во время
фаззинга сетевых протоколов.

Любой фаззинг в Peach’е начинается с создания PeachPit. Как я
уже сказал, в этом XML-файле определяется цель фаззинга, описывается структура
данных, с которой будет работать фаззер, а также определяются правила
манипуляции с ними. Для удобства автор фреймворка предлагает библиотеку для
Visual Studio, серьезно упрощающую работу с PeachPit’ами, в том числе с помощью
автодополнения кода. Любая «косточка» состоит из нескольких функциональных
блоков. Чтобы не составлять весь файл с нуля, в корневом каталоге фаззера есть
файл-шаблон template.xml, который мы и возьмем за основу.

Важная часть любого PeachPit’а — описание модели данных. Именно
в этом месте мы делаем фаззер «умным», рассказываем ему о структуре файле или
протокола (размерах полей, смещениях и т.д.), с которым предстоит работать.
Возьмем для примера простейший протокол TFTP и попробуем профаззить запрос на
чтение файла (Read). Если верить RFC, то выглядит он следующим образом:

Получается, что запрос начинается с HEX-символов «\x00\x01»,
после которых следует название файла и флаги режима передачи файла. При этом
после полей Filename и Mode идут нулевые байты. Итак, задача — написать фаззер,
который будет играться со значением Filename. Начнем с создания модели запроса в
нашем PeachPit’е в соответствии с RFC:

В первой строке модели мы задаем двухбайтный код, обозначающий
запрос на чтение. Указанный здесь параметр token=»true» мы будем использовать
каждый раз, чтобы дать понять Peach, что это поле остается как есть, и его не
нужно фаззить. Обрати внимание, что в следующей строке, которая описывает поле
filename, этого флага как раз нет, и именно поэтому фаззер будет манипулировать
со значением в этом поле (или, другими словами, фаззить). В последней строке
описывается поле, обозначающее режим работы. Для полей «filename» и «mode» мы
подставляем флаг nullTerminated, указывая на то, что после них идут нулевые
байты-разделители. Обрати внимание, что для каждого из трех полей указывается
его тип (blob или string). Таким образом мы рассказываем фаззеру, с каким типом
данных он будет иметь дело. Понятно, что это очень простая модель, в большинстве
случаев с ее составлением придется поработать намного плотнее.

После того, как модель данных готова, необходимо описать логику
работы фаззера, которая описывается в следующем блоке PeachPit’а. Поскольку
единственное место, где мы будем осуществлять фаззинг — это поле filename, то и
логика нас будет очень простая. Укажем Peach’у, что необходимо отправлять данные
(Action type=»output»), используя ранее описанную модель данных «tftprrx»:

Следующий блок конфигурации фаззера — описание агентов. Агенты
присоединяют к нужному процессу отладчик и постоянно следят за его состоянием. В
случае вылета приложения из-за ошибки агенты записывают различные детали падения
в логфайл, в том числе и вызвавший сбой запрос (в случае, если речь идет о
снифинге сетевого протокола). Для того, чтобы классифицировать падение (Exploitable,
Probably Exploitable, Probably Not Exploitable, Unknown), разработчик
рекомендует дополнительно к отладчику WinDBG установить плагин
!exploitable.
Обозначим в этом блоке, что будем отслеживать состояние приложения TFTPD32 и
весь UDP-трафик, поступающий на 69 порт (TFTP):

После «publisher» указывается, каким образом будут передаваться
данные. Поскольку TFTP работает по UDP-протоколу, то его мы и используем при
составлении теста. Последний блок, который необходимо изменить в файле-шаблоне —
это блок для запуска фаззера («Run»). Здесь определяется, куда ты хочешь
сохранить логи с результатами и какие тесты хочешь провести:

Составление «косточек» для Peach’а может показаться непростой
задачей, и это действительно так. А как иначе объяснить фаззеру особенности
формата данных и то, каким образом ему эффективнее играться с теми или иными
параметрами? В этом и есть смысл умного фаззинга. С другой стороны, если прямо
сейчас попробовать реализовать другой метод того же протокола TFTP (скажем,
метод write), то сразу осознаешь, что кода потребуется намного меньше — большая
часть XML-конфига уже готова. Специально для проверки корректности PeachPits’ов
в состав фаззера входит специальный скрипт peachvalidator.pyw. Если валидатор
отдаст отмашку на старт фаззера, можно запускать Peach:

Первая команда активирует агентов, а вторая позволяет запустить
фаззер с использованием только что составленного XML-конфига.

Фаззим драйвера

Итак, мы уже разобрались с фаззингом файлов, протоколов — теперь
попробуем использовать фаззинг для поиска ошибок в драйверах. Тут надо понимать,
что драйверы используются не только для управления устройствами, вовсе нет.
Многие программы устанавливают в систему драйвер в качестве посредника для
доступа в более привилегированный режим — Ring0. Прежде всего, это антивирусы и
утилиты, обеспечивающие (по крайней мере, обещающие обеспечить) безопасность
системы. Драйверы, в общем, ничем не отличаются от программы в плане
безопасности: как и везде, большое количество уязвимостей связано с неправильной
обработкой данных, в особенности тех, что поступают в IRP-запросах. I/O request
packets (IRP) — это специальные структуры, использующиеся моделью драйверов
Windows для взаимодействия и обмена данными драйверов друг с другом и самой
системой. Получается, и здесь есть все условия для того, чтобы автоматизировать
поиск уязвимостей. Конечно, инструмент тут нужен совершенно особенный, потому
как обычным фаззерам доступ в недра системы закрыт.

Одна из немногих разработок в этой области —
IOCTL Fuzzer,
которая изначально нацелена на проведение fuzzing-тестов, манипулируя с данными
в IRP-запросах. Программа устанавливает в систему вспомогательный драйвер (не
удивляйся, что подобную активность антивирус посчитает подозрительной), который
перехватывает вызовы NtDeviceIoControlFile, тем самым получая возможность
контролировать все IRP-запросы от любого приложения к драйверам режима ядра. Это
нужно потому, что изначально формат IRP-запроса для конкретного драйвера или
программы неизвестен. А имея на руках перехваченный IRP-запрос, его можно легко
изменить — получается классический фаззинг с помощью мутации. Проспуфенный
IRP-запрос ничем не отличается от оригинального за исключением поля с данными,
которые заполняется фаззером псевдослучайным образом. Поведение фаззера,
лог-файл, названия драйверов для спуфинга и другие параметры задаются с помощью
простейшего XML-конфига, который находится в корне программы. Но прежде чем
рваться в бой, необходима некоторая подготовка.

Из эксперимента с драйверами на рабочей машине ничего хорошего
не выйдет. Если IOCTL Fuzzer удастся нащупать слабое место в каком-нибудь из
драйверов, то система легко улетит в BSOD, а это едва ли прибавит удобства для
идентификации уязвимости :). По этой причине для использования фаззера нам
понадобится отдельная виртуальная машина, к которой мы подключим удаленный
дебаггер ядра. Тут честь и хвала Microsoft, которые не только смогли сделать
толковый отладчик WinDbg, поддерживающий удаленный дебаггинг, но и
распространяют его бесплатно. Взаимодействие между гостевой системой в VMware и
удаленным отладчиком WinDbg осуществляется с помощью именованного канала (named
pipe), который мы сейчас и создадим.

1. Сначала создаем именованный канал в VMware. Для этого
переходим в меню «Settings „p Configuration Editor», нажимаем на кнопку добавить
оборудование («Add»), выбираем «Serial Port», жмем «Next», далее из списка
выбираем тип порта — «Use named pipe» и оставляем дефолтное название для
именованного канала (\\.\pipe\com_1). После этого задаем режим работы «This end
is server. The other end is application» в двух выпадающих полях и напоследок
нажимаем кнопку «Advanced», где активируем опцию «Yiled CPU on poll» (иначе
ничего не заработает).

Осталось реализовать возможность загрузки гостевой системы с
включенным режимом удаленной отладки. Для этого в boot.ini (будем считать, что в
качестве гостевой системы используется Windows XP) необходимо вставить новую
строку для запуска системы, добавив два важных ключа /debugport и /baudrate:

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

Вот теперь можно запускать IOCTL Fuzzer в режиме фаззинга, не
опасаясь BSOD’а на основной системе. Выполняем произвольные манипуляции с
тестируемым ПО до тех пор, пока отладчик не сообщит нам о возникновении
необрабатываемого исключения (это значит, что в обычных условиях, скорее всего,
это закончилось бы аварийным завершением работы системы).

Далее необходимо возобновить выполнение кода на виртуальной
машине (в случае с WinDbg надо просто нажать F5), после чего ОС, работающая на
виртуальной машине, запишет аварийный дамп (crash dump) на диск. Готово: теперь
у нас есть подробные логи, дамп и сам запрос, который привел к падению. Дело за
малым — понять, как это можно эксплуатировать :).

А как же веб-фаззеры?

Я намеренно не стал упоминать в рамках этой статьи так
называемые web-based фаззеры, которые работают на уровне HTTP и заваливают
веб-сервер специально составленными запросами в поиске ошибок веб-приложения.
Такая опция есть в каждом втором сканере веб-безопасности, которые мы не так
давно рассматривали в рамках цикла «Инструменты
пентестера». Если говорить об универсальных платформах для создания фаззеров,
то грех не вспомнить о фреймворке
Sulley,
представленном на Blackhat’е в 2007 году. К сожалению, с тех самых пор он и не
развивается, но несмотря на это остается эффективным решением.

Каждый отдельный фаззер с его помощью конструируется отдельно,
но в отличие от Peach, где все описывается декларативно в XML-файле, здесь тебе
придется написать немного кода на Python. Есть еще один популярный конструктор
фаззеров — проект

SPIKE, но подружиться с ним смогут только те, кто хорошо знает язык C.
Помимо этого можно было долго говорить о фаззерах для поиска уязвимостей в
ActiveX, COM-объектах и где угодно еще. Но это не главное. Важно понять, что во
многих местах поиск уязвимостей можно автоматизировать: именно с помощью
фаззинга находится большое количество багов в современных браузерах и смежных с
ними продуктов. А если есть понимание того, где может быть выявлена ошибка и как
ее искать, то фаззер уже несложно написать самому или подобрать готовое решение.

WARNING

Информация представлена в ознакомительных целях. Использование
ее для противозаконных действий может обернуться уголовным преследованием. Ни
автор, ни редакция за такие последствия ответственности не несут.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *