Блог

ssh-keysign-pwn: как непривилегированный пользователь крадёт ключи хоста — и как это остановить

ssh-keysign-pwn
Linux

ssh-keysign-pwn: как непривилегированный пользователь крадёт ключи хоста — и как это остановить

Сервер настроен. Nginx за Cloudflare, fail2ban банит ботов, root-логин по SSH отключён. Публичного доступа к /etc/shadow нет — это же вообще 640, root:shadow. Приватные SSH-ключи хоста лежат в /etc/ssh/ с правами 600. Всё закрыто.

Потом кто-то получает непривилегированный shell — через дырявый плагин, слабый пароль, что угодно — и за несколько секунд читает /etc/shadow и все приватные SSH-ключи хоста. Без sudo и без root. Просто запускает скрипт.

Добро пожаловать в CVE-2026-46333, также известную как ssh-keysign-pwn.

ЧТО СЛУЧИЛОСЬ

14 мая 2026 года Qualys сообщили об уязвимости в ядре Linux, патч был закоммичен в тот же день коммитом 31e62c2ebbfd. В тот же день из публичного коммита появился независимый PoC-эксплойт. Полный advisory Qualys опубликовали 20 мая.

Уязвимость затрагивает не OpenSSH и не конкретную конфигурацию — она в логике ядра Linux.

КАК ЭТО РАБОТАЕТ

Представь охранника который уже сдал пост и пропуск — но ключи от сейфа ещё в кармане. Именно в этот момент кто-то подходит и просит ключи. Формально охранник уже не охранник, проверка провалена.

Примерно так работает CVE-2026-46333.

Ядро Linux использует механизм ptrace — это интерфейс, через который один процесс может наблюдать за другим или обращаться к его ресурсам. Когда привилегированный процесс завершается, ядро освобождает его память (mm) — охранник сдал пропуск. Но файловые дескрипторы к открытым файлам — /etc/shadow, /etc/ssh/ssh_host_*_key — ещё живы. Ключи в кармане.

В этот короткий промежуток функция __ptrace_may_access() пропускает часть проверки: у задачи уже нет контекста памяти, а дескрипторы к чувствительным файлам ещё существуют. Атакующий ловит этот момент через системный вызов pidfd_getfd() — он позволяет скопировать файловый дескриптор из чужого процесса в свой — и получает прямой доступ к файлу.

Два вектора атаки в публичном PoC:

ssh-keysign — это setuid-вспомогательная программа OpenSSH, запускается от root когда SSH-клиенту нужно подписать данные приватным ключом хоста. Устанавливается вместе с openssh-client и присутствует на большинстве Linux-систем. Она открывает приватные ключи хоста (/etc/ssh/ssh_host_*_key) и держит их открытыми на время работы. Атакующий ловит момент завершения ssh-keysign и крадёт дескриптор — приватные ключи прочитаны.

chage — утилита управления сроками паролей. При запуске chage -l система открывает /etc/shadow для чтения данных о пароле пользователя. Тот же race condition — и хеши паролей у атакующего.

Это не переполнение буфера и не сложная цепочка эксплойтов. Просто гонка условий в несколько строк кода.

ЧЕМ ЭТО ОПАСНО

Qualys разработали четыре рабочих эксплойта для одной и той же уязвимости:

chage — читает /etc/shadow с хешами паролей.
ssh-keysign — читает приватные SSH-ключи хоста.
pkexec — выполняет произвольные команды от root. Требует активной консольной сессии, но атакующий может быть залогинен удалённо по SSH.
accounts-daemon — тоже выполняет команды от root, без консоли. Протестировано на дефолтных установках Debian 13 и Fedora.

То есть «просто читает файлы» — это только публичный PoC. Полный root через pkexec и accounts-daemon технически возможен на большинстве дистрибутивов с дефолтной установкой.

Приватный SSH-ключ хоста — это то, чем ваш сервер представляется клиентам при SSH-соединении. Кто владеет этим ключом — может выдать себя за ваш сервер. MITM без предупреждения у клиентов, которые уже добавили ключ в known_hosts. До момента ротации ключей атакующий может перехватывать SSH-сессии незаметно.

Хеши из /etc/shadow можно вынести на отдельную машину и ломать без шума в инфраструктуре. Никаких следов в логах вашего сервера. Если один пароль используется в нескольких местах — компрометация расширяется горизонтально.

Один сервер с непривилегированным доступом превращается в точку входа во всю инфраструктуру.

ЧТО ДЕЛАТЬ ПРЯМО СЕЙЧАС

Шаг 1. Заблокировать эксплойт немедленно — без перезагрузки

Пока ядро не обновлено, два способа закрыть вектор прямо сейчас.

