🛡️ CVE-2026-98432: удалённый root на Linux через MPTCP, Go 1.24+ и экстренный Xray v26.10.31

О чём заметка

Разбор уязвимости ядра Linux CVE-2026-98432 (октябрь 2026) для тех, кто держит свой прокси-сервер на Xray или другой программе на Go: что сломано в ядре, почему опасность резко выросла именно у Go-серверов, что изменил выпуск Xray v26.10.31 и как проверить и закрыть свой сервер.

TL;DR

  • В ядре Linux нашли ошибку при приёме входящих IPv4 TCP-подключений: память освобождается, пока другое ядро процессора ещё её читает. CVE-2026-98432 получила оценку 9,8 из 10, ошибка есть в ядрах начиная с 4.4.
  • Anthropic показала, как через эту ошибку получить root на сервере с MPTCP-слушателем без пароля и без действий администратора: в их тесте ушло 48 + 5 минут, а неудачная попытка систему не роняет.
  • Программы на Go 1.24 и новее открывают MPTCP-слушатели сами, даже если администратор об этом не знает. На типичном VPS с Xray именно Xray оказывается таким слушателем.
  • Xray v26.10.31 вышел 31 октября 2026 года как экстренное обновление: MPTCP теперь выключен по умолчанию. Команда Go менять своё поведение пока не стала.
  • Полностью закрывает дыру только исправленное ядро и перезагрузка. Обновление Xray, GODEBUG=multipathtcp=0 и net.mptcp.enabled=0 убирают самый лёгкий путь атаки, но не саму ошибку.

Что произошло

31 октября 2026 года разработчики Xray выпустили экстренное обновление v26.10.31. В описании выпуска сказано прямо: в ядре Linux нашли способ удалённо получить root через слушатель IPv4 MPTCP, а Go 1.24+ включает MPTCP по умолчанию, поэтому новая версия его выключает. Предыдущая версия v26.10.29 отозвана, пользователям советуют обновиться как можно скорее и заодно обновить ядро Linux, потому что исправить ошибку в корне может только оно.

За выпуском стоит цепочка событий короче месяца. Исправление в ядро Linux приняли 5 октября, по данным The Hacker News, 15 октября опубликовали CVE. Положение изменилось 27 октября: Anthropic опубликовала разбор, где её модель написала рабочий эксплойт с удалённым root, и целью в нём был сервер с MPTCP-слушателем. Через два дня связь с Go заметили в трекере Go и в Xray, и обсуждение пошло уже о том, у кого такие слушатели есть.

Ошибка в ядре: гонка при приёме TCP-подключения

Чтобы понять ошибку, нужно вспомнить, как сервер принимает подключение. Клиент присылает пакет SYN («хочу подключиться»), сервер отвечает SYN-ACK, клиент подтверждает. Пока рукопожатие не закончено, ядро держит для будущего подключения временную запись — запрос на соединение (request socket). Когда рукопожатие завершается, ядро создаёт из неё настоящий сокет подключения. Подробнее о самом рукопожатии рассказано в заметке о том, как DPI «замораживает» VLESS.

В IPv4-пакете бывают IP-опции — редкие служебные поля в заголовке. Если они пришли в SYN, ядро хранит их в записи о запросе. По описанию CVE-2026-98432 в NVD, при создании сокета подключения функция tcp_v4_syn_recv_sock() передаёт ему эти опции, не копируя их. Тем временем другое ядро процессора может обрабатывать повторный SYN для того же запроса и строить по тем же опциям ответный SYN-ACK. Если сокет подключения в этот момент закрывается, опции освобождаются обычным kfree(), а второе ядро продолжает их читать. Такая ошибка называется использованием после освобождения (use-after-free, UAF).

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

