首页 网络安全 正文

OpenVPN tls-crypt-v2拒绝服务CVE-2026-35058

摘要

栋科技漏洞库关注到 OpenVPN 2.6.x 及 2.8_git 版本的中存在的拒绝服务漏洞,现已被追踪为CVE-2026-35058,CVSS 3.1 评分7.7。

OpenVPN是一款开源、跨平台、基于 SSL/TLS 的 VPN(虚拟专用网络)软件与协议,可用于在公网上建立加密隧道,安全传输数据。

一、基本情况

OpenVPN是开源 VPN 软件,广泛用于构建安全远程访问和站点间隧道,在应用层建立安全隧道通过虚拟网卡(TUN/TAP)处理流量。

OpenVPN 是中小企业与个人首选的开源 VPN 方案,兼具安全、灵活、跨平台优势,产品广泛用于远程办公、跨地域组网与安全上网。

OpenVPN tls-crypt-v2拒绝服务漏洞CVE-2026-35058

OpenVPN是一套虚拟专用网络(VPN)系统,该产品被用于在路由 / 桥接模式及远程访问场景中建立安全的点到点或站点到站点连接。

栋科技漏洞库关注到 OpenVPN 2.6.x 及 2.8_git 版本的中存在的拒绝服务漏洞,现已被追踪为CVE-2026-35058,CVSS 3.1 评分7.7。

二、漏洞分析

CVE-2026-35058是 OpenVPN 相关版本 TLS Crypt v2 客户端密钥提取功能中存在可触发断言漏洞,特制网络数据包可导致拒绝服务。

OpenVPN 的 --tls-crypt-v2 功能提供客户端级预认证密钥,保护控制信道免受未认证访问,该功能常常部署于企业及商用 VPN 产品中。

其作为纵深防御机制抵御针对 TLS 握手的拒绝服务攻击,但 tls-crypt-v2 被定位为拒绝服务攻击缓解层,其实现漏洞将造成更高影响。

tls_crypt_v2_extract_client_key 函数处理 tls-crypt-v2 客户端密钥提取时,接收到缓冲区包含完整的控制信道数据包(含操作码字节)。

但代码在读取 WKC 长度信息前未先跳过操作码,导致将操作码内容误解释为密钥数据的一部分。

同时 tls_crypt_unwrap 函数中存在一处过于严格的 ASSERT(src->len > 0) 检查,可被特定异常数据包触发。

持有特定属性 tls-crypt-v2 客户端密钥的认证攻击者,或处于活动会话中的中间人攻击者,因此可发送异常构造的数据包触发上述断言。

这意味着攻击者可发送一系列恶意数据包触发该漏洞,使 OpenVPN 服务器进程崩溃并导致拒绝服务。

CVE-2025-2704修复了 tls_crypt.c 文件中 tls_crypt_v2_extract_client_key () 函数的预认证内存耗尽漏洞。

该修复添加了!initial_packet 防护逻辑,

以跳过对重传的 P_CONTROL_WKC_V1 数据包的完整 WKC 处理(此类数据包在会话已建立后到达)。

该防护逻辑会从缓冲区中移除 WKC 数据,使调用方可将剩余数据作为普通 P_CONTROL_V1 数据包处理。

但该防护逻辑未验证移除数据后缓冲区是否仍有剩余内容。

代码库中的两处代码逻辑共同导致程序崩溃:

// tls_crypt.c
tls_crypt_v2_extract_client_key(), !initial_packet path
if (!initial_packet)
{
    /* ... comment about ignoring WKC on resend ... */
    /* Remove client key from buffer so tls-crypt code can unwrap message */
    ASSERT(buf_inc_len(buf, -(BLEN(&wrapped_client_key))));  // [1]
    return true;                                             // [2]
}

在位置[1]处,`buf_inc_len()`函数通过`BLEN(&wrapped_client_key)`减小`buf->len`的值。

当攻击者将数据包中的WKC长度字段设置为等于数据包总长度时,该调用会将`buf->len`减至0。

在位置[2]处,该函数返回true(成功),但未检查缓冲区此时是否为空,导致调用方按照存在有效控制消息的逻辑继续执行。

调用方 read_control_auth() 函数(位于ssl_pkt.c文件第236行)将此时为空的缓冲区传递给 tls_crypt_unwrap() 函数,

该函数会立即触发无条件断言:

// tls_crypt.c:219
ASSERT(src->len > 0);  // [3] src->len == 0 → SIGApT

在位置[3]处,ASSERT宏调用 abort() 函数,向进程发送 SIGApT 信号并立即终止服务器进程。所有已连接的VPN会话均被断开。

触发攻击的最小数据包长度为11字节:

Offset  Field           Size  Value
------  -----           ----  -----
0       Opcode|KeyID    1     0x58 (P_CONTROL_WKC_V1 << 3 | 0)
1       Session ID      8     Attacker's session ID (from handshake)
9       WKC length      2     htons(11) — equals total packet length

!initial_packet 路径不会对 WKC 进行密码学校验。