Вариант А — sysctl. Ограничить ptrace на уровне ядра. Значение 2 — достаточная митигация по рекомендации Ubuntu: запрещает ptrace для пользователей без CAP_SYS_PTRACE:

echo kernel.yama.ptrace_scope=2 | sudo tee /etc/sysctl.d/99-CVE-2026-46333.conf
sudo sysctl -p /etc/sysctl.d/99-CVE-2026-46333.conf

Внимание: значение 3 отключает ptrace полностью для всех включая root и не может быть отменено без перезагрузки — не используйте его.

Побочный эффект: непривилегированные пользователи больше не смогут использовать gdb, strace на чужих процессах. На production-серверах это приемлемо.

Вариант Б — снять SUID-бит с обоих векторов атаки:

# Debian/Ubuntu
chmod u-s /usr/lib/openssh/ssh-keysign
chmod u-s /usr/bin/chage

# RHEL/AlmaLinux/Rocky
chmod u-s /usr/libexec/openssh/ssh-keysign
chmod u-s /usr/bin/chage

Это нейтрализует именно те два бинарника которые использует публичный PoC. После установки патча ядра SUID-бит нужно вернуть.

Шаг 2. Обновить ядро

# Debian/Ubuntu
apt update && apt upgrade -y

# RHEL/AlmaLinux/Rocky
dnf clean metadata && dnf upgrade -y

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

Версии ядра с патчем:

Ubuntu 24.04 LTS — патч в версии 6.8.0-117 (USN-8278-1, опубликован 19 мая 2026):

uname -r
# 6.8.0-111-generic → уязвима, обновляться
# 6.8.0-117-generic → патч есть

Ubuntu 22.04 LTS — lowlatency/HWE ядро серии 6.8.x: 6.8.0-117.117.1~22.04.1 (USN-8278-1). Стандартное ядро 5.15.x — следить: https://ubuntu.com/security/CVE-2026-46333

AlmaLinux 10 — начиная с kernel-6.12.0-227.el10 (в продакшн-репозитории с 16 мая).

После перезагрузки с патчем убрать митигации:

sudo rm /etc/sysctl.d/99-CVE-2026-46333.conf
sudo sysctl kernel.yama.ptrace_scope=1

# Debian/Ubuntu
chmod u+s /usr/lib/openssh/ssh-keysign
chmod u+s /usr/bin/chage

# RHEL/AlmaLinux/Rocky
chmod u+s /usr/libexec/openssh/ssh-keysign
chmod u+s /usr/bin/chage

Откатывать ptrace_scope нужно в 1 (значение по умолчанию в Ubuntu), не в 0.

Шаг 3. Ротировать SSH host keys

Даже после установки патча — если атакующий уже получил ключи до обновления, старые ключи скомпрометированы. Пересоздать на критичных серверах:

rm /etc/ssh/ssh_host_*
ssh-keygen -A
systemctl restart ssh   # Debian/Ubuntu
systemctl restart sshd  # RHEL/AlmaLinux/Rocky

Предупредить пользователей: при следующем подключении SSH выдаст предупреждение о смене ключа — это нормально, нужно принять новый отпечаток.

Шаг 4. Аудит локальных учёток и смена паролей

Проверить кто вообще имеет shell-доступ на машине:

awk -F: '$7 !~ /nologin|false/ {print $1, $7}' /etc/passwd

Всё лишнее — заблокировать:

usermod -s /usr/sbin/nologin имя_пользователя

Если непривилегированные пользователи с shell-доступом на машине были — считать хеши паролей скомпрометированными и сменить:

passwd имя_пользователя

Шаг 5. Проверить NoNewPrivileges в критичных сервисах

NoNewPrivileges — директива systemd, которая запрещает процессу получать привилегии выше тех, с которыми он запущен. Даже если атакующий получил shell от имени www-data и попытается эксплуатировать похожий вектор — повышение привилегий будет заблокировано на уровне ядра.

Это не прямой фикс CVE-2026-46333, но снижает поверхность атаки для похожих race condition:

systemctl show nginx | grep NoNewPrivileges
systemctl show postgresql | grep NoNewPrivileges

Если пусто или false — добавить:

systemctl edit nginx
[Service]
NoNewPrivileges=yes
systemctl daemon-reload && systemctl restart nginx

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

ВЫВОД

CVE-2026-46333 — напоминание что «сервер снаружи закрыт» и «сервер безопасен» — разные утверждения. Локальный непривилегированный доступ, который кажется безобидным, превращается в кражу секретов которые живут дольше самой уязвимости.

Патч — сегодня. Ротация ключей — после патча. Аудит учёток — хороший повод сделать это в любом случае.

PoC публичный. Счёт идёт на часы.

Leave your thought here

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Поддержать автора

Если вам понравилась статья — вы можете поддержать автора.

Crypto donation button by NOWPayments