company_banner

Уязвимость CVE-2019-5736 в runc, позволяющая получить права root на хосте

https://seclists.org/oss-sec/2019/q1/119
  • Перевод
Прим. перев.: Минувшей ночью Aleksa Sarai, старший инженер по контейнерам из SUSE Linux, сообщил в почтовой рассылке oss-sec о критической уязвимости в безопасности runc/LXC, которая позволяет злоумышленнику, имеющему доступ в изолированный контейнер, получить привилегии root на хостовой системе. Поскольку проблема выявлена в эталонной реализации исполняемой среды для контейнеров — runc, — она затрагивает многочисленные контейнерные системы включая Docker/Moby, Podman, cri-o (и собственно Kubernetes). Ниже представлены подробности в виде перевода сообщения инженера в почтовую рассылку.


Я являюсь одним из мейнтейнеров runc (нижележащей среды исполнения контейнеров, используемой в Docker, cri-o, containerd, Kubernetes и т.п.). Недавно стало известно об уязвимости, которую мы проверили и пропатчили.

Исследователи, обнаружившие уязвимость:

  • Adam Iwaniuk;
  • Borys Popławski.

Кроме того, Aleksa Sarai (т.е. я) обнаружил, что более изощрённой версии этой уязвимости подвержен и LXC.

Краткий обзор


Уязвимость позволяет вредоносному контейнеру (с минимальным взаимодействием с пользователем) переписать хостовый бинарник runc и таким образом получить возможность исполнения кода с правами root на хосте. Степень взаимодействия с пользователем такова, что позволяет запускать любые команды (не важно, контролирует ли команду злоумышленник) с правами root в рамках контейнера в любом из этих контекстов:

  • Создание нового контейнера из контролируемого злоумышленником образа;
  • Подключение (docker exec) к существующему контейнеру, к которому ранее у злоумышленника был доступ на запись.