Ошибку внёс коммит, после которого записи о запросах обрабатываются без блокировки слушающего сокета. Затронуты ядра начиная с Linux 4.4; исправление переводит освобождение опций на kfree_rcu(), то есть память отдаётся только после того, как все читатели закончили. Исправленные версии, по записи CVE: 5.10.272, 5.15.223, 6.1.190, 6.6.159, 6.12.113, 6.18.56, 7.2.10 и 7.3. IPv6 первым вариантом ошибки не затронут, потому что для IPv6 ядро опции копирует. Однако сервер, который слушает на [::] и принимает IPv4-подключения через тот же сокет, обрабатывает их IPv4-кодом ядра, так что слушать на [::] вместо 0.0.0.0 не помогает.

У ошибки есть второй вариант — при переносе запросов между сокетами (net.ipv4.tcp_migrate_req=1 или BPF-программа BPF_SK_REUSEPORT_SELECT_OR_MIGRATE). Эта настройка по умолчанию выключена, и, как отметил автор Xray RPRX в обсуждении исправления, ею пользуются немногие.

Как Anthropic дошла до root

27 октября 2026 года команда Frontier Red Team компании Anthropic опубликовала разбор пяти цепочек атак, которые нашла и превратила в эксплойты её внутренняя, ещё не выпущенная исследовательская модель. Одна из них — удалённое выполнение кода в ядре Linux. По словам компании, после начальной постановки задачи Claude написал эксплойт, который позволяет удалённому атакующему отправлять пакеты на сервер Linux с MPTCP-слушателем и выполнять любые команды от root, без учётных данных и без действий пользователя. На русском новость пересказал канал Black Triangle.

Атака идёт в два этапа. На первом атакующий обходит KASLR — случайное размещение ядра в памяти, из-за которого заранее неизвестно, где лежат нужные функции. Гонка заставляет ядро прочитать поле длины, которое контролирует атакующий, и отправить ему лишние байты памяти. Как только в одном из ответов оказывается адрес внутри ядра, расположение ядра раскрыто. На втором этапе та же ошибка переполняет буфер и перезаписывает указатель на функцию (callback) адресом заранее подложенной в память ядра нагрузки. Когда ядро вызывает этот указатель, нагрузка цепочкой обычных функций ядра запускает команду атакующего от root.

Главное свойство этой гонки, по словам Anthropic, в том, что проигрыш ничего не ломает: срывается одно рукопожатие, система работает дальше, поэтому настойчивый атакующий пробует, пока не получится. В демонстрации утечка адреса ядра заняла 48 минут, а ещё пять минут ушло на выполнение команды. Код эксплойта, версию ядра и настройки стенда компания не опубликовала, как отмечает The Hacker News.

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

При чём тут MPTCP и Go

MPTCP (Multipath TCP) — расширение TCP, которое позволяет одному подключению идти сразу по нескольким сетевым путям, например одновременно через Wi-Fi и мобильную сеть. В Linux программа должна сама попросить MPTCP при создании сокета, а ядро при этом по умолчанию его разрешает (net.mptcp.enabled=1). Если клиент MPTCP не предлагает, подключение работает как обычный TCP, поэтому снаружи включённый MPTCP никак не заметен.

С версии 1.24 язык Go включает MPTCP по умолчанию для всех слушающих сокетов на Linux. Администратору ничего делать не нужно: любой сервер на Go 1.24+, который сам не выключил эту настройку, принимает подключения через MPTCP. Xray собирается свежим Go (в go.mod версии v26.10.31 указан Go 1.27), а на типичном VPS для обхода блокировок Xray — единственная программа, которая слушает внешние порты. Отсюда вывод RPRX: для большинства пользователей Xray единственный IPv4 MPTCP-слушатель на сервере — это сам Xray или другой прокси на Go.

В самой записи CVE и в исправлении ядра MPTCP не упоминается, связь с ним пришла из разбора Anthropic. Ошибка находится в общем коде IPv4 TCP, и Red Hat пишет, что вызвать гонку может удалённый атакующий, которому доступен любой открытый TCP-сервис. Но вызвать гонку и довести её до root — разные вещи. RPRX рассуждает так: все IPv4 TCP-слушатели затронуты, однако через MPTCP получить root особенно легко, иначе Anthropic атаковала бы обычный TCP. Это вывод по косвенным признакам, а не доказанный факт: на 31 октября 2026 года публично root без MPTCP никто не показал, и команда безопасности Go прямо предупреждает, что системы без MPTCP-слушателей тоже могут оказаться уязвимы к похожим атакам.

