Назад к блогу

Что на самом деле чинили в Tailscale SSH: UID вместо имени, сокеты и симлинки

Что на самом деле чинили в Tailscale SSH: UID вместо имени, сокеты и симлинки

Tailscale закрыла несколько уязвимостей в Tailscale SSH и Serve, через которые непривилегированный пользователь мог обойти ACL и получить права root — разбор механики этих обходов и внесённых исправлений поможет администраторам tailnet понять, насколько критично обновление до версии 1.98.9. Заодно в статье показан полный путь обработки SSH-сессии, включая момент смены привилегий, где и возникали все три проблемы. Отдельного внимания заслуживает то, что часть найденных при аудите дыр к моменту публикации оставалась незакрытой.

Tailscale выпустила исправления для нескольких уязвимостей в Tailscale SSH и Tailscale Serve, позволявших не-root пользователю получить доступ к root. Все они закрыты в версии 1.98.9 или новее. Отдельно в статье BleepingComputer упоминаются 11 неустранённых на момент отчёта проблем (Tailworm), найденных при аудите Tailscale 1.104.2 и self-hosted headscale v0.29.5, включая критическую в SSH-сервере; версии исправления для них не указаны.

Ниже — механика каждой из закрытых проблем, как устроен путь от приёма соединения до запуска сессии и что это меняет для администраторов tailnet.

Что именно изменилось

Числовой UID вместо имени. Tailscale SSH разрешал адресовать пользователя по имени или по UID, но ограничения на root в ACL учитывали только имя. Пользователь с не-root доступом мог обратиться как 0@host и получить root в обход ACL. Теперь UID и чисто числовые имена через SSH запрещены — двусмысленность устранена.

Проксирование Unix-сокетов через Serve. Проверка путей в Serve не покрывала Unix-сокеты как цели прокси. Не-root оператор мог заставить процесс tailscaled, работающий как root, проксировать привилегированный сокет. Теперь цели-сокеты ограничены пользователем root — так же, как это уже требовалось для обработчиков файловой системы.

Симлинки при форвардинге сокетов в SSH. При проверке прав на запрошенные сокеты выполнялось только лексическое сопоставление пути с allow- и deny-списками. Симлинк на защищённый ресурс обходил ограничения. Теперь, помимо лексического сопоставления, проверяются запрошенные и настроенные пути на симлинки, и их назначения тоже должны быть авторизованы.

Как устроен путь сессии и где возникал обход

Точка входа принимает сырое соединение, создаёт объект соединения, взводит таймер login-grace, регистрирует соединение в списке активных и передаёт управление обработчику. Аутентификация устроена так: если проверка подлинности Tailscale отключена, соединение сразу считается прошедшим её без дополнительных прав; иначе заполняются сведения о клиенте, оценивается политика доступа, и по результату соединение либо принимается, либо отклоняется с баннером (имя запрошенного пользователя, отказ политики, ошибка оценки). При принятии выполняется поиск локального пользователя и его групп, результаты сохраняются в соединении.

После SSH-аутентификации политика проверяется заново: если изменение политики материальное изменение, в stderr выводится tailscale: access revoked, сессия завершается с кодом 255 и соединение отзывается, команда не запускается. Затем по запрошенной подсистеме различаются sftp, обычная сессия и всё прочее (неподдерживаемая подсистема). Далее создаётся сессия и запускается команда.

Смена привилегий происходит в инкубаторе. Он блокирует текущий поток ОС, разбирает аргументы, загружает пересланное окружение, проверяет взаимоисключение --sftp и --shell. Если процесс работает от root и хост не в SELinuxEnforcing, инкубатор пробует заменить процесс командой login, затем su; иначе обрабатывает в процессе. В обоих путях перед запуском команды сбрасываются привилегии: выставляются дополнительные группы, при необходимости меняются GID и UID на целевого пользователя, после чего эффективные идентификаторы сверяются с ожидаемыми и при несовпадении процесс завершается. Именно этот переход от root к uid/gid целевого пользователя — место, где обход ACL приводил к повышению привилегий.

Предыстория

Раньше Tailscale SSH поддерживал вход без ключей: сервер отвечает успехом на запрос аутентификации типа «none». Для клиентов, которые на это ломаются, применялся суффикс имени пользователя +password, включающий режим парольной аутентификации с произвольным паролем.

