Ядерные LPE в Linux на практике
Применение ядерных эксплойтов в Linux - весьма опасный метод повышения прав доступа. Неудачная отработка эксплойта способна привести к нарушению целостности памяти ядра, за которым часто следует kernel panic и сопутствующая ему потеря данных, а в особо неудачных случаях - даже повреждение файловой системы.
Такие эксплойты имеет смысл использовать только когда все остальные, более безопасные для работоспособности системы способы не применимы. Это вполне вероятно, т.к. наличие классических мисконфигураций sudo/cron/suid вне CTF-like сценариев вряд ли встречается часто, особенно, если первичный доступ к системе осуществляется после RCE в Web-приложении или сетевом сервисе, для учеток которых админам обычно незачем добавлять дополнительные права.
Эпоха относительно простых в эксплуатации юзерспейсных уязвимостей CVE-2021-3156 Baron Samedit и CVE-2021-4034 Pwnkit, актуальных для очень длинной линейки версий sudo и pkexec, явно подходит к концу, а более новые уязвимости вроде CVE-2023-4911 Looney tunables сложнее в эксплуатации и затрагивают меньшую линейку версий. В то же время, появляется все больше kernelspace-эксплойтов, способных работать на больших линейках версий ядер, что позволяет достаточно эффективно их применять на системах, где указанные выше уязвимости уже не актуальны.
Для успешного применения ядерного эксплойта необходимо не только очень аккуратно проверять условия эксплуатабельности, содержание эксплойта и метод его работы, но и проводить предварительное тестирование в условиях, максимально приближенных к тому что есть на проде.
Эта тема уже не раз поднималась, поэтому основной целью данной статьи является именно поиск более удобных и универсальных подходов к такому тестированию.
Проблема выбора эксплойта
Основная проблема при применении эксплойтов на практике состоит в том, что значительная часть публично доступных PoC явно заточены под конкретную сборку ядра и без глубокой адаптации не могут быть применены на других ядрах.
Наличие в коде эксплойта адресов (часто указываемых в виде смещений относительно kernel base) определенных функций в ядре, адресов инструкций процессора, используемых в ROP-цепочках, смещений полей различных структур и других магических констант - все это указывает на то, что эксплойт скорее всего может быть применен только на конкретном билде, обычно указываемом где-то в комментариях или описании, даже если многие другие версии ядра имеют ту же уязвимость.
Адаптация подобных эксплойтов под другие билды вполне возможна, но это может потребовать много времени, хорошим примером подобной уязвимости и эксплойта под неё является история с CVE-2017-11176, закрытом в версии 4.11.9.
Эксплойтов, не требующих таких модификаций, не так уж и много, поэтому скорее всего будет проще не искать каждый раз эксплойт под конкретное ядро, а взять все известные эксплойты и выделить те, что не требуют таких доработок, а затем для каждого выписать версии совместимых с ним ядер. Начать это нелегкое дело можно с достаточно полной коллекции эксплойтов, а для их удобного тестирования можно пользоваться окружениями и подходами из этого репозитория.
Сбор информации о системе
Для примера применения такого подхода возьмем образ минимальной инсталляции CentOS 8.0.1905 с ядром 4.18.0-80.11.2.el8_0.x86_64, скомпилированным 24 сентября 2019 года. Так как CVE-2019-15666 в этом дистрибутиве пофиксили только в январе 2020, выполним попытку её эксплуатации на нашем тестовом стенде.
Чтобы его поднять нам нужно будет получить из системы ядро, initramfs и загружаемые модули ядра, а затем загрузиться с них в некую тестовую файловую систему, где можно будет выполнить все необходимые проверки.
В случае CentOS мы можем получить образ ядра, но initramfs не доступен для чтения:
Для того чтобы его получить, можно воспользоваться командой dracut для генерации своего initramfs со всеми текущими модулями:
В других дистрибутивах initramfs обычно доступен на чтение, но может быть закрыт образ ядра, поэтому проще узнать версию пакета с целевым ядром и скачать его где-нибудь в архивах репозиториев.
Примеры источников старых пакетов для различных дистрибутивов:
Подготовка универсальной среды для тестирования эксплойтов
После получения ядра и initramfs нам остается только подготовить корневую файловую систему, где и будут выполняться все тесты. В идеале, подобная среда должна точно соответствовать дистрибутиву, но для экспресс-тестов может подойти что-то куда более простое.
Возьмем минимальный образ корневой ФС для x64 из проекта micro-rootfs и немного модифицируем его под наши нужды:
Соберем отреверсенную версию эксплойта и добавим её в образ:
Запуск и тестирование эксплойта
Для запуска VM используем эмулятор Qemu, т.к. в отличие от других средств виртуализации он позволяет очень удобно загружаться в наш образ просто подавая в качестве аргументов файлы с ядром и initrd, а ещё в нём очень легко указывать опции ядра и применяемые на таргете аппаратные защиты SMEP и SMAP.
Скрипт для запуска VM:
После открытия консоли VM запустим эксплойт и после нескольких неудачных попыток увидим что он успешно дописал нашего юзера в sudoers, что доказывает уязвимость этой версии ядра в данной конфигурации системы.
Автоматизация тестирования с помощью out-of-tree
При необходимости протестировать эксплойт на большой линейке ядер или для развертывания среды для отладки этого ядра будет гораздо удобнее автоматизировать этот процесс с помощью инструмента out-of-tree, поддерживающего дистрибутивы CentOS, Debian, Oracle Linux и Ubuntu.
Подготовим стенд:
Проведем анализ эксплуатабельности для CVE-2017-16995 из примера в репозитории:
Поднимем стенд для отладки ядра:
Подключимся к стенду по ssh для подготовки окружения:
Запомним адрес commit_creds для быстрой проверки символов:
После подготовки окружения можем начать отладку с помощью gdb:
Для удобства отладки получим отладочные символы для ядра с launchpad:
Подгрузим их в GDB и проверим, что адрес сходится:
Заключение
Ядерные эксплойты имеют очень разную природу и успех их применения часто зависит от внешних обстоятельств: типа уязвимости и метода её эксплуатации, настроек дистрибутива, уровня нагрузки на систему и множества иных факторов. Учесть и воспроизвести на стенде их все очень сложно, поэтому даже применение рассмотренных в статье методов не гарантирует что эксплуатация уязвимости на проде пройдет удачно.
С другой стороны, само наличие стенда и возможности вести отладку переводит эксплуатацию подобных уязвимостей из категории непонятной черной магии в что-то, что можно изучать, менять и в конце концов разбираться, как и почему это работает в том или ином случае.
Happy hacking!
Last updated