Не Useless Crap. Качаем скилл бинарной эксплуатации на сложной задаче с CTF - «Новости» » Самоучитель CSS
Меню
Наши новости
Учебник CSS

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

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

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

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

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

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

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

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

Новости

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

Справочник CSS

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

Афоризмы

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

Видео Уроки


Видео уроки
Наш опрос



Наши новости

       
18-05-2020, 16:40
Не Useless Crap. Качаем скилл бинарной эксплуатации на сложной задаче с CTF - «Новости»
Рейтинг:
Категория: Новости

PWN — одна из наиболее самодостаточных категорий тасков на CTF-соревнованиях. Такие задания быстро готовят к анализу кода в боевых условиях, а райтапы по ним чаще всего описывают каждую деталь, даже если она уже была многократно описана. Мы рассмотрим таск Useless Crap с апрельского TG:HACK 2020. Сам автор оценил его сложность как Hard. Задание очень интересное, во время соревнования я потратил на него около двенадцати часов.

Подготовка



Для начала расскажу об инструментах, которые я использовал.



Я предпочел не выбирать однозначно между IDA и Ghidra и использую один или другой дизассемблер в зависимости от ситуации, но в тасках категории PWN хороший псевдокод чаще выдает IDA.



«Ванильный» GDB невозможно использовать без очень серьезной психологической подготовки, так что чаще всего его юзают в сочетании с одним из плагинов: PEDA, GEF или pwndbg. Из них PEDA — самый старый (классический!) вариант, но я до сих пор не переехал на один из новых, так что использую его.



Также, пока весь мир полностью переезжает на Python 3, разработчики эксплоитов и не думают о том, чтобы покидать любимый Python 2. Дело в очень неприятной обработке raw bytes в третьей ветке Python, приходится постоянно держать в голове ее особенности и тратить лишнее время на исправление возникающих багов.



Полезные дополнительные инструменты:



  • pwntools как самый удобный API на Python для взаимодействия с исполняемыми файлами;

  • checksec — для определения защитных механизмов бинарника;

  • patchelf как инструмент для патчинга libc и исполняемых файлов.


Первоначальный осмотр



Не Useless Crap. Качаем скилл бинарной эксплуатации на сложной задаче с CTF - «Новости»


Итак, организаторы дали нам бинарник и файлы серверной libc и линковщика. Также точно указан путь до флага; опытные игроки в CTF сразу могут предположить, что придется писать свой шелл-код.



Очевидно, самое первое, что нужно сделать, — это просто выполнить бинарник и примерно оценить сложность, быстренько просмотрев security mitigations в checksec.



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



patchelf --set-interpreter ld-2.31.so ./crap
LD_PRELOAD=./libc-2.31.so ./crap




Нас встречает незамысловатая менюшка, появляется надежда на быстрое и простое решение. Живет эта надежда, правда, недолго, примерно до открытия checksec.





У нас включены на максимум все защитные механизмы. Вот их краткое описание.



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



Stack canary — определенное секретное значение на стеке, записанное перед RBP и return pointer и, таким образом, защищающее их от перезаписи через уязвимость переполнения буфера.



Full RELRO — делает сегмент GOT доступным только для чтения и размещает его перед сегментом BSS. Техники эксплуатации через перезапись GOT не сложны, но выходят за рамки этой статьи, так что предлагаю читателю самому разобраться с ними. О том, что такое Global Offset Table, можно прочитать, например, в Википедии.


Как работают ASLR и PIE?



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



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



  • последние три ниббла («полубайта») этого адреса должны быть равны 000;

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

Главная проблема атакующего в том, что это действительно работает. Можно взять конкретный пример: нужно найти адрес функции system в libc, при этом никакой информации о нем не известно. Давай примерно представим, сколько времени на это понадобится. Первый байт любого адреса библиотеки почти обязан быть равен 0x7f. Последние три ниббла мы знаем, так как независимо от выбора базового адреса они остаются теми же при каждом запуске программы. Достаточно несложная школьная задачка по комбинаторике:



2^8 * 2^8 * 2^8 * 2^4 = 2^28 = 268435456
[/code]

Это примерная оценка, так как не учитывается определенное количество адресов вверху диапазона, которые брать нельзя, иначе остальной регион памяти тогда не уместится; тем не менее она достаточно точная. Допустим, на каждый запуск эксплоита в среднем мы тратим три секунды. Тогда полный перебор займет примерно 25 лет, что нас явно не устраивает, ведь CTF идет всего 48 часов.



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