MPTCP-слушатели есть не только у Xray

На проверочном хосте 31 октября 2026 года команда ss -Mlnp (её разбор ниже) показала MPTCP-слушатели у xray, у tailscaled и у собственного сервиса на Go. Это наблюдение одной машины, но оно показывает общую картину: MPTCP открывает любая программа на Go 1.24+, а не только прокси.

Позиция Go и решение Xray

29 октября в трекере Go открыли предложение выключить MPTCP по умолчанию. В ночь на 30 октября по московскому времени команда безопасности Go ответила заявлением в рассылке golang-announce, которое переслали и в oss-security. Лучшее исправление, по словам команды, — обновить ядро. MPTCP можно выключить переменной окружения GODEBUG=multipathtcp=0, строкой godebug multipathtcp=0 в go.mod при сборке или для отдельного сокета через net.ListenConfig.SetMultipathTCP. При этом команда называет выключение MPTCP в каждой программе по отдельности ненадёжной защитой: стоит забыть одну программу, и система уязвима, к тому же неизвестно, все ли рабочие эксплойты требуют MPTCP. Менять поведение самого Go в ответ на эту ошибку команда считает преждевременным.

Xray решил иначе. В запросе на изменение #7291, открытом 29 октября и принятом 31 октября, MPTCP в слушателях Xray выключается явно. Попутно исправлена старая неувязка: опция tcpMptcp в sockopt раньше умела только включать MPTCP, а значение false ничего не меняло, потому что Go и так включал его сам. Теперь опция снова работает в обе стороны, и кому MPTCP действительно нужен, может включить его вручную. RPRX объяснил выбор так: позиция Go обоснована, но для пользователей Xray выключение MPTCP по умолчанию заметно сокращает поверхность атаки, а выпуск в виде срочного обновления заодно напомнит обновить ядро.

Кого это касается

Владельцы серверов. В первую очередь — все, у кого на Linux-сервере с непропатченным ядром работает прокси на Go 1.24+ и слушает внешний IPv4-порт: Xray до v26.10.31 и другие программы на Go, которые MPTCP сами не выключают. В панелях управления версия ядра Xray обычно выбирается отдельно от версии самой панели, поэтому проверять стоит именно ядро.

Android-клиенты с доступом из локальной сети. В описании выпуска Xray отдельно отмечено, что ошибка касается не только серверов: Android-клиенту тоже грозит некоторая опасность, если в нём включены входящие SOCKS/HTTP-подключения с опцией «Разрешить подключения из локальной сети». Тогда клиент слушает порт для всей Wi-Fi-сети, и до него может дотянуться любой участник этой сети. Ядро на телефоне обновляет производитель, и часто с большой задержкой, а клиенты с устаревшим ядром Xray встречаются нередко — например, у Happ ядро Xray обновляется медленно. О том, чем ещё опасен открытый SOCKS-порт клиента, рассказано в заметке про неаутентифицированный SOCKS5 на localhost.

Обычные устройства, которые ничего не слушают. Ошибка находится в коде, который принимает входящие подключения. Устройство, у которого нет открытых для сети TCP-портов, этим путём не атакуется, а Go по умолчанию включает MPTCP только для слушающих сокетов, не для исходящих. Это вывод из описания исправления, а не отдельное заявление разработчиков.

Версия: MPTCP как примета Go-серверов

В том же комментарии RPRX мимоходом заметил, что неизвестно, не получил ли Великий китайский файрвол «бонус», и что REALITY, у которого MPTCP включён пассивно, по умолчанию выглядит ещё более странно. Возможное прочтение: REALITY выдаёт себя за чужой сайт, а настоящий сайт на nginx на предложение MPTCP отвечает обычным TCP. Сервер на Go 1.24+ отвечает согласием, и по этой разнице его можно отличить от маскировки. Это гипотеза из реплики разработчика, а не подтверждённый способ обнаружения; выключение MPTCP в v26.10.31 её снимает.

