Новое Распределяем каналы MAX по категориям и территориям. Читать новость

Репост из «Хакер | Этичный хакинг с Михаилом Тарасовым»

Призрак освобожденной памяти: как работает Use-After-Free и почему его боятся даже создатели браузеров



Мы уже посмотрели, как компилятор отбивает атаки на стек и как ошибки форматирования сливают токены из памяти. Теперь шагнем на территорию, где находят самые дорогие уязвимости в ядрах ОС, браузерах и демонах - в динамическую память (Heap / Кучу).

Сегодня в Parrot Security OS на ARM64 я разобрал уязвимость класса Use-After-Free (UAF) и получил доступ администратора без единой ошибки сегментации.

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

1. В чем суть бага Use-After-Free?
Когда программа выделяет блок памяти через malloc(), а затем освобождает его через free(), программист обязан занулить указатель (ptr = NULL).

Если этого не сделать, указатель становится «висячим» (Dangling Pointer). Он продолжает указывать на адрес в куче, хотя система считает этот кусок свободным. Если программа позже снова обратится по этому указателю, она прочитает то, что окажется на этом месте.

2. Эксперимент: симулируем веб-сессию
Я написал сервис, где есть две сущности:

1. Сессия пользователя UserSession: логин (24 байта) и флаг роли is_admin (4 байта).

2. Заметка пользователя global_note: обычный текстовый буфер того же размера.

Смотрим на первый скриншот:

1. Создаем сессию: выделяется блок по адресу 0xaaaaaaac16b0, статус is_admin = 0.

2. Пользователь выходит: вызывается free(), но указатель не зануляется.

3. Создаем заметку: и аллокатор glibc выделяет под нее ровно тот же самый адрес 0xaaaaaaac16b0!

Почему адреса совпали?
В glibc работает механизм кэширования Tcache (Thread Local Cache). Чтобы не тратить время на системные вызовы, аллокатор складывает недавно освобожденные чанки одинакового размера в быстрый список и при следующем malloc мгновенно отдает их повторно!

3. Ловушки ядра: почему нельзя передать нули в argv
Казалось бы, достаточно записать в новую заметку 24 символа имени и байт \x01\x00\x00\x00, чтобы выставить флаг is_admin = 1.

Но тут включились правила Linux и POSIX (второй и третий скриншоты):

- Командная строка argv считает нулевой байт \x00 концом строки.

- Python при попытке передать бинарный ноль в аргумент выбросил системную ошибку ValueError: embedded null byte.

- А когда мы передали строку без нулей, memcpy скопировал наш байт \x01, но не затер старые служебные указатели аллокатора, выдав статус is_admin = 1213399041 вместо единицы!

4. Взлом через сырой поток stdin (четвертый и пятый скриншоты)
В реальных сетевых службах данные приходят не из аргументов запуска, а из сокета или стандартного ввода stdin.

Я переписал чтение заметки на fread() из потока ввода и передал пейлоад через пайп:
python3 -c 'import sys; sys.stdout.buffer.write(b"A"*24 + b"\x01\x00\x00\x00")' | ./uaf

Все 28 байт прошли без искажений:

- 24 буквы A заполнили поле логина;

- байты \x01\x00\x00\x00 аккуратно легли на место флага роли;

- программа обратилась к старому висячему указателю global_user->is_admin, увидела значение 1 и выдала флаг:
[+++] ДОСТУП РАЗРЕШЕН! Привет, Администратор! Флаг: FLAG{UAF_HEAP_MASTER_2026}.

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

Главные выводы по безопасности кучи
1. Правило чистого указателя: Вызвал free(ptr) - сразу пиши ptr = NULL;. Обращение к нулевому адресу приведет к мгновенному и безопасному завершению программы вместо скрытой эксплуатации.

2. Динамический анализ (ASan): Собирайте тестовые билды с флагом -fsanitize=address. AddressSanitizer блокирует использование освобожденной памяти и сразу выводит имя проблемной строки.

3. Тренд на Memory-Safe языки: Именно сложности контроля времени жизни объектов в Си/C++ подталкивают индустрию к переходу на Rust и Go, где компилятор проверяет владение памятью на этапе сборки.
Просмотры: 16
Открыть в MAX Сообщить о неточности

Сообщить о неточности

Опишите, что нужно исправить. Если есть источник, добавьте ссылку.

Вы покидаете datool.ru

Ссылка ведёт на внешний сайт. datool.ru не отвечает за его содержимое — проверьте адрес, прежде чем вводить пароли или платёжные данные.

Переход через 10 с

Перейти