На аудите VPN-периметра финтеха в начале 2026-го наткнулся на OpenVPN-сервер с плагином openvpn-auth-oauth2 в экспериментальном режиме plugin. Подключился штатным
openvpn CLI из Kali - без токена, без SSO-потока, без каких-либо credentials - и получил маршруты ко всей внутренней сети. Три минуты от первого SYN до полноценного VPN-туннеля. Root cause - одна строчка в Go-коде, которая возвращала FUNC_SUCCESS при отказе в аутентификации. CVSS 10.0, CWE-287 (Improper Authentication), advisory GHSA-246w-jgmq-88fg. Ниже - полный разбор: что ломается в коде, как воспроизвести на стенде и по каким маркерам выловить в логах.Бизнес-логика атаки: зачем атакующему обход аутентификации VPN
CVE-2026-41070 по MITRE ATT&CK - Exploit Public-Facing Application (T1190, Initial Access) через External Remote Services (T1133). Атакующий получает unauthenticated initial access напрямую во внутреннюю сеть, минуя весь OIDC-стек, IdP, MFA и любую логику, которую компания настраивала для защиты VPN-периметра.
Что это даёт на практике:
- Полный сетевой доступ к ресурсам за VPN без единого credential. IdP (Keycloak, Azure AD, Okta) даже не фиксирует попытку аутентификации - для него ничего не произошло
- Точка входа для lateral movement. После получения IP из VPN-пула атакующий видит внутренние подсети и может переходить к SMB-перечислению, LLMNR/NBNS poisoning, атакам на Active Directory
- Низкий шанс обнаружения. VPN-сервер продолжает работать штатно, availability не затрагивается (A:N в CVSS-векторе) - incident response может запоздать на часы или дни
Механика уязвимости openvpn-auth-oauth2: что ломается в коде
Два режима работы плагина
openvpn-auth-oauth2 - Go-приложение для интеграции OIDC SSO в OpenVPN. Работает в двух режимах:Management interface mode (по умолчанию, рекомендуемый). Плагин подключается к OpenVPN через management socket и передаёт решения об аутентификации через протокол управления. Этот режим не затронут CVE-2026-41070 - решения идут напрямую через management protocol, минуя механизм return codes.
Experimental plugin mode. Плагин загружается как shared library через директиву
plugin в server.conf. OpenVPN вызывает функции плагина напрямую и принимает решение об аутентификации на основе return code. Тут-то всё и ломается.Критический нюанс: когда плагин возвращает
OPENVPN_PLUGIN_FUNC_SUCCESS (status=0), OpenVPN немедленно считает аутентификацию пройденной. Файл auth_control_file проверяется только при возврате FUNC_DEFERRED - отложенной аутентификации. Это задокументированное поведение OpenVPN, и именно на нём строится вся уязвимость.Root cause: return code mismatch
Согласно advisory GHSA-246w-jgmq-88fg и данным NVD, баг находился в файлеlib/openvpn-auth-oauth2/openvpn/handle.go - в ветке ClientAuthDeny функции handleAuthUserPassVerify. Когда клиент не поддерживает WebAuth/SSO (не отправляет IV_SSO=webauth), плагин корректно определял, что аутентификация невозможна, записывал "0" (deny) в auth_control_file - но возвращал FUNC_SUCCESS:
Код:
case management.ClientAuthDeny:
if err := openVPNClient.WriteToAuthFile("0"); err != nil {
return c.OpenVPNPluginFuncError
}
return c.OpenVPNPluginFuncSuccess // BUG: OpenVPN трактует как "auth passed"
auth_control_file с записью "0" (deny) игнорировалось - для синхронного FUNC_SUCCESS оно не проверяется. Плагин считал, что отказ зафиксирован. OpenVPN считал, что плагин одобрил подключение. Два компонента смотрят на один и тот же return code - и видят разное.Патч в коммите
36f69a6 заменил возврат на OpenVPNPluginFuncError. Одно слово в return statement - разница между CVSS 0.0 и CVSS 10.0.Место в цепочке атаки: от recon до internal network
Fingerprinting уязвимого OpenVPN-сервера
Эксплуатация начинается с определения, работает ли целевой OpenVPN-сервер с openvpn-auth-oauth2 в experimental plugin mode. И тут есть фундаментальная проблема: определить режим работы плагина извне, до подключения, практически невозможно.Стандартный
nmap -sU -p 1194 <target> покажет, что на порту OpenVPN, но не раскроет ни тип плагина, ни его режим. Плагин аутентификации - серверная сторона, клиенту он не анонсируется в handshake.Косвенные признаки, доступные на этапе OSINT:
- Упоминания OIDC/SSO в документации для сотрудников или на внутреннем портале компании (если он доступен)
- Наличие OAuth2/OIDC endpoint'ов (Keycloak, Azure AD) в DNS-записях рядом с VPN-инфраструктурой
- Job postings с упоминанием openvpn-auth-oauth2 или OIDC VPN integration
Эксплуатация: подключение без OIDC SSO
Требования к окружению:- ОС: GNU/Linux (Kali, Ubuntu, Debian) с установленным пакетом
openvpn(CLI-версия, без GUI) - RAM: минимальные требования ОС (512 МБ достаточно)
- Сеть: прямая видимость до целевого OpenVPN-сервера (порт 1194/UDP или TCP)
- Файл: валидный
.ovpn-конфиг для целевого сервера (публичный endpoint, CA-сертификат)
openvpn CLI на Linux не поддерживает IV_SSO=webauth - ограничение CLI-клиента, который рассчитан на username/password аутентификацию. При подключении к уязвимому серверу в plugin mode:
Bash:
sudo openvpn --config target.ovpn --auth-user-pass /dev/null
--auth-user-pass /dev/null передаёт пустые credentials. Плагин обрабатывает запрос, обнаруживает отсутствие SSO-capabilities у клиента, выполняет ветку ClientAuthDeny - но возвращает FUNC_SUCCESS. OpenVPN выдаёт IP из пула, пушит маршруты. Всё. Ты внутри.После успешного подключения атакующий оказывается во внутренней сети. Дальше - стандартный kill chain: внутренний recon (
nmap по полученным маршрутам), перечисление сервисов, поиск AD-контроллеров, LLMNR/NBNS poisoning для перехвата хэшей - всё, что входит в типовой internal pentest после получения foothold.Предусловия и ограничения CVE-2026-41070
Уязвимость эксплуатируема только при одновременном выполнении всех условий:
| Условие | Детали |
|---|---|
| Версия плагина | openvpn-auth-oauth2 >= 1.26.3, < 1.27.3 (Go-пакет jkroepke/openvpn-auth-oauth2) |
| Режим работы | Experimental plugin mode - директива plugin в конфигурации OpenVPN |
| Тип клиента | Клиент без поддержки IV_SSO=webauth (стандартный openvpn CLI на Linux) |
Когда техника НЕ работает:
- Management interface mode (по умолчанию). Большинство production-деплоев используют этот режим - он рекомендован авторами плагина. Аутентификация управляется через management protocol, return codes плагина не задействованы. Attack surface радикально сужается.
- Клиенты с WebAuth/SSO. OpenVPN Connect 3+ и аналогичные GUI-клиенты отправляют
IV_SSO=webauthи проходят полноценный OIDC-поток. Уязвимая ветка кода для них не вызывается. - Версии за пределами диапазона. До 1.26.3 баг не существовал, с 1.27.3 - исправлен.
none, Automatable = no, Technical Impact = total. EPSS = 0.0044, percentile 0.3550 - ниже медианы. Массовой эксплуатации в дикой среде не зафиксировано, что логично: experimental plugin mode используется ограниченным числом деплоев.Но technical impact -
total. Если предусловия выполнены, атакующий получает полный доступ без каких-либо credentials. На пентесте это категория "one-click internal network" - при удачном стечении обстоятельств самый быстрый путь от периметра до domain admin.Обнаружение обхода аутентификации OpenVPN
Серверные логи и корреляция с IdP
Основной detection signal: рассинхронизация между логами OpenVPN и логами IdP. Клиент подключился к VPN и получил IP-адрес, но в Keycloak / Azure AD / Okta нет записи о выдаче OIDC-токена для этого пользователя или сессии.Маркеры в логах OpenVPN, на которые стоит настроить мониторинг:
- Подключения от клиентов, не передавших
IV_SSO=webauthв capabilities - Успешные подключения, которым не предшествовал HTTP redirect на OIDC authorize endpoint
- Client info с user-agent, указывающим на CLI-клиент
openvpnвместо корпоративного OpenVPN Connect
ClientAuthDeny для клиентов без SSO. Сопоставляем: плагин зафиксировал deny, но клиент всё равно получил IP из пула - однозначный индикатор эксплуатации.Правила корреляции для SIEM
Для Elastic SIEM или Splunk логика детекции сводится к отрицательной корреляции: VPN connection event минус IdP token issuance event = алерт. Конкретная реализация зависит от стека, но принцип один: если VPN-клиент получил сетевой доступ без прохождения OIDC flow - это аномалия.Дополнительный слой: мониторинг появления новых IP в VPN-пуле, за которыми следует нетипичный трафик - SMB-сканирование, LDAP-запросы к контроллерам домена, DNS-запросы к внутренним зонам. Это уже пост-эксплуатационные индикаторы, но в связке с отсутствием IdP-записи они формируют высокоприоритетный алерт.
Чеклист: патч и защитные меры
Уязвимость исправлена в openvpn-auth-oauth2 v1.27.3 (коммит36f69a6). Чеклист для сетевого администратора:
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
CVSS 10.0 на бумаге - число внушительное, но реальный attack surface определяется тем, сколько организаций используют experimental plugin mode в production. По данным CISA SSVC: automatable =
no, exploitation in the wild = none на момент анализа. Это не значит, что можно не патчить. Это значит, что у вас есть окно для спокойного, но оперативного обновления - не для паники.Парадокс этой CVE в том, что она бьёт именно тех, кто пытался сделать безопаснее - интегрировал OIDC SSO для VPN, настроил MFA через IdP, выстроил zero-trust flow. А потом выбрал experimental plugin mode вместо штатного management interface - может, из-за специфики деплоя, может, из-за ограничений инфраструктуры. Одна директива
plugin в конфигурации, один некорректный return code в плагине - и вся цепочка SSO превращается в декорацию. Management interface mode при этом работает корректно, рекомендован авторами и не требует ни дополнительных ресурсов, ни сложной настройки. Вывод простой: experimental - это не маркетинговое слово, а предупреждение. Если видите его в документации продукта, через который проходит аутентификация на периметре - трижды подумайте, прежде чем тащить в production. Если хочешь системно разобраться в аудите VPN-периметра и протокольных багов подобного класса - на курсе "Сетевая безопасность" от Codeby это одна из ключевых тем с лабораторным стендом, где такие сценарии прогоняются от fingerprinting до пост-эксплуатации.
Последнее редактирование модератором: