Невозможно отучить людей изучать самые ненужные предметы.
Введение в CSS
Преимущества стилей
Добавления стилей
Типы носителей
Базовый синтаксис
Значения стилевых свойств
Селекторы тегов
Классы
CSS3
Надо знать обо всем понемножку, но все о немногом.
Идентификаторы
Контекстные селекторы
Соседние селекторы
Дочерние селекторы
Селекторы атрибутов
Универсальный селектор
Псевдоклассы
Псевдоэлементы
Кто умеет, тот делает. Кто не умеет, тот учит. Кто не умеет учить - становится деканом. (Т. Мартин)
Группирование
Наследование
Каскадирование
Валидация
Идентификаторы и классы
Написание эффективного кода
Вёрстка
Изображения
Текст
Цвет
Линии и рамки
Углы
Списки
Ссылки
Дизайны сайтов
Формы
Таблицы
CSS3
HTML5
Блог для вебмастеров
Новости мира Интернет
Сайтостроение
Ремонт и советы
Все новости
Справочник от А до Я
HTML, CSS, JavaScript
Афоризмы о учёбе
Статьи об афоризмах
Все Афоризмы
Помогли мы вам |
Также по теме фаззинга рекомендуем следующие статьи:
Так же как и AFL, WinAFL собирает информацию о покрытии кода. Делать это он может тремя способами:
Мы остановимся на классическом первом варианте как самом простом и понятном.
Фаззит WinAFL следующим образом:
Такой подход позволяет не тратить лишнее время на запуск и инициализацию программы и значительно увеличить скорость фаззинга.
Из логики работы WinAFL вытекают простые требования к целевой функции для фаззинга. Целевая функция должна:
В репозитории WinAFL на GitHub уже лежат скомпилированные бинари, но у меня они просто не захотели работать, поэтому для того, чтобы не пришлось разбираться с лишними проблемами, скомпилируем WinAFL вместе с самой последней версией DynamoRIO. К счастью, WinAFL относится с тем немногочисленным проектам, которые компилируются без проблем на любой машине.
В командной строке Visual Studio перейди в папку с исходниками WinAFL.
Для компиляции 32-битной версии выполни следующие команды:
cdbuild32cmake-G"Visual Studio 16 2019"-AWin32..-DDynamoRIO_DIR=..pathtoDynamoRIOcmake-DINTELPT=0-DUSE_COLOR=1cmake--build.--configRelease
Для компиляции 64-битной версии — такие:
cdbuild64cmake-G"Visual Studio 16 2019"-Ax64..-DDynamoRIO_DIR=..pathtoDynamoRIOcmake-DINTELPT=0-DUSE_COLOR=1cmake--build.--configRelease
В моем случае эти команды выглядят так:
mkdirbuild32cdbuild32cmake-G"Visual Studio 16 2019"-AWin32..-DDynamoRIO_DIR=C:winafl_buildDynamoRIO-Windows-8.0.18915cmake-DINTELPT=0-DUSE_COLOR=1cmake--build.--configRelease
После компиляции в папке build<32/64>binRelease
будут лежать рабочие бинари WinAFL. Скопируй их и папку с DynamoRIO на виртуалку, которую будешь использовать для фаззинга.
AFL создавался для фаззинга программ, которые парсят файлы. Хотя WinAFL можно применять для программ, использующих другие способы ввода, путь наименьшего сопротивления — это выбор цели, использующей именно файлы.
Если же тебе, как и мне, нравится дополнительный челлендж, ты можешь пофаззить сетевые программы. В этом случае тебе придется использовать custom_net_fuzzer.
из состава WinAFL либо писать свою собственную обертку.
К сожалению, custom_net_fuzzer
будет работать не так быстро, потому что он отправляет сетевые запросы своей цели, а на их обработку будет тратиться дополнительное время.
Однако фаззинг сетевых приложений выходит за рамки этой статьи. Оставь комментарий, если хочешь отдельную статью на эту тему.
Таким образом:
Удивительно, но большинство разработчиков не думают о WinAFL, когда пишут свои программы. Поэтому если твоя цель не соответствует этим критериям, то ее все равно можно при желании адаптировать к WinAFL.
Мы поговорили об идеальной цели, но реальная может быть от идеала далека, поэтому для примера я взял программу из старых запасов, которая собрана статически, а ее основной исполняемый файл занимает 8 Мбайт.
У нее много всяких возможностей, так что, думаю, ее будет интересно пофаззить.
Моя цель принимает на вход файлы, поэтому первое, что сделаем после загрузки бинаря в IDA Pro, — это найдем функцию CreateFileA
в импортах и посмотрим перекрестные ссылки на нее.
Мы сразу же можем увидеть, что она используется в четырех функциях. Вместо того чтобы реверсить каждую из них в статике, посмотрим в отладчике, какая именно функция вызывается для парсинга файла.
Откроем нашу программа в отладчике (я обычно использую x64dbg) и добавим аргумент к командной строке — тестовый файл. Откуда я его взял? Просто открыл программу, выставил максимальное число опций для документа и сохранил его на диск.
Дальше на вкладке Symbols выберем библиотеку kernelbase.dll и поставим точки останова на экспорты функций CreateFileA
и CreateFileW
.
Один любопытный момент. «Официально» функции CreateFile*
предоставляются библиотекой kernel32.dll. Но если посмотреть внимательнее, то это библиотека содержит только jmp на соответствующие функции kernelbase.dll.
Я предпочитаю ставить брейки именно на экспорты в соответствующей библиотеке. Это застрахует нас от случая, когда мы ошиблись и эти функции вызывает не основной исполняемый модуль (.exe), а, например, какие‑то из библиотек нашей целей. Также это полезно, если наша программа захочет вызвать функцию с помощью GetProcAddress
.
После установки брейкпойнтов продолжим выполнение программы и увидим, как она совершает первый вызов к CreateFileA
. Но если мы обратим внимание на аргументы, то поймем, что наша цель хочет открыть какой‑то из своих служебных файлов, не наш тестовый файл.
Продолжим выполнение программы, пока не увидим в списке аргументов путь к нашему тестовому файлу.
Перейдем на вкладку Call Stack и увидим, что CreateFileA
вызывается не из нашей программы, а из функции CFile::
библиотеки mfc42.
Так как мы только ищем функцию для фаззинга, нам нужно помнить, что она должна принимать путь к входному файлу, делать что‑то с файлом и завершать свою работу настолько чисто, насколько это возможно. Поэтому мы будем подниматься по стеку вызовов, пока не найдем подходящую функцию.
Скопируем адрес возврата из CFile::
, перейдем по нему в IDA и посмотрим на функцию. Мы сразу же увидим, что эта функция принимает два аргумента, которые далее используются как аргументы к двум вызовам CFile::
.
Судя по прототипам CFile::
из документации MSDN, наши переменные a1
и a2
— это пути к файлам. Обрати внимание, что в IDA путь к файлу передается функции CFile::
в качестве второго аргумента, так как используется thiscall
.
virtualBOOLOpen(
LPCTSTRlpszFileName,
UINTnOpenFlags,
CFileException*pError=NULL);
virtualBOOLOpen(
LPCTSTRlpszFileName,
UINTnOpenFlags,
CAtlTransactionManager*pTM,
CFileException*pError=NULL);
Эта функция уже выглядит очень интересно, и стоит постараться рассмотреть ее подробнее. Для этого я поставлю брейки на начало и конец функции, чтобы изучить ее аргументы и понять, что с ними происходит к концу функции.
Сделав это, перезапустим программу и увидим, что два аргумента — это пути к нашему тестовому файлу и временному файлу.
Самое время посмотреть на содержимое этих файлов. Судя по содержимому нашего тестового файла, он сжат, зашифрован или каким‑то образом закодирован.
Временный же файл просто пуст.
Выполним функцию до конца и увидим, что наш тестовый файл все еще зашифрован, а временный файл по‑прежнему пуст. Что ж, убираем точки останова с этой функции и продолжаем отслеживать вызовы CreateFileA
. Следующее обращение к CreateFileA
дает нам такой стек вызовов.
Функция, которая вызывает CFile::
, оказывается очень похожей на предыдущую. Точно так же поставим точки останова в ее начале и конце и посмотрим, что будет.
Список аргументов этой функции напоминает то, что мы уже видели.
Срабатывает брейк в конце этой функции, и во временном файле мы видим расшифрованное, а скорее даже разархивированное содержимое тестового файла.
Таким образом, эта функция разархивирует файл. Поэкспериментировав с программой, я выяснил, что она принимает на вход как сжатые, так и несжатые файлы. Нам это на руку — с помощь фаззинга несжатых файлов мы сможем добиться гораздо более полного покрытия кода и, как следствие, добраться до более интересных фич.
Посмотрим, сможем ли мы найти функцию, которая выполняет какие‑то действия с уже расшифрованным файлом.
Один из подходов к выбору функции для фаззинга — это поиск функции, которая одной из первых начинает взаимодействовать с входным файлом. Двигаясь вверх по стеку вызовов, найдем самую первую функцию, которая принимает на вход путь к тестовому файлу.
Функция для фаззинга должна выполняться до конца, поэтому ставим точку останова на конец функции, чтобы быть уверенными, что это требование выполнится, и жмем F9 в отладчике.
Также убедимся, что эта функция после возврата закрывает все открытые файлы. Для этого проверим список хендлов процесса в Process Explorer — нашего тестового файла там нет.
Видим, что наша функция соответствует требованиям WinAFL. Попробуем начать фаззить!
|
|