Как проверить свой сервер

Сначала узнайте версию ядра командой uname -r и сравните её с исправленными версиями выше. Для ядер из дистрибутива надёжнее смотреть трекер безопасности самого дистрибутива, потому что исправление переносят в старые ветки под их собственными номерами. В Debian исправление уже вышло: 6.1.190-1 для bookworm и 6.12.113-1 для trixie. В Ubuntu на 31 октября 2026 года все поддерживаемые выпуски значатся уязвимыми, исправление «в работе». Red Hat, по данным The Hacker News на 30 октября, относит RHEL 8, 9 и 10 к затронутым, а исправленных ядер ещё не выпустил.

Дальше проверьте, включён ли MPTCP в системе и кто его слушает:

uname -r                                  # версия ядра
cat /proc/sys/net/mptcp/enabled           # 1 — MPTCP в системе разрешён
cat /proc/sys/net/ipv4/tcp_migrate_req    # 1 — включён перенос запросов (второй вариант ошибки)
sudo ss -Mlnp                             # только MPTCP-слушатели и их процессы
xray version                              # версия ядра Xray; нужна v26.10.31 или новее

Флаг -M у ss показывает только MPTCP-сокеты. Не добавляйте к нему -t: вместе они выводят и обычные TCP-слушатели, и список выглядит хуже, чем есть. Если ss -Mlnp показывает процесс на внешнем IPv4-адресе или на 0.0.0.0 и [::], а ядро не исправлено, сервер подходит под сценарий из разбора Anthropic.

Что делать

  • Обновите ядро и перезагрузите сервер. Это единственная мера, которая закрывает ошибку целиком, в том числе для обычного TCP. Установленный пакет без перезагрузки ничего не меняет: работает старое ядро.
  • Обновите Xray до v26.10.31. Если сервер управляется панелью, обновите ядро Xray через неё и проверьте версию командой выше.
  • Выключите MPTCP в остальных программах на Go. Для службы systemd добавьте в её override строку Environment=GODEBUG=multipathtcp=0 (systemctl edit <служба>), затем перезапустите службу.
  • Или выключите MPTCP во всей системе: sysctl -w net.mptcp.enabled=0 и та же строка net.mptcp.enabled=0 в файле /etc/sysctl.d/, чтобы настройка пережила перезагрузку. Так защищены сразу все программы, но уже запущенные службы надо перезапустить: в рассылке oss-security предупредили, что программы на Go, запущенные после изменения, переходят на обычный TCP без проблем, а уже работающие могут выдавать ошибки на новых подключениях.
  • Проверьте, что net.ipv4.tcp_migrate_req равен 0, если не включали его сознательно.
  • Если исправленного ядра для вашего дистрибутива ещё нет, Red Hat предлагает правило nftables, которое отбрасывает входящие IPv4 TCP-пакеты с IP-опциями. Обычный трафик его не задевает, потому что TCP-опции живут в заголовке TCP, а не IP. По словам Red Hat, правило снижает риск, но полностью атаку не предотвращает, и его стоит проверить на своём трафике перед включением:
table inet cve_2026_98432 {
  chain input {
    type filter hook input priority -310; policy accept;
    ip protocol tcp ip hdrlength > 5 counter drop
  }
}

Сохраните правило в файл cve-2026-98432.nft, проверьте командой sudo nft --check --file cve-2026-98432.nft и примените sudo nft --file cve-2026-98432.nft. После обновления ядра таблицу удаляют: sudo nft delete table inet cve_2026_98432.

Вывод

Выключенный MPTCP убирает путь, по которому root уже показан, и поэтому выпуск Xray v26.10.31 стоит поставить сразу. Но ошибка остаётся в общем коде IPv4 TCP, и, как подчёркивают и Go, и Red Hat, окончательно сервер защищает только исправленное ядро.

Источники

📚 См. также


🤖 Эти статьи открыты — можно обучать на них ИИ

При желании вы можете натренировать ИИ на наших статьях. Исходное форматирование доступно в Forgejo: исходник этой заметки · скачать весь репозиторий одним zip-архивом.