WinAFL на практике. Учимся работать фаззером и искать дыры в софте - «Новости» » Самоучитель CSS
Меню
Наши новости
Учебник CSS

Невозможно отучить людей изучать самые ненужные предметы.

Введение в CSS
Преимущества стилей
Добавления стилей
Типы носителей
Базовый синтаксис
Значения стилевых свойств
Селекторы тегов
Классы
CSS3

Надо знать обо всем понемножку, но все о немногом.

Идентификаторы
Контекстные селекторы
Соседние селекторы
Дочерние селекторы
Селекторы атрибутов
Универсальный селектор
Псевдоклассы
Псевдоэлементы

Кто умеет, тот делает. Кто не умеет, тот учит. Кто не умеет учить - становится деканом. (Т. Мартин)

Группирование
Наследование
Каскадирование
Валидация
Идентификаторы и классы
Написание эффективного кода

Самоучитель CSS

Вёрстка
Изображения
Текст
Цвет
Линии и рамки
Углы
Списки
Ссылки
Дизайны сайтов
Формы
Таблицы
CSS3
HTML5

Новости

Блог для вебмастеров
Новости мира Интернет
Сайтостроение
Ремонт и советы
Все новости

Справочник CSS

Справочник от А до Я
HTML, CSS, JavaScript

Афоризмы

Афоризмы о учёбе
Статьи об афоризмах
Все Афоризмы

Видео Уроки


Наш опрос



Наши новости

       
12-11-2021, 00:02
WinAFL на практике. Учимся работать фаззером и искать дыры в софте - «Новости»
Рейтинг:
Категория: Новости

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

«Luke, I am your fuzzer. Авто­мати­зиру­ем поиск уяз­вимос­тей в прог­раммах»


Так­же по теме фаз­зинга рекомен­дуем сле­дующие статьи:



  • «Фаз­зинг гла­зами прог­раммис­та. Как в Google авто­мати­зиру­ют поиск багов»

  • «Рас­пуши пин­гви­на! Раз­бира­ем спо­собы фаз­зинга ядра Linux»


Так же как и AFL, WinAFL собира­ет информа­цию о пок­рытии кода. Делать это он может тре­мя спо­соба­ми:



  • ди­нами­чес­кая инс­тру­мен­тация с помощью DynamoRIO;

  • ста­тичес­кая инс­тру­мен­тация с помощью Syzygy;

  • трей­синг с помощью IntelPT.


Мы оста­новим­ся на клас­сичес­ком пер­вом вари­анте как самом прос­том и понят­ном.


Фаз­зит WinAFL сле­дующим обра­зом:



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

  2. WinAFL инжектит­ся в прог­рамму и ждет, пока не нач­нет выпол­нятся целевая фун­кция.

  3. WinAFL начина­ет записы­вать информа­цию о пок­рытии кода.

  4. Во вре­мя выхода из целевой фун­кции WinAFL при­оста­нав­лива­ет работу прог­раммы, под­меня­ет вход­ной файл, переза­писы­вает RIP/EIP адре­сом начала фун­кции и про­дол­жает работу.

  5. Ког­да чис­ло таких ите­раций дос­тигнет некото­рого мак­сималь­ного зна­чения (его ты опре­деля­ешь сам), WinAFL пол­ностью переза­пус­кает прог­рамму.


Та­кой под­ход поз­воля­ет не тра­тить лиш­нее вре­мя на запуск и ини­циали­зацию прог­раммы и зна­читель­но уве­личить ско­рость фаз­зинга.


 

Требования к функции


Из логики работы WinAFL вытека­ют прос­тые тре­бова­ния к целевой фун­кции для фаз­зинга. Целевая фун­кция дол­жна:



  1. От­кры­вать вход­ной файл.

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

  3. Вы­пол­нение дол­жно доходить до воз­вра­та из фун­кции, выб­ранной для фаз­зинга.


 

Компиляция WinAFL