Эта уязвимость не блокируется ни политикой AppArmor по умолчанию, ни политикой SELinux по умолчанию в Fedora* (потому что процессы контейнера выглядят как запущенные с container_runtime_t). Однако она блокируется корректным использованием пользовательских пространств имён (где root хоста не map'ится в пользовательское пространство имён контейнера).

Вектор CVSSv3 (с рейтингом в 7.2) таков:

AV:L/AC:H/PR:L/UI:R/S:C/C:N/I:H/A:H

Проблеме назначен CVE-2019-5736.

* Проблема относится только к пакету moby-engine в Fedora. Пакет docker, как и podman, защищён от её эксплуатации, поскольку запускает процессы контейнера как container_t.

Патчи


Прикладываю соответствующий патч, исправляющий проблему (0001-nsenter-clone-proc-self-exe-to-avoid-exposing-host-b.patch). Он основан на ветке HEAD, хотя код в libcontainer/nsenter/ меняется настолько редко, что патч скорее всего применим практически к любой старой версии кодовой базы runc, с какой вы имеете дело.

Обратите внимание, что патч, который я push'нул в master-ветку runc, является модифицированной версии этого патча, хоть они и идентичны функционально (если вы ещё не пропатчили свои файлы приложенным патчем, мы рекомендуем использовать upstream-версию).

Второстепенность кода эксплоита


Некоторые вендоры запросили код эксплоита, чтобы убедиться, что патчи решили проблему. Поскольку проблема очень серьёзна (особенно для вендоров публичных облаков), мы решили предоставить такой код. Эксплоит написан мною, является более общим, чем оригинальный код, предоставленный исследователями, и работает для LXC (не требует сильных модификаций для возможности применить для других уязвимых исполняемых сред). Подробности о том, как использовать код эксплоита, предоставлены в README.

В соответствии с правилами OpenWall, код эксплоита будет публично обнародован через 7 дней после CRD (т.е. 18 февраля 2019 года). Если у вас есть исполняемая среда для контейнеров, пожалуйста, предварительно убедитесь, что она не подвержена этой уязвимости.

Влияние на другие проекты


Следует отметить, что в процессе дальнейшего расследования проблемы я обнаружил, что у LXC есть схожая уязвимость, и они уже push'нули схожий патч нашей совместной разработки. LXC немного сложнее эксплуатировать, однако сама проблема та же.

Обсуждение с представителями systemd-nspawn привело к выводу, что они уязвимости не подвержены (поскольку у них иной метод подключения к контейнеру для LXC и runc).

Со мной также связались представители Apache Mesos, сообщившие, что и они подвержены уязвимости (думаю, что они попросту использовали код эксплоита, который будет опубликован). Очень похоже, что большинство исполняемых сред для контейнеров подвержены уязвимости, если они предварительно не предпринимали весьма необычных действий по смягчению её возможного воздействия.

Другие новости


Мы настроили рассылку анонсов для будущих уязвимостей в безопасности: процесс присоединения к ней описан здесь (он основан на почтовой рассылке Kubernetes security-announce). Пожалуйста, присоединяйтесь, если распространяете любые исполняемые среды для контейнеров, которые зависят от runc (или других проектов OCI).

P.S. От переводчика


Проблема CVE-2019-5736 в трекерах популярных Linux-дистрибутивов:


… и запись в блоге Kubernetes (обратите внимание на раздел «What Should I Do?»).
Флант
259,00
Специалисты по DevOps и высоким нагрузкам в вебе
Поделиться публикацией

Комментарии 8

    0

    Запись в /proc/self/exec? На это хватило прав? Какие права проброшены внутрь контейнера? Столько интересных вопросов, аж жаль, что перевод.

      0
      Через 6 дней можно будет взглянуть на эксплоит и понять точно. Или перевести статью, где это сделал кто-то еще)
        0
        Эксплоит скорее всего уже написан, только в привате и за $
          0
          Закрытый — возможно. Но и сам автор говорит, что они написали демонстрационный, и откроют его 18 февраля. А на него уже посмотреть всем можно будет.
        0
        Из NVD (ссылка есть в статье):

        This occurs because of file-descriptor mishandling, related to /proc/self/exe.

        В этом патче (к LXC; тоже есть ссылка в статье) — больше подробностей:

        The attack can be made when attaching to a running container or when starting a
        container running a specially crafted image. For example, when runC attaches
        to a container the attacker can trick it into executing itself. This could be
        done by replacing the target binary inside the container with a custom binary
        pointing back at the runC binary itself. As an example, if the target binary
        was /bin/bash, this could be replaced with an executable script specifying the
        interpreter path #!/proc/self/exe (/proc/self/exec is a symbolic link created
        by the kernel for every process which points to the binary that was executed
        for that process). As such when /bin/bash is executed inside the container,
        instead the target of /proc/self/exe will be executed — which will point to the
        runc binary on the host. The attacker can then proceed to write to the target
        of /proc/self/exe to try and overwrite the runC binary on the host. However in
        general, this will not succeed as the kernel will not permit it to be
        overwritten whilst runC is executing. To overcome this, the attacker can
        instead open a file descriptor to /proc/self/exe using the O_PATH flag and then
        proceed to reopen the binary as O_WRONLY through /proc/self/fd/ and try to
        write to it in a busy loop from a separate process. Ultimately it will succeed
        when the runC binary exits. After this the runC binary is compromised and can
        be used to attack other containers or the host itself.
          +4

          Спасибо! То есть:


          1. Мы заставляем exec-нуться в себя runc, теперь он запущен внутри контейнера.
          2. Процесс не потерял fd-шку на себя потому что лапки.
          3. Изнутри контейнера мы через этот fd начинает писать в бинарник.
          4. У нас получается?!
            +2

            Для желающих, я почитал доки: да, получится, ещё как! :D Одновременно красивый хак, но и безолаберный: запуск привилегированного контейнера это практически root, вот ещё один пример в коллекцию.

        +2
        Выдохнул. Очередной повод порадоваться включенному SELinux, и поблагодарить разработчиков.
        Пакет docker, как и podman, защищён от её эксплуатации, поскольку запускает процессы контейнера как container_t.
        OpenShift Online and Dedicated are not vulnerable to exploit due to the use of SELinux in enforcing mode.
        Customers using SELinux in enforcing mode can observe exploitation attempts by looking at AVC events in the audit logs. E.g.
        $ aureport -a
        AVC Report
        ===============================================================
        # date time comm subj syscall class permission obj result event
        ===============================================================
        1. 11/02/19 00:00:00 script system_u:system_r:container_t:s0:c530,c886 2 file write system_u:object_r:container_runtime_exec_t:s0 denied 81359

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое