37 лет под водой: уязвимость в ядре OpenBSD, уходящая корнями в оригинальный BSD

· Безопасность
Исследователи Calif получили root в OpenBSD с включёнными KARL, SMAP и SMEP, использовав переполнение счётчика, который оставался 16-битным ещё со времён исходников BSD.

cover.svg

Компания Calif рассказала об эксплуатации уязвимости в ядре OpenBSD, историю которой можно проследить примерно на 37 лет назад — до оригинальных исходников BSD. Обычно фирма публикует наступательные исследования, но на этот раз речь идёт о работе, выполненной в связке с проектом: уязвимости были сообщены разработчикам, зачастую вместе с предлагаемыми патчами.

В чём ошибка

Корень проблемы — счётчик привязок разделяемой памяти, определённый как знаковое 16-битное целое (short). Многократное ветвление процесса с записями о привязках позволяло вытолкнуть счётчик за его максимум в 32 767 и «завернуть» его в отрицательное значение. Это целочисленное переполнение приводило к use-after-free через состояние гонки, а в сочетании с отдельной внеграничной записью в ядре давало локальное повышение привилегий до root. Проблемы устранены в errata 026 и 018.

Путь эксплуатации

Исследователям удалось получить локальный root без использования утечки информации. Схема такова: отобразить 127 сегментов разделяемой памяти SysV, снять их через munmap() и породить 259 процессов, доведя счётчик привязок до −32 643. Затем — подготовка кучи с опорой на метрики sysctl(KERN_MALLOCSTATS), выигрыш гонки с помощью IPC_RMID, выравнивание размещений IP-сокетов и установка IP_MULTICAST_TTL в нестандартное значение, чтобы выделить структуру ip_moptions.

Далее условная внеграничная запись −1 перезаписывает поля числа и максимума членств, после чего close() сокета запускает атомарные декременты, дважды меняющие самоссылающееся отображение PTE — из пользовательского в супервизорное. Так обходятся SMAP/SMEP и достигается исполнение кода в ядре через перезапись предсказуемого указателя. По сути это примитив «записать что куда»: «что» — пользовательская память, ставшая доступной супервизору, «куда» — предсказуемый адрес ядра.

Почему адреса предсказуемы

Механизм KARL перекомпоновывает ядро, рандомизируя адреса функций и данных, однако аллокаторы памяти остаются детерминированными. Ранние загрузочные выделения стабильно попадают в предсказуемые места на одном и том же оборудовании. Эксплойт надёжно нацеливается на обработчики ioctl для lo0 и enc0: один перезаписывается ради захвата потока управления, другой используется для восстановления указателя.

Что предлагают авторы

Calif перечисляет меры защиты: безопасное отсоединение элементов двусвязных списков (как в FreeBSD и NetBSD), рандомизация адреса самоссылающегося отображения PTE, недетерминированность аллокатора ядра. Отдельно отмечаются компиляторные средства — санитайзер границ массивов (его предложили FreeBSD вместе с 21 приватно сообщённой проблемой) и грядущие Alloc Tokens, изолирующие выделения с указателями. В эпоху поиска уязвимостей с помощью ИИ, подчёркивают авторы, устранение целых классов ошибок и повышение стоимости атаки становится лишь важнее.


Источник: Hacker News

Комментарии

Войдите, чтобы комментировать.

  • Пока нет комментариев.