Реверс-инжиниринг программы



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





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



Рассмотрим функции по порядку.



1. init





Здесь нет ничего по-настоящему интересного, просто отключается буферизация ввода и вывода и устанавливается время работы программы (после 0x3c секунд произойдет прыжок на handler, функцию, которая состоит РёР· РѕРґРЅРѕР№ строки: exit(0);).



2. sandbox





Эта функция намного интереснее предыдущей: оказывается, в программе достаточно жестко настроен seccomp. Давай разберемся, какие системные вызовы разрешены. Найти таблицу соответствий названий сисколлов с их номерами не представляет труда.



Итак, абсолютно точно разрешены exit, mprotect, open Рё close. Немного, но уже становится понятен финальный этап эксплуатации: нужно будет сделать один из регионов памяти доступным для чтения, записи и исполнения, записать туда шелл-код на чтение файла с флагом и прыгнуть на него.





Также доступны системные вызовы read Рё write, но не полностью. IDA не показывает аргументы seccomp_rule_add после четвертого, Р° ведь основные правила настройки для заданных сисколлов именно там. Нажав правой РєРЅРѕРїРєРѕР№ мыши РЅР° название функции, можно выбрать опцию Set call type Рё, таким образом, дописать еще несколько __int64, чтобы увидеть больше аргументов.





По опыту работы с seccomp могу сказать, что IDA не совсем правильно определила седьмой аргумент, который равен SCMP_CMP_EQ (это 4), РЅРѕ становится СЏСЃРЅРѕ, что программа может читать только РёР· нулевого дескриптора (stdin), а писать только в первый дескриптор (stdout). РџРѕРєР° что РЅРµ совсем понятно, как тогда написать шелл-РєРѕРґ, ведь читать нужно РІ любом случае РёР· дескриптора открытого файла, который точно РЅРµ равен нулю. РќРѕ РѕР± этом позже.



 

3. menu





Это меню, которое выводится каждую итерацию цикла в main.



 

4. get_num





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



 

5. do_read





Автор таска предоставляет нам чистый arbitrary read. РќРµ РјРѕРіСѓ сказать, что это очень редкое Рё уникальное решение, РЅРѕ такие задания чаще всего крайне интересны. РњС‹ можем прочитать что СѓРіРѕРґРЅРѕ откуда СѓРіРѕРґРЅРѕ РЅРµ более РґРІСѓС… раз, РїРѕ крайней мере так будет считать программа. Переменная read_count глобальная, а значит, хранится не на стеке, а в BSS. В дальнейшем понимание этого может облегчить эксплуатацию.



6. do_write





Похожим образом работает do_write. РЈ нас появляется возможность записывать что СѓРіРѕРґРЅРѕ РєСѓРґР° СѓРіРѕРґРЅРѕ, РїРѕРєР° write_count меньше единицы или равен ей. Сразу можно придумать обход механизма проверки: после каждой записи через следующий do_write присваивать write_count значение -1, таким образом получить полный, ничем РЅРµ ограниченный arbitrary write Рё схожим образом arbitrary read.



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



 

7. leave_feedback





При выборе третьей опции меню вместо незамедлительного выхода программа попросит оставить обратную связь. Это происходит следующим образом:



проверяется, равен ли нулю глобальный указатель feedback;
если нет, то программа аллоцирует чанк размером 0x501 и даст нам непосредственный ввод в него;
затем пользователя спрашивают: хочет ли он, чтобы его фидбек был сохранен;
если он введет n, то чанк будет освобожден, но указатель feedback не обнулится.

Пока что эта ошибка некритична, но в дальнейшем может быть очень полезна.





Чтобы вызвать эту функцию, нужно ввести цифру 4, упоминания Рѕ которой нет РІ меню. Функция view_feedback выводит то, что находится по указателю feedback, не проверяя состояние чанка, который может быть освобожден. Такой тип уязвимостей называется Use-After-Free. Подразумевается, что по адресу указателя должен лежать пользовательский ввод, но чуть позже мы увидим, что для освобожденных чанков это не всегда так.



