Исследователи компании Calif показали локальную цепочку повышения привилегий, которая получает права root в OpenBSD 7.9. Для атаки используются переполнение целочисленного счётчика и отдельная ошибка use-after-free в ядре. Эксплойт обходит рандомизацию KARL и аппаратные механизмы защиты SMAP и SMEP.

Переполнение связано с функцией
Чтобы вызвать переполнение, эксплойт отображает 127 сегментов разделяемой памяти и запускает 259 процессов через
Следующий этап использует отдельную запись за границы выделенной области. Она меняет счётчики членства в группах многоадресной рассылки ядра. Когда затронутый сокет закрывается, уменьшение этих счётчиков изменяет записи таблиц страниц. Отображение пользовательской памяти становится доступным в режиме супервизора, что позволяет обойти SMAP и SMEP. После этого эксплойт перезаписывает указатель на функцию по предсказуемому адресу ядра и запускает собственный код.
KARL — Kernel Address Randomized Link — перелинковывает ядро, меняя адреса функций и данных. Но распределители памяти ядра остаются детерминированными. Как написал исследователь Эндрю Гриффитс: «Хотя KARL в OpenBSD перелинковывает ядро, рандомизируя адреса функций и данных, распределители памяти ядра остаются детерминированными».
Ни загрузочный распределитель памяти, ни распределитель best-fit не рандомизируют базовые адреса. Поэтому структуры, создаваемые на раннем этапе загрузки, включая указатели на функции в обработчиках сетевых интерфейсов
Переполнение исправили в errata 018: обновление вышло 14 сентября как исправление надёжности. Оно также доступно для OpenBSD 7.8. Ошибку подсчёта ссылок, приводившую к use-after-free, закрыли в errata 026, опубликованной 30 сентября как исправление безопасности. Оба патча устанавливаются через
На момент публикации ни одной из уязвимостей не присвоили CVE; свидетельств их использования в атаках не было. Calif сообщила OpenBSD об ошибках «ранее в этом году». После выхода патчей компания разместила подробный разбор и полный код proof of concept на GitHub.
Для дополнительного укрепления ядра Calif предложила безопасное удаление элементов из связанных списков — safe-unlinking, уже применяемое во FreeBSD и NetBSD. Среди других предложений — рандомизация самоссылочного отображения таблиц страниц, рандомизация распределителя памяти ядра и проверка границ массивов на уровне компилятора.

Изображение носит иллюстративный характер
Переполнение связано с функцией
shmat(4), подключающей разделяемую память. Она использует счётчик shm_nattch, объявленный как знаковое 16-битное число типа short. Его максимум — 32 767. Такой тип присутствует в исходниках BSD ещё с 1988 года; OpenBSD унаследовала его и не расширила. Чтобы вызвать переполнение, эксплойт отображает 127 сегментов разделяемой памяти и запускает 259 процессов через
fork. Счётчик выходит за предел, оборачивается и принимает значение −32 643. Затем гонка приводит к use-after-free: из-за испорченного счётчика ядро освобождает память, которой всё ещё пользуются другие процессы. Следующий этап использует отдельную запись за границы выделенной области. Она меняет счётчики членства в группах многоадресной рассылки ядра. Когда затронутый сокет закрывается, уменьшение этих счётчиков изменяет записи таблиц страниц. Отображение пользовательской памяти становится доступным в режиме супервизора, что позволяет обойти SMAP и SMEP. После этого эксплойт перезаписывает указатель на функцию по предсказуемому адресу ядра и запускает собственный код.
KARL — Kernel Address Randomized Link — перелинковывает ядро, меняя адреса функций и данных. Но распределители памяти ядра остаются детерминированными. Как написал исследователь Эндрю Гриффитс: «Хотя KARL в OpenBSD перелинковывает ядро, рандомизируя адреса функций и данных, распределители памяти ядра остаются детерминированными».
Ни загрузочный распределитель памяти, ни распределитель best-fit не рандомизируют базовые адреса. Поэтому структуры, создаваемые на раннем этапе загрузки, включая указатели на функции в обработчиках сетевых интерфейсов
lo0 и enc0, после перезагрузки оказываются по тем же адресам на одном и том же оборудовании. Эксплойту не нужна уязвимость для раскрытия адресов. Переполнение исправили в errata 018: обновление вышло 14 сентября как исправление надёжности. Оно также доступно для OpenBSD 7.8. Ошибку подсчёта ссылок, приводившую к use-after-free, закрыли в errata 026, опубликованной 30 сентября как исправление безопасности. Оба патча устанавливаются через
syspatch и распространяются на все архитектуры. На момент публикации ни одной из уязвимостей не присвоили CVE; свидетельств их использования в атаках не было. Calif сообщила OpenBSD об ошибках «ранее в этом году». После выхода патчей компания разместила подробный разбор и полный код proof of concept на GitHub.
Для дополнительного укрепления ядра Calif предложила безопасное удаление элементов из связанных списков — safe-unlinking, уже применяемое во FreeBSD и NetBSD. Среди других предложений — рандомизация самоссылочного отображения таблиц страниц, рандомизация распределителя памяти ядра и проверка границ массивов на уровне компилятора.