Запуск сессий шёл через субкоманду tailscaled be-child ssh, которая сообщает системе о новом логине для монтирования домашних каталогов и расшифровки ФС. Login-shell запускался только при работе от root и вне SELinuxEnforcing, иначе использовался запуск «в процессе». Затем инкубатор пытался заменить процесс командой login (регистрация удалённого IP, PAM-аутентификация, профиль PAM «remote»), а при неудаче — запустить su с флагами -w, -l и при необходимости -c. Специальный режим совместимости отключал login-shell для SFTP и отключал su, возвращая старое поведение.

В бюллетенях описаны и более ранние SSH-инциденты. При включённом в ACL флаге enforceRecorder пользователи могли кратковременно выполнять команды до прекращения доступа из-за сбоев записи — требовалось обновить tsrecorder и клиенты до 1.78.0 или новее. Ошибка разбора ACL трактовала "checkPeriod": "0s" как неустановленное значение и применяла 12 часов вместо повторной аутентификации при каждом подключении; исправление развёрнуто 2024-04-23, документированный способ — "checkPeriod": "always". Пересылаемые переменные окружения были видны в /proc/<pid>/cmdline другим локальным пользователям на время запуска процесса и записывались в аргументы начала сессии, которые Tailscale логирует локально и (если узел не настроен с --no-logs-no-support) в log.tailscale.com; исправлено в 1.102.1 или новее — значения теперь передаются через унаследованный файловый дескриптор и не пишутся в логи.

Почему это сделали

Исправления касаются проверки прав при запуске сессии и доступа к привилегированным ресурсам, а не валидации пользователя или окружения как таковой. В каждом случае проверка была неполной: ACL смотрели только на имя, Serve не проверял Unix-сокеты, форвардинг сокетов сопоставлял пути лексически. Сброс привилегий при запуске сессии реализован корректно — процесс меняет группы, GID и UID на целевого пользователя и проверяет результат, — но обойти ограничения можно было до того, как до него доходило дело.

Что это меняет на практике

Администраторам tailnet, использующим Tailscale SSH, нужно обновить узлы до 1.98.9 или новее. Той же версии требуют Tailscale Serve и Tailscale Services. Отдельно для управления удалёнными узлами через веб-интерфейс нужна версия 1.98.0 или новее.

В SSH-правилах ACL поле action принимает accept или check; при check доступен необязательный период повторной аутентификации (по умолчанию 12h). Поле users задаёт список SSH-пользователей, и теперь адресовать их по UID или чисто числовым именам нельзя — это затрагивает ограничения autogroup:nonroot.

Как параметры читаются во время работы: пересылаемые клиентом переменные окружения принимаются, только если ключ не опасен и не запрещён, значение не содержит NUL, а для TERM/LANG/LC_* — значения с «/» и ведущим «-»; остальные пары отклоняются. Login-shell выбирается только при работе от root и вне SELinuxEnforcing. Запись сессии включается, если у сессии есть рекордеры или включён TS_DEBUG_LOG_SSH, а изменение списка рекордеров требует реаутентификации, поскольку состояние записи фиксируется при аутентификации.

Ограничения и открытые вопросы

Tailscale не рекомендует всем отключать Tailscale SSH. Предлагаемые меры: проверить политики доступа SSH и ограничить доступ нужными пользователями и устройствами; отключить пересылку SSH, если она не нужна, установив TS_SSH_DISABLE_FORWARDING=1 в окружении службы tailscaled и перезапустив её — это отключает пересылку, но не сам Tailscale SSH, и смягчает часть наиболее серьёзных находок; временно ужесточить политики доступа к чувствительным системам; установить исправленный клиент, когда он выйдет. BleepingComputer собственных рекомендаций не даёт, а пересказывает меры Tailscale.

Открытым остаётся полный объём находок и затронутые конфигурации — Tailscale продолжает их проверять. По другой проблеме в бюллетене указано, что журналы аудита не содержат достаточно информации для обнаружения гонки при работе с auth keys, и улучшение журналов лишь планируется. У самого Tailscale SSH есть и постоянные ограничения: подключаться можно только к устройствам в сети Tailscale (не к устройствам за subnet router без Tailscale), только к Linux и macOS с open source CLI-версией, нельзя запускать на Synology/QNAP; порт SSH жёстко предполагается равным 22, изменить его нельзя; режим check применим только к Tailscale SSH, не к обычному SSH или другим TCP-соединениям; при одновременном наличии check- и accept-правил применяется более ограничительное check-правило, и пользователь ограничивается только users из него; перезапуск tailscaled обрывает существующие сессии.

Источники

Похожее