该路径假定 WKC 是之前已验证密钥的无害重传,并直接移除wkc_len字节数据,不检查内容。

由于密码学校验本应在移除操作之后调用的tls_crypt_unwrap()函数中执行,

因此攻击数据包无需有效的加密、HMAC 或 WKC 内容,仅需正确的操作码和匹配的会话 ID 即可。

该攻击需要三个数据包来建立会话上下文,使initial_packet变为 false。

数据包流程为:

先发送P_CONTROL_HARD_RESET_CLIENT_V3消息,

再发送P_CONTROL_HARD_RESET_SERVER_V2消息,

最后发送P_CONTROL_WKC_V1消息。

数据包 1 和 3 需要有效的tls-crypt-v2客户端密钥。数据包 3 创建多实例并将密钥状态推进至S_START。

数据包 4(攻击包)在处理时,由于会话状态已为S_START,因此initial_packet=false,触发存在漏洞的代码路径。

服务器重启后,该攻击可立即重复实施。

攻击前提条件:

(1)服务器在服务端模式下启用了--tls-crypt-v2;

(2)攻击者持有该服务器的任意有效tls-crypt-v2客户端密钥,包括合法签发、泄露或已吊销的密钥。

三、POC概念验证

要触发该漏洞,服务器必须配置支持tls-crypt-v2,这需要为客户端和服务器生成 TLS Crypt v2 密钥对。可通过以下命令行完成。

管理员已设置登录后刷新可查看

TLS 的使用还需要配置公钥基础设施(PKI)。

可通过位于 https://github.com/openvpn/easy-rsa 的 easyrsa 脚本完成配置。可使用以下命令构建证书颁发机构(CA):

$ /path/to/easyrsa --pki=./pki init-pki
$ /path/to/easyrsa --pki=./pki gen-dh
$ /path/to/easyrsa --pki=./pki build-ca

接下来,可使用以下命令生成服务端和客户端证书。

这些命令将生成证书请求,并将已签名证书存储在 `./pki/issued` 目录下,证书密钥存储在 `./pki/private` 目录下。

$ /path/to/easyrsa --pki=./pki gen-req server
$ /path/to/easyrsa --pki=./pki sign-req server server
$ /path/to/easyrsa --pki=./pki gen-req client
$ /path/to/easyrsa --pki=./pki sign-req client client

可使用以下命令行启动服务端,配置触发该漏洞所需的参数。

$ /path/to/openvpn --dev tun --proto udp --port $port --tls-server --ca pki/ca.crt --cert pki/issued/server.crt --key pki/private/server.key --dh pki/dh.pem --tls-crypt-v2 tls-crypt-v2.server.key --topology subnet --ifconfig 10.8.0.1 255.255.255.0

该概念验证还包含一份服务端配置,可用于以正确选项运行OpenVPN服务端。

$ /path/to/openvpn --config=/path/to/server.conf

服务端启动后,可使用以下命令行运行概念验证代码。

$ python3 poc.py $host $port $tls_crypt_v2_server_key

服务端日志(--verb 4)确认程序崩溃:

2026-03-31 21:07:03 udp4:127.0.0.1:60803 Control Channel: using tls-crypt-v2 key
2026-03-31 21:07:03 udp4:127.0.0.1:60803 control channel security already setup ignoring wrapped key part of packet.
2026-03-31 21:07:03 udp4:127.0.0.1:60803 Assertion failed at tls_crypt.c:219 (src->len > 0)
2026-03-31 21:07:03 udp4:127.0.0.1:60803 Exiting due to fatal error
2026-03-31 21:07:03 udp4:127.0.0.1:60803 Closing tun/tap interface

服务器在接收到首个攻击数据包时便被终止。从首个数据包发送到崩溃的总时间:不足1秒。

测试环境:Linux 5.15.0,OpenVPN 2.8_git(master a04a3ced),启用ASAN检测的编译版本。

同时在已修复CVE-2025-2704漏洞的Debian软件包(2.6.12-0ubuntu0.24.04.3~bpo22.04.1)中得到验证。

缓解措施

建议的修复方案是:在tls_crypt_v2_extract_client_key()函数的!initial_packet分支中,校验移除WKC数据后缓冲区不为空。

修复版本通过在 tls_crypt_v2_extract_client_key 函数的缓冲区读取流程,先调用 buf_advance 跳过操作码字节再读取密钥长度信息。

消除了将操作码误解释为密钥数据的逻辑错误;

同时移除 tls_crypt_unwrap 中过于严格的 ASSERT(src->len > 0) 检查,

改为依赖后续已有的数据包长度校验逻辑返回正确错误,避免了异常数据包触发进程终止。

四、影响范围

OpenVPN 2.6.x

OpenVPN 2.8_git

五、修复建议

OpenVPN ≥ 2.7.2

OpenVPN ≥ 2.6.20

六、参考链接

管理员已设置登录后刷新可查看



扫描二维码,在手机上阅读
评论
更换验证码
友情链接