Компания Qualys выявила третью в этому году опасную уязвимость (CVE-2022-3328) в утилите snap-confine, поставляемой с флагом SUID root и вызываемой процессом snapd для формирования исполняемого окружения для приложений, распространяемых в самодостаточных пакетах в формате snap. Уязвимость позволяет локальному непривилегированному пользователю добиться выполнения кода с правами root в конфигурации Ubuntu по умолчанию. Проблема устранена в выпуске snapd 2.57.6. Обновления пакетов выпущены для всех поддерживаемых веток Ubuntu.
Интересно, что рассматриваемая уязвимость была внесена в процессе исправления похожей февральской уязвимости в snap-confine. Исследователям удалось подготовить рабочий эксплоит, предоставляющий root-доступ в Ubuntu Server 22.04, в котором кроме уязвимости в snap-confine также задействованы две уязвимости в процессе multipathd (CVE-2022-41974, CVE-2022-41973), связанные с обходом проверки полномочий при передаче привилегированных команд и небезопасной работой с символическими ссылками.
Уязвимость в snap-confine вызвана состоянием гонки в функции must_mkdir_and_open_with_perms(), добавленной для защиты от подмены каталога /tmp/snap.$SNAP_NAME на символическую ссылку в момент после проверки владельца, но перед обращением к системному вызову mount для bind-монтирования в него каталогов для пакета в формате snap. Добавленная защита сводилась к переименованию каталога /tmp/snap.$SNAP_NAME в другой каталог в /tmp со случайным именем, если он существует и не принадлежит пользователю root.
При эксплуатации операции переименования каталога /tmp/snap.$SNAP_NAME исследователи воспользовались тем, что snap-confine также создаёт каталог /tmp/snap.rootfs_XXXXXX для корня содержимого пакета snap. Часть “XXXXXX” в имени выбирается случайно при помощи mkdtemp(), но пакет с именем “rootfs_XXXXXX” может пройти проверку в функции sc_instance_name_validate (т.е. идея в том, чтобы имя $SNAP_NAME приняло значение “rootfs_XXXXXX” и тогда операция переименования приведёт к перезаписи каталога /tmp/snap.rootfs_XXXXXX с корнем snap).
Для того чтобы добиться одновременного использования /tmp/snap.rootfs_XXXXXX и переименования /tmp/snap.$SNAP_NAME было запущено два экземпляра snap-confine. Как только первый экземпляр создавал /tmp/snap.rootfs_XXXXXX процесс блокировался и запускался второй экземпляр с именем пакета rootfs_XXXXXX, что приводило к тому, что временный каталог /tmp/snap.$SNAP_NAME второго экземпляра становился корневым каталогом /tmp/snap.rootfs_XXXXXX первого. Сразу после выполнения переименования второй экземпляр аварийно завершался, а /tmp/snap.rootfs_XXXXXX подменялся с манипуляцией состоянием гонки, как при эксплуатации февральской уязвимости. После подмены с первого экземпляра снималась блокировка выполнения и атакующие получали полный контроль над корневым каталогом snap.
На последнем этапе создавалась символическая ссылка /tmp/snap.rootfs_XXXXXX/tmp, которая использовалась функцией sc_bootstrap_mount_namespace() для bind-монтирования доступного на запись реального каталога /tmp в любой каталог ФС, так как вызов mount() следует символическим ссылкам перед монтированием. Подобное монтирование блокируется ограничениями AppArmor, но для обхода этой блокировки в эксплоите были задействован две вспомогательные уязвимости в multipathd.