PWN — одна из наиболее самодостаточных категорий тасков на CTF-соревнованиях. Такие задания быстро готовят к анализу кода в боевых условиях, а райтапы по ним чаще всего описывают каждую деталь, даже если она уже была многократно описана. Мы рассмотрим таск Useless Crap с апрельского TG:HACK 2020. Сам автор оценил его сложность как Hard. Задание очень интересное, во время соревнования я потратил на него около двенадцати часов. Подготовка Для начала расскажу об инструментах, которые я использовал. Я предпочел не выбирать однозначно между IDA и Ghidra и использую один или другой дизассемблер в зависимости от ситуации, но в тасках категории PWN хороший псевдокод чаще выдает IDA. «Ванильный» GDB невозможно использовать без очень серьезной психологической подготовки, так что чаще всего его юзают в сочетании с одним из плагинов: PEDA, GEF или pwndbg. Из них PEDA — самый старый (классический!) вариант, но я до сих пор не переехал на один из новых, так что использую его. Также, пока весь мир полностью переезжает на Python 3, разработчики эксплоитов и не думают о том, чтобы покидать любимый Python 2. Дело в очень неприятной обработке raw bytes в третьей ветке Python, приходится постоянно держать в голове ее особенности и тратить лишнее время на исправление возникающих багов. Полезные дополнительные инструменты: pwntools как самый удобный API на Python для взаимодействия с исполняемыми файлами; checksec — для определения защитных механизмов бинарника; patchelf как инструмент для патчинга libc и исполняемых файлов. Первоначальный осмотр Итак, организаторы дали нам бинарник и файлы серверной libc и линковщика. Также точно указан путь до флага; опытные игроки в CTF сразу могут предположить, что придется писать свой шелл-код. Очевидно, самое первое, что нужно сделать, — это просто выполнить бинарник и примерно оценить сложность, быстренько просмотрев security mitigations в checksec. Чтобы исполняемый файл использовал нужную libc, пропатчим в нем путь до линкера и укажем ее в переменной окружения LD_PRELOAD. patchelf --set-interpreter ld-2.31.so ./crap LD_PRELOAD=./libc-2.31.so ./crap Нас встречает незамысловатая менюшка, появляется надежда на быстрое и простое решение. Живет эта надежда, правда, недолго, примерно до открытия checksec. У нас включены на максимум все защитные механизмы. Вот их краткое описание. NX — делает стек неисполняемым. Около двадцати лет назад большинство уязвимостей переполнения буфера эксплуатировали запись шелл-кода на стек с последующим прыжком на него. NX делает такую технику невозможной, однако сейчас она еще жива в мире IoT. Stack canary — определенное секретное значение на стеке, записанное перед RBP и return pointer и, таким образом, защищающее их от перезаписи через уязвимость переполнения буфера. Full RELRO — делает сегмент GOT доступным только для чтения и размещает его перед сегментом BSS. Техники эксплуатации через перезапись GOT не сложны, но выходят за рамки этой статьи, так что предлагаю читателю самому разобраться с ними. О том, что такое Global Offset Table, можно прочитать, например, в Википедии. Как работают ASLR и PIE? ASLR — это защитный механизм, который значительно усложняет эксплуатацию. Его основная задача — рандомизация базовых адресов всех регионов памяти, кроме секций, принадлежащих самому бинарнику. По сути, ASLR работает следующим образом. В диапазоне адресов, который на несколько порядков превышает размер рандомизируемого региона памяти, выбирается начальная точка отсчета, базовый адрес. К нему есть два требования: последние три ниббла («полубайта») этого адреса должны быть равны 000; весь рандомизированный регион не должен конфликтовать с другими регионами и выходить за рамки предложенного диапазона. Главная проблема атакующего в том, что это действительно работает. Можно взять конкретный пример: нужно найти адрес функции system в libc, при этом никакой информации о нем не известно. Давай примерно представим, сколько времени на это понадобится. Первый байт любого адреса библиотеки почти обязан быть равен 0x7f. Последние три ниббла мы знаем, так как независимо от выбора базового адреса они остаются теми же при каждом запуске программы. Достаточно несложная школьная задачка по комбинаторике: 2^8 * 2^8 * 2^8 * 2^4 = 2^28 = 268435456 _

Теги: CSS

Просмотров: 355
Комментариев: 0:   18-05-2020, 16:40
Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь. Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

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



Другие новости по теме:
Комментарии для сайта Cackle