Содержание статьи
В статье «Разбираем V8» я описывал способ эксплуатации намеренной уязвимости в движке V8. Она позволила получить шелл, но, чтобы продвинуться дальше и получить флаг юзера, требуется решить новую сложную задачу — проэксплуатировать уязвимости работы с памятью.
Разведка
Первым делом подключаемся к тачке по SSH и запускаем скрипт поиска уязвимостей для эскалации привилегий. Лично я предпочитаю использовать LinPEAS.
artex@kali:/home/artex/HTB/RopeTwo# ssh -i key chromeuser@10.10.10.196
artex@kali:/home/artex/HTB/RopeTwo# scp -i ssh/key linpeas.sh chromeuser@10.10.10.196:/tmp
chromeuser@rope2:/tmp$ chmod +x linpeas.sh
chromeuser@rope2:/tmp$ ./linpeas.sh > linpeas.txt
artex@kali:/home/artex/HTB/RopeTwo# scp -i ssh/key chromeuser@10.10.10.196:/tmp/linpeas.txt linpeas.txt
Смотрим внимательно отчет, анализируя каждую строчку. В разделе «Interesting Files — SUID» видим интересный файл — rshell.
Посмотрим внимательнее, что это.
Похоже на restricted shell с включенным битом SUID, это явно наш пациент! Скачиваем и натравливаем на него «Гидру». Не буду приводить здесь весь листинг дизассемблированного кода, я вместо этого сделал упрощенную диаграмму с основной логикой функций rshell.
Как оказалось, это вовсе не restricted shell, а лишь его эмуляция. Нам доступно всего несколько команд: add, edit, rm, ls, echo, id и whoami. Самые интересные из них — первые четыре (позже выяснится, что три). Они позволяют создавать, изменять, удалять и отображать объекты («файлы») и выделять соответствующие им участки в памяти с определенным размером (не более 112 байт) и контентом. Причем команда ls выводит только имена файлов, без содержания. Что ж, все указывает на то, что впереди нас ждет heap exploitation.
В интернете много информации на эту тему, начать свое погружение в нее можно, например, с сайта Дхавала Капила. Первое, что нам нужно, — найти уязвимости в коде, которые можно проэксплуатировать.
На первый взгляд, никаких явных уязвимостей в коде нет. Везде используются либо безопасные функции, либо проверки размерности, а ввод терминируется нулем. Я потратил много времени, прежде чем нашел уязвимость под названием use after free (UAF).
Подробнее о том, что такое UAF, можно почитать, например, в блоге Orange Cyberdefense.
Настраиваем окружение
Наш эксплоит мы будем писать с помощью pwntools — незаменимой питоновской библиотеки для создания эксплоитов. Но первым делом нам нужно настроить окружение. Для этого, помимо самого rshell, необходимо скачать с машины RopeTwo библиотеки glibc (стандартная библиотека C, реализующая системные вызовы и основные функции, такие как malloc, open, printf) и ld (библиотека динамической линковки). Это необходимо для полной совместимости версий. Во‑первых, новые релизы glibc часто содержат изменения, устраняющие те или иные уязвимости, а во‑вторых, нам важно, чтобы смещения всех функций совпадали. Ниже приведена таблица версий glibc и возможности использования различных вариантов heap exploitation.
Видим, что в нашем случае мы будем использовать версию libc 2.29.
Также в интернете необходимо найти и скачать версию libc 2.29 с отладочными символами, без них писать эксплоит крайне затруднительно. Думаю, с этим квестом ты справишься.
Теперь надо пропатчить наш rshell командой patchelf
, чтобы он стал использовать линкер нужной версии.
Теперь, если ты хочешь запустить rshell c нужной версией libc, используй команду
LD_PRELOAD='libc-2.29.so' rshell
Вывод checksec заставляет содрогнуться — включены все защитные механизмы! Но мы принимаем вызов!
- Full RELRO. Глобальная таблица смещений (GOT) доступна только для чтения. Это означает, что мы не можем перезаписать в ней указатель функции, чтобы изменить ход выполнения программы.
- Canary found. В стеке размещается «канарейка» (определенное значение, перезапись которого означает, что стек был изменен), поэтому переполнение стека нам не светит, если только мы не сможем заполучить контроль над «канарейкой».
- NX enabled. Означает отсутствие областей в памяти, позволяющих одновременную запись и исполнение (RWX). Поэтому мы не можем поместить в адресное пространство шелл‑код и запустить его.
- PIE enabled. PIE — это аббревиатура от Position Independent Executable. Означает, что базовый адрес исполняемого файла меняется при каждом запуске, поэтому без утечки использовать ROP и ret2libc не получится.
Для начала напишем вспомогательные функции, эмулирующие пользовательский ввод.
def add(name, size, content="A"): io.sendlineafter('$ ', 'add '+str(name)) io.sendlineafter('size: ', str(int(size))) io.recvuntil("content: ") io.sendline(content)def edit(name, size, content="A"): io.sendlineafter('$ ', 'edit '+str(name)) io.sendlineafter('size: ', str(int(size))) if int(size) != 0: io.recvuntil("content: ") io.send(content)def rm(name): io.sendlineafter('$ ', 'rm '+str(name))
Тут сразу важно отметить, что в функции add
мы не можем использовать io.
, как в функции edit
, поскольку для записи контента add использует fgets
, а edit — read
. Поэтому воспользуемся методом io.
, который добавляет в конце перенос строки и головной боли нам (об этом дальше).
Куча, бины и чанки
Бин — это корзина, в которую попадают освобожденные участки памяти (чанки). Представляет собой список освобожденных чанков, который бывает односвязный и двусвязный. Основное его назначение — быстрое выделение участка памяти (по статистике, в программах часто выделяются и освобождаются участки памяти одинаковых размеров). Вид связности списка зависит от того, в какой бин попал освобождаемый чанк, что, в свою очередь, зависит от его размера. Размер чанка увеличивается кратно 16 байтам (0x20 → 0x30 → 0x40...). Это значит, что младшие 4 бита поля размера чанка не используются. Вместо этого они содержат флаги состояния чанка:
-
PREV_INUSE
— установленный флаг означает, что предыдущий чанк используется, и наоборот; -
IS_MMAPPED
— означает, что этот чанк был выделенmmap(
;) -
NON_MAIN_ARENA
— означает, что чанк не принадлежит main arena.
Арена — это структура функции malloc
, содержащая бины для освобожденных из кучи чанков.
Максимальное количество арен для процесса ограничено количеством ядер процессора, которое доступно этому процессу.
На данный момент существует пять типов бинов (цифры приведены для 64-битных приложений):
- Tcache (появился в glibc 2.26) для любых чанков, которые меньше или равны 0x410 байт. Всего 64 односвязных списка на каждую арену. Каждый tcache bin хранит чанки одинакового размера. Каждый tcache bin может хранить максимум семь освобожденных чанков.
- Fast для любых чанков, которые меньше или равны 0x0b байт. Всего десять односвязных списков на каждую арену c размером от 0x20 до 0xb0.
- Unsorted. Двусвязный список, который может содержать чанки любого размера. Каждая арена содержит только один такой список. При выделении области памяти перед unsorted bin свободные чанки ищутся сначала в бинах tcache, fast и small. Large bin опрашивается последним.
- Small — коллекция из 62 двусвязных списков на каждую арену размером от 0x20 до 0x3f0 (перекрываются по размерам с fast bins).
-
Large — коллекция из 63 двусвязных списков на каждую арену, из них каждый содержит чанки, размер которых лежит в определенном диапазоне (например,
largebin
содержит освобожденные чанки размеров 0x400–0x430).0x400
Для наглядности выполним простой код, который создает и очищает два чанка по 0x30 байт каждый:
add(0, 0x28)add(1, 0x28)rm(0)rm(1)
Посмотрим, как это выглядит в GDB. Мы видим, что оба чанка попали в tcachebin
. Структура tcache bin представлена на скриншоте.
Односвязный список можно представить так.
А двусвязный — так (для small bins Size будет одинаковый, а для large bin еще добавятся указатели fd_nextsize
и bk_nextsize
).
fd
указывает на следующий чанк в списке, а bk
— на предыдущий.
Пишем эксплоит
С теорией покончено, теперь попробуем написать примитив произвольной записи, используя UAF. Мы не можем использовать технику Tcache Dup (Double Free), так как в glibc 2.29 появилась защита от нее.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»