В ре­пози­тории WinAFL на GitHub уже лежат ском­пилиро­ван­ные бинари, но у меня они прос­то не захоте­ли работать, поэто­му для того, что­бы не приш­лось раз­бирать­ся с лиш­ними проб­лемами, ском­пилиру­ем WinAFL вмес­те с самой пос­ледней вер­сией DynamoRIO. К счастью, WinAFL отно­сит­ся с тем нем­ногочис­ленным про­ектам, которые ком­пилиру­ются без проб­лем на любой машине.



  1. Ска­чай и уста­нови Visual Studio 2019 Community Edition (при уста­нов­ке выбери пункт «Раз­работ­ка клас­сичес­ких при­ложе­ний на C++».

  2. По­ка у тебя уста­нав­лива­ется Visual Studio, ска­чай пос­ледний релиз DynamoRIO.

  3. Ска­чай исходни­ки WinAFL из ре­пози­тория.

  4. Пос­ле уста­нов­ки Visual Studio в меню «Пуск» у тебя появят­ся ярлы­ки для откры­тия коман­дной стро­ки Visual Studio: x86 Native Tools Command Prompt for VS 2019 и x64 Native Tools Command Prompt for VS 2019. Выбирай в соот­ветс­твии с бит­ностью прог­раммы, которую ты будешь фаз­зить.


  5. В коман­дной стро­ке 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

  6. Пос­ле ком­пиляции в пап­ке build<32/64>binRelease будут лежать рабочие бинари WinAFL. Ско­пируй их и пап­ку с DynamoRIO на вир­туал­ку, которую будешь исполь­зовать для фаз­зинга.



 

Поиск подходящей цели для фаззинга


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


Ес­ли же тебе, как и мне, нра­вит­ся допол­нитель­ный чел­лендж, ты можешь пофаз­зить сетевые прог­раммы. В этом слу­чае тебе при­дет­ся исполь­зовать custom_net_fuzzer.dll из сос­тава WinAFL либо писать свою собс­твен­ную обер­тку.



info


К сожале­нию, custom_net_fuzzer будет работать не так быс­тро, потому что он отправ­ляет сетевые зап­росы сво­ей цели, а на их обра­бот­ку будет тра­тить­ся допол­нитель­ное вре­мя.



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


Та­ким обра­зом:



  • иде­аль­ная цель работа­ет с фай­лами;

  • при­нима­ет путь к фай­лу как аргу­мент коман­дной стро­ки;

  • мо­дуль, содер­жащий фун­кции, который ты хочешь пофаз­зить, дол­жен быть ском­пилиро­ван не ста­тичес­ки. В про­тив­ном слу­чае WinAFL будет инс­тру­мен­тировать мно­гочис­ленные биб­лиотеч­ные фун­кции. Это не при­несет допол­нитель­ного резуль­тата, но силь­но замед­лит фаз­зинг.


Уди­витель­но, но боль­шинс­тво раз­работ­чиков не дума­ют о WinAFL, ког­да пишут свои прог­раммы. Поэто­му если твоя цель не соот­ветс­тву­ет этим кри­тери­ям, то ее все рав­но мож­но при желании адап­тировать к WinAFL.


 

Поиск функции для фаззинга внутри программы


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


У нее мно­го вся­ких воз­можнос­тей, так что, думаю, ее будет инте­рес­но пофаз­зить.


Моя цель при­нима­ет на вход фай­лы, поэто­му пер­вое, что сде­лаем пос­ле заг­рузки бинаря в IDA Pro, — это най­дем фун­кцию CreateFileA в импортах и пос­мотрим перек­рес­тные ссыл­ки на нее.


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


От­кро­ем нашу прог­рамма в отладчи­ке (я обыч­но исполь­зую x64dbg) и добавим аргу­мент к коман­дной стро­ке — тес­товый файл. Отку­да я его взял? Прос­то открыл прог­рамму, выс­тавил мак­сималь­ное чис­ло опций для докумен­та и сох­ранил его на диск.


WinAFL на практике. Учимся работать фаззером и искать дыры в софте - «Новости»

Даль­ше на вклад­ке Symbols выберем биб­лиоте­ку kernelbase.dll и пос­тавим точ­ки оста­нова на экспор­ты фун­кций CreateFileA и CreateFileW.


Один любопыт­ный момент. «Офи­циаль­но» фун­кции CreateFile* пре­дос­тавля­ются биб­лиоте­кой kernel32.dll. Но если пос­мотреть вни­матель­нее, то это биб­лиоте­ка содер­жит толь­ко jmp на соот­ветс­тву­ющие фун­кции kernelbase.dll.


Я пред­почитаю ста­вить брей­ки имен­но на экспор­ты в соот­ветс­тву­ющей биб­лиоте­ке. Это зас­тра­хует нас от слу­чая, ког­да мы ошиб­лись и эти фун­кции вызыва­ет не основной исполня­емый модуль (.exe), а, нап­ример, какие‑то из биб­лиотек нашей целей. Так­же это полез­но, если наша прог­рамма захочет выз­вать фун­кцию с помощью GetProcAddress.


Пос­ле уста­нов­ки брей­кпой­нтов про­дол­жим выпол­нение прог­раммы и уви­дим, как она совер­шает пер­вый вызов к CreateFileA. Но если мы обра­тим вни­мание на аргу­мен­ты, то пой­мем, что наша цель хочет открыть какой‑то из сво­их слу­жеб­ных фай­лов, не наш тес­товый файл.


Про­дол­жим выпол­нение прог­раммы, пока не уви­дим в спис­ке аргу­мен­тов путь к нашему тес­товому фай­лу.


Пе­рей­дем на вклад­ку Call Stack и уви­дим, что CreateFileA вызыва­ется не из нашей прог­раммы, а из фун­кции CFile::Open биб­лиоте­ки mfc42.


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


Ско­пиру­ем адрес воз­вра­та из CFile::Open (125ACBB0), перей­дем по нему в IDA и пос­мотрим на фун­кцию. Мы сра­зу же уви­дим, что эта фун­кция при­нима­ет два аргу­мен­та, которые далее исполь­зуют­ся как аргу­мен­ты к двум вызовам CFile::Open.


Су­дя по про­тоти­пам CFile::Open из докумен­тации MSDN, наши перемен­ные a1 и a2 — это пути к фай­лам. Обра­ти вни­мание, что в IDA путь к фай­лу переда­ется фун­кции CFile::Open в качес­тве вто­рого аргу­мен­та, так как исполь­зует­ся thiscall.


virtualBOOLOpen(
LPCTSTRlpszFileName,
UINTnOpenFlags,
CFileException*pError=NULL);
virtualBOOLOpen(
LPCTSTRlpszFileName,
UINTnOpenFlags,
CAtlTransactionManager*pTM,
CFileException*pError=NULL);

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


Сде­лав это, переза­пус­тим прог­рамму и уви­дим, что два аргу­мен­та — это пути к нашему тес­товому фай­лу и вре­мен­ному фай­лу.


Са­мое вре­мя пос­мотреть на содер­жимое этих фай­лов. Судя по содер­жимому нашего тес­тового фай­ла, он сжат, зашиф­рован или каким‑то обра­зом закоди­рован.


Вре­мен­ный же файл прос­то пуст.


Вы­пол­ним фун­кцию до кон­ца и уви­дим, что наш тес­товый файл все еще зашиф­рован, а вре­мен­ный файл по‑преж­нему пуст. Что ж, уби­раем точ­ки оста­нова с этой фун­кции и про­дол­жаем отсле­живать вызовы CreateFileA. Сле­дующее обра­щение к CreateFileA дает нам такой стек вызовов.


Фун­кция, которая вызыва­ет CFile::Open, ока­зыва­ется очень похожей на пре­дыду­щую. Точ­но так же пос­тавим точ­ки оста­нова в ее начале и кон­це и пос­мотрим, что будет.


Спи­сок аргу­мен­тов этой фун­кции напоми­нает то, что мы уже видели.


Сра­баты­вает брейк в кон­це этой фун­кции, и во вре­мен­ном фай­ле мы видим рас­шифро­ван­ное, а ско­рее даже разар­хивиро­ван­ное содер­жимое тес­тового фай­ла.


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


Пос­мотрим, смо­жем ли мы най­ти фун­кцию, которая выпол­няет какие‑то дей­ствия с уже рас­шифро­ван­ным фай­лом.


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


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


Так­же убе­дим­ся, что эта фун­кция пос­ле воз­вра­та зак­рыва­ет все откры­тые фай­лы. Для это­го про­верим спи­сок хен­длов про­цес­са в Process Explorer — нашего тес­тового фай­ла там нет.


Ви­дим, что наша фун­кция соот­ветс­тву­ет тре­бова­ниям WinAFL. Поп­робу­ем начать фаз­зить!


Фаз­зинг, фаз­зить, фаз­зер: ищем уяз­вимос­ти в прог­раммах, сетевых сер­висах, драй­верах» «Luke, I am your fuzzer. Авто­мати­зиру­ем поиск уяз­вимос­тей в прог­раммах» Так­же по теме фаз­зинга рекомен­дуем сле­дующие статьи: «Фаз­зинг гла­зами прог­раммис­та. Как в Google авто­мати­зиру­ют поиск багов» «Рас­пуши пин­гви­на! Раз­бира­ем спо­собы фаз­зинга ядра Linux» Так же как и AFL, WinAFL собира­ет информа­цию о пок­рытии кода. Делать это он может тре­мя спо­соба­ми: ди­нами­чес­кая инс­тру­мен­тация с помощью DynamoRIO; ста­тичес­кая инс­тру­мен­тация с помощью Syzygy; трей­синг с помощью IntelPT. Мы оста­новим­ся на клас­сичес­ком пер­вом вари­анте как самом прос­том и понят­ном. Фаз­зит WinAFL сле­дующим обра­зом: В качес­тве одно­го из аргу­мен­тов ты дол­жен передать сме­щение так называ­емой целевой фун­кции внут­ри бинаря. WinAFL инжектит­ся в прог­рамму и ждет, пока не нач­нет выпол­нятся целевая фун­кция. WinAFL начина­ет записы­вать информа­цию о пок­рытии кода. Во вре­мя выхода из целевой фун­кции WinAFL при­оста­нав­лива­ет работу прог­раммы, под­меня­ет вход­ной файл, переза­писы­вает RIP/EIP адре­сом начала фун­кции и про­дол­жает работу. Ког­да чис­ло таких ите­раций дос­тигнет некото­рого мак­сималь­ного зна­чения (его ты опре­деля­ешь сам), WinAFL пол­ностью переза­пус­кает прог­рамму. Та­кой под­ход поз­воля­ет не тра­тить лиш­нее вре­мя на запуск и ини­циали­зацию прог­раммы и зна­читель­но уве­личить ско­рость фаз­зинга. Требования к функции Из логики работы WinAFL вытека­ют прос­тые тре­бова­ния к целевой фун­кции для фаз­зинга. Целевая фун­кция дол­жна: От­кры­вать вход­ной файл. Пар­сить файл и завер­шать свою работу мак­сималь­но чис­то: зак­рывать файл и все откры­тые хен­длы, не менять гло­баль­ные перемен­ные и так далее. В реаль­нос­ти не всег­да получа­ется най­ти иде­аль­ную фун­кцию пар­синга, но об этом погово­рим поз­же. Вы­пол­нение дол­жно доходить до воз­вра­та из фун­кции, выб­ранной для фаз­зинга. Компиляция WinAFL В ре­пози­тории WinAFL на GitHub уже лежат ском­пилиро­ван­ные бинари, но у меня они прос­то не захоте­ли работать, поэто­му для того, что­бы не приш­лось раз­бирать­ся с лиш­ними проб­лемами, ском­пилиру­ем WinAFL вмес­те с самой пос­ледней вер­сией DynamoRIO. К счастью, WinAFL отно­сит­ся с тем нем­ногочис­ленным про­ектам, которые ком­пилиру­ются без проб­лем на любой машине. Ска­чай и уста­нови Visual Studio 2019 Community Edition (при уста­нов­ке выбери пункт «Раз­работ­ка клас­сичес­ких при­ложе­ний на C ». По­ка у тебя уста­нав­лива­ется Visual Studio, ска­чай пос­ледний релиз DynamoRIO. Ска­чай исходни­ки WinAFL из ре­пози­тория. Пос­ле уста­нов­ки Visual Studio в меню «Пуск» у тебя появят­ся ярлы­ки для откры­тия коман­дной стро­ки Visual Studio: x86 Native Tools Command Prompt for VS 2019 и x64 Native Tools Command Prompt for VS 2019. Выбирай в соот­ветс­твии с бит­ностью прог­раммы, которую ты будешь фаз­зить. В коман­дной стро­ке Visual Studio перей­ди в пап­ку с исходни­ками WinAFL. Для ком­пиляции 32-бит­ной вер­сии выпол­ни сле­дующие коман­ды: cd build32 cmake -G

Теги: CSS

Просмотров: 514
Комментариев: 0:   12-11-2021, 00:02
Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь. Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

 
Еще новости по теме:



Другие новости по теме: