[Тип угрозы]: локальное повышение привилегий (LPE)
[CVE]: CVE-2021-4034
[CVSS vector]: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
[Platform]: Все дистрибутивы Linux[Product]: pkexec
[Version]: Все версии
[Severity]: 7.8/10
[Дата обнаружения]: 18.11.2021 (Дата публикации: 25.01.2022)
25 января 2022 года группа исследователей кибербезопасности из Qualys опубликовала уязвимость, получившую название PwnKit. Эксплуатация данной уязвимости приводит к повреждению памяти в программе pkexec, вследствие чего злоумышленник может локально повысить привилегии до уровня системы. Данная уязвимость присутствует в pkexec с момента ее создания, с мая 2009 г. Pkexec как часть polkit присутствует во всех основных дистрибутивах Linux (Ubuntu, Debian, Fedora, CentOS).
Polkit (PolicyKit) — это компонент, контролирующий привилегии на уровне системы в Unix-подобных ОС и позволяющий организовать взаимодействие непривилегированных процессов с привилегированными. Иногда его называют «sudo для systemd». Примеры использования polkit — когда пользователь выключает или перезагружает компьютер, управляет беспроводными подключениями, получает доступ к аудио, сканера и пр. Pkexec — это SUID root-программа, предоставляющая интерфейс к Polkit и позволяющая исполнять команды от имени другого пользователя или администратора.
Уязвимость PwnKit (CVE-2021-4034) является опасной по следующим причинам:
1) Pkexec установлена по умолчанию во всех основных дистрибутивах Linux. Исследователями были успешно поэксплуатированы дистрибутивы Ubuntu, Debian, Fedora, CentOS. Уязвимость присутствует в pkexec с мая 2009 года.
2) Любой непривилегированный пользователь может использовать данную уязвимость для получения root-прав.
3) Хотя технически эта уязвимость представляет собой уязвимость типа повреждения памяти, с ее эксплуатацией не происходит никаких проблем независимо от архитектуры, эксплойт работает быстро и надежно.
Публичный эксплойт был разработан на C и опубликован даже до, а не после рекомендации. Он заявлен как proof-of-concept. Эксплойт доступен на haxx.in. Уязвимость рассматривалась как закрытый эксплойт нулевого дня в течение как минимум одного дня.
Для успешной эксплуатации уязвимости пользователь должен быть аутентифицирован в системе.
Программа pkexec неправильно проверяет количество переданных ей аргументов. Эта проблема в конечном итоге приводит к попыткам выполнить переменные среды как команды, что, в свою очередь, приводит к тому, что pkexec выполняет произвольный код от имени УЗ root, предоставляя злоумышленнику локальную эскалацию привилегий.
Ниже представлены технические подробности уязвимости.
Начало функции pkexec main() обрабатывает аргументы командной строки (строки 534-568) и ищет программу для выполнения, если ее путь не является абсолютным, в каталогах переменной среды PATH (строки 610-640):
------------------------------------------------------------------------
435 main (int argc, char *argv[])
436 {
...
534 for (n = 1; n < (guint) argc; n++)
535 {
...
568 }
...
610 path = g_strdup (argv[n]);
...
629 if (path[0] != '/')
630 {
...
632 s = g_find_program_in_path (path);
...
639 argv[n] = path = s;
640 }
------------------------------------------------------------------------
Если количество аргументов командной строки argc равно 0, что означает, что список аргументов argv, который мы передаем в execve(), пуст, т. е. {NULL}, тогда argv[0] равен NULL. Это терминатор списка аргументов. Следовательно:
o В строке 534 целое число n постоянно установлено равным 1.
o В строке 610 путь указателя считывается за пределами argv[1].o В строке 639 указатель s записывается за пределы argv[1].
Когда мы производим системный вызов execve() для новой программы, ядро копирует наш аргумент, строки окружения и указатели (argv и envp) в конец стека новой программы, например:
|---------+---------+-----+------------|---------+---------+-----+------------|
| argv[0] | argv[1] | ... | argv[argc] | envp[0] | envp[1] | ... | envp[envc] |
|----|----+----|----+-----+-----|------|----|----+----|----+-----+-----|------|
V V V V V V
"program" "-option" NULL "value" "PATH=name" NULL
Поскольку указатели argv и envp непрерывны в памяти, если argc равен 0, то argv[1] за границами на самом деле является envp[0], указателем на нашу первую переменную среды, «значение». Следовательно:
o В строке 632 это «значение» пути передается в g_find_program_in_path() (поскольку «значение» не начинается с косой черты в строке 629).
o Затем g_find_program_in_path() ищет исполняемый файл с именем «value» в каталогах нашей переменной окружения PATH.o Если такой исполняемый файл найден, его полный путь возвращается функции main() pkexec (строка 632).
o Наконец, в строке 639 этот полный путь записывается за пределы argv[1] (т. е. envp[0]), таким образом перезаписывая нашу первую переменную среды.
Уязвимы все Linux-дистрибутивы, содержащие Polkit.
Для выявления уязвимых систем рекомендуется проверять их на наличие pkexec с помощью одной из следующих команд:
whereis pkexec
which pkexec
ls -la /usr/bin/pkexec
find / -type f -name pkexec
“The value for the SHELL variable was not found the /etc/shells file”,
“The value for environment variable […] contains suspicious content”.
Однако в оригинальном исследовании подчеркивается, что попытки эксплуатации могут проходить бесследно для системных журналов Linux.