
Надёжный эксплойт + описание для повышения привилегий до root. (Протестировано на Ubuntu 22.04)
CVE-2022-37706

Привет, ребята, на этот раз я расскажу о недавнем 0-day, который я нашел в одном из
основных оконных менеджеров Linux под названием Enlightenment (https://www.enlightenment.org/).
Этот 0-day мгновенно и очень легко повышает привилегии любого пользователя до root.
Эксплойт протестирован на Ubuntu 22.04, но должен работать на любом дистрибутиве.
Прежде всего, Enlightenment — это оконный менеджер, композитор и минимальное рабочее окружение
для Linux (основная платформа), BSD и любых других совместимых UNIX-систем.
Я установил этот оконный менеджер, чтобы немного поэкспериментировать с ним. Мне было интересно,
так как он содержит множество инструментов и выглядит довольно аккуратно, честно говоря.
После установки пакета с помощью apt install enlightenment я изучил
установленные файлы и каталоги в моей системе: множество модулей и множество вспомогательных
бинарников, но самое интересное — это:
➜ enlightenment cd /usr/lib/x86_64-linux-gnu/enlightenment/
➜ enlightenment find . -perm -4000
./utils/enlightenment_ckpasswd
./utils/enlightenment_system
./utils/enlightenment_sys
Он устанавливает несколько SUID-бинарников, и я подумал, смогу ли я использовать один из них
для повышения привилегий до root. Все бинарники выглядели безопасными и хорошо написанными.
Бинарник, о котором мы будем говорить, — это enlightenment_sys.
Как и в любой другой цели, мы выбираем стратегию после предварительной оценки
(см. мой блог, если еще не: https://pwn-maher.blogspot.com/2020/10/vulnerability-assessment.html).
Я провел аудит кода по нисходящему подходу.
И поскольку этот оконный менеджер с открытым исходным кодом, исходный код доступен
для всех этих бинарников и модулей.
Поэтому первым делом я выполнил apt source enlightenment, чтобы получить весь исходный код,
и, немного покопавшись, мы можем добраться до кода целевого бинарника.
Но для отладки бинарника я загрузил его в Ghidra для анализа и получения адресов
для установки точек останова и всего прочего.
Символов при первой попытке не нашлось, но они и не нужны, так как бинарник
оказался относительно небольшим.
Удивительно, но мне было гораздо приятнее смотреть на декомпилированный псевдокод
Ghidra, чем напрямую на исходники (избегая макросов и проверок на
используемую ОС для компиляции определенного блока кода).
Итак, начнем анализ.
1- Играем с бинарником.
Запустим файл, чтобы получить некоторую информацию о нашей цели:

Запуск бинарника не дает никакого вывода:

Аргумент --help дал такой вывод:

Извините, я использую его, чтобы получить root.
Далее просто выполним strace и посмотрим, использует ли он какие-либо подозрительные системные вызовы, например
execve или openat:
strace ./enlightenment_sys 2>&1 | grep open

Он просто открывает известные библиотеки в местах, к которым у нас нет разрешения на вмешательство.
strace ./enlightenment_sys 2>&1 | grep exec

2- Давайте реверсим бинарник, а затем эксплуатируем его.
Я создал новый проект Ghidra и загрузил этот конкретный бинарник.
Поскольку символы не найдены, мы можем определить функцию main через entry.
Первый аргумент функции entry — это сама main.
Я переименовал ее в main для дальнейших ссылок.
Прокрутив немного вниз, я уже вижу, что используется функция system().
Как pwner, я провожу дни за решением задач, чтобы вызвать эту конкретную функцию x)
Я реверсил бинарник в поисках ошибки повреждения памяти или проблем с кучей,
но на самом деле это оказалась странная инъекция команд.
Бинарник принимает все меры предосторожности перед запуском system, но, к сожалению,
мы всегда можем внедрить туда наш ввод.

Хорошо, теперь давайте пройдемся по бинарнику сверху вниз до нашей функции system, пытаясь
внедрить туда наш ввод.
Сначала бинарник просто проверяет, является ли первый аргумент --help или -h, и выводит то
сообщение, которое мы видели ранее.

Во-вторых, он повышает свои привилегии до root.

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

Итак, если первый аргумент, который мы ввели, — это "mount", он войдет в эту ветку, проверит некоторые
флаги, которые будут установлены в стеке.
Далее он проверяет, начинается ли следующий параметр после mount с UUID= — мы не хотим туда
попадать, поэтому мы передали "/dev/../tmp/;/tmp/exploit".

Таким образом мы проходим проверку в строке 410. Проверку strncmp.
Потому что если он не начинается с /dev/, бинарник завершится.
Затем происходит вызов stat64 для этого файла. Обратите внимание, что мы можем
создать папку с именем ";" и это вызовет инъекцию команды.
На данный момент эксплойт уже создал этот файл /dev/../tmp/;/tmp/exploit,
но это не тот эксплойт, который будет вызван.


Теперь мы приближаемся к system().
Теперь p (указатель) обновляется до последнего аргумента, переданного нашему SUID-бинарнику:
/tmp///net.
Зачем передавать /tmp///net, если можно передать /tmp/net?
Мы обойдем эту проверку:
if (((next_next == (char *)0x0) || (next_next[1] == '\0')) || ((long)next_next - (long)p != 6))
Нам нужно было, чтобы /tmp/net существовал, а /tmp/// имел длину 6.
Теперь последний stat64 проверит существование "/dev/net"
__snprintf_chk(cmd,0x1000,1,0x1000,"/dev%s",next_next);
И он найдет его, так что мы проходим последнюю проверку.
Теперь он проверит наличие некоторых файлов, но это уже неважно
на данном этапе, потому что всё готово и мы близки к запуску произвольной
команды.
Теперь eina_strbuf_new() просто инициализирует команду, которая будет передана
system. Проблема в том, что мы ввели её как:
/bin/mount -o noexec,nosuid,utf8,nodev,iocharset=utf8,utf8=0,utf8=1,uid=$(id -u), "/dev/../tmp/;/tmp/exploit" /tmp///net
Но бинарник вызывает eina_strbuf_append_printf() несколько раз и получает
/bin/mount -o noexec,nosuid,utf8,nodev,iocharset=utf8,utf8=0,utf8=1,uid=$(id -u), /dev/../tmp/;/tmp/exploit /tmp///net
Обратите внимание, что двойные кавычки удалены, и мы сможем вызвать /tmp/exploit
от имени root.

Бинарник сделал всё возможное, чтобы смягчить любое нецелевое поведение, но, как обычно,
всё можно взломать. Я не ожидал, что смогу эксплуатировать это с помощью такой логической ошибки.
Я хочу, чтобы следующая CVE была связана с повреждением памяти, ведущим к LPE до root.
Твиттер-раскрытие: https://twitter.com/maherazz2/status/1569665311707734023