这是一个安全、无需认证的检测器,用于检测 KB4893 中描述的 Veeam Service Provider Console 漏洞(发布于 2026-08-04)。它针对每个目标只回答一个问题,且在任何认证或 TLS 之前:该控制台是否已应用 KB4893 修复?
最核心的一对漏洞构成了一条攻击链。CVE-2026-58073(CVSS 9.5)允许未认证的网络对等方模拟已连接的管理代理,并获得该代理的真实证书,因为代理握手是根据对等方写入其自身证书中的 GUID 来决定授权的。CVE-2026-58072(CVSS 9.0)是一个任意文件写入漏洞,一旦你持有代理身份即可利用。两者串联起来,就是在管理所有租户备份的控制台上实现未认证的远程代码执行。同一份公告还修复了 CVE-2026-58071(CVSS 8.2,以门户管理员身份代理设备 API)和 CVE-2026-58067(CVSS 8.7,未认证的内存耗尽型 DoS)。CVE-2026-58073 和 CVE-2026-58072 是通过 HackerOne 报告给 Veeam 的;公告未提及报告者姓名。
此脚本不会尝试模拟、请求证书或写入文件。它只读取路由器通告的协议代次,仅此而已。
是的。该检测器专为生产和评估场景设计:
Connector 握手,并指定一个不存在的接收方。不协商 TLS 会话,不提供证书,也从不调用 SaveFiles。ChannelHostProxy.m_multiplexers 中进行一次失败的字典查找。不注册接收方,不构建通道或多路复用器,不触碰任何代理记录。Receiver 类型的握手会注册名称;此工具从不发送这种握手。ConnectionHub.log 中的六行日志,每行都带有接收方名称 bf-probe-<uuid4>,因此防御者可以区分扫描与攻击。具体日志行如下所示。VULNERABLE,因此安静的 TCP 服务不会被误认为未打补丁的控制台。每个目标,该工具会打开两次 TCP 连接,并在每次连接上发送一个 ConnectionHub 握手,指定一个不存在的接收方 bf-probe-<uuid4>。
在默认的 --transport auto 模式下,如果目标的传输方式与其端口隐含的方式不匹配,则会多消耗一次连接:错误传输方式的探测会在握手期间被拒绝(在读取任何接收方名称之前),然后正确的传输方式会用于两次真正的探测。固定使用 --transport direct 或 --transport gateway 可将其严格控制在两次连接——如果你在变更请求中注明了连接次数,这一点值得做。
服务器状态变更:无。 Connector 代码路径在 ChannelHostProxy.m_multiplexers 中执行字典查找,未命中并返回错误。不注册接收方,不创建多路复用器或通道,不协商 TLS 会话,不触碰任何代理记录。此工具从不发送 Receiver 类型的握手,而只有这种握手才会注册名称。
日志条目写入 %ProgramData%\Veeam\Veeam Availability Console\Log\Server\ConnectionHub.log。以下内容逐字摘自一个运行中的 9.2.1.33875 ConnectionHub,时间戳和 scope JSON 已精简:
探测 1(版本 6),已打补丁和未打补丁的构建均相同:
[INFO] ChannelHostProxy: Accept connection begin {"RemoteEndPoint":"<ip>:<port>","Line":"1"}
[INFO] ChannelHostProxy: Accept connection end {"RemoteEndPoint":"<ip>:<port>","Line":"2",...}
[WARN] ChannelHostProxy: Cannot connect transmitter. Requested receiver not found
(receiver name:bf-probe-<uuid>) {"RemoteEndPoint":"<ip>:<port>","Line":"3",...}
探测 2(版本 7),仅已打补丁的构建:
相同的三行日志
探测 2(版本 7),未打补丁的构建:
[INFO] ChannelHostProxy: Accept connection begin
[WARN] ChannelHostProxy: Handshake failed. Reason:Unsupported client version "7"
[INFO] ChannelHostProxy: Accept connection end
两次连接、六行日志、无其他条目、无状态变更——已在真实主机上确认。
ConnectionHub.log 中的字面字符串 bf-probe- 可标识此工具的流量,因此防御者可以归因,扫描团队也可以证明他们发送了什么。如果你需要不同的标记,可以修改源码中的 RECEIVER_PREFIX。
ConnectionHub 管理代理路由器在任何认证或 TLS 之前读取客户端握手,Request.Read 会根据硬编码的范围验证客户端通告的协议版本。修复在修复 CVE 的同一构建中扩大了该范围:
| 构建 | 检查 | 接受 |
|---|---|---|
<= 9.2.1.33875(易受攻击) | (uint)(versionByte - 3) <= 3 | 3, 4, 5, 6 |
>= 9.3.0.35057(已打补丁) | (uint)(versionByte - 3) <= 4 |
因此,通告版本 7 的握手是一个干净的二进制判别器。检测器对每个目标发送两次探测,顺序是有原因的(传输检测可能增加第三次——见下文):
| 探测 | 通告 | 目的 |
|---|---|---|
| 1 | 版本 6 | 必须返回 Requested receiver not found,证明目标确实是 VSPC ConnectionHub |
| 2 | 版本 7 | 有回复表示 PATCHED;无回复表示 VULNERABLE |
如果没有第一阶段的门控,探测 2 中的无回复也会匹配互联网上任何安静的 TCP 服务,防火墙会被报告为易受攻击的 Veeam 控制台。
它适用于管理代理使用的两条路径:
| 传输方式 | 端口 | 暴露面 |
|---|---|---|
| 直连 ConnectionHub | 9999 | 通常为内部 |
| 通过 Veeam Cloud Connect 网关 | 6180 | 按设计面向互联网 |
网关路径需要一个中继前导(relay prologue),而直连路径不能有,因此探测 1 兼作传输检测。在默认的 --transport auto 模式下,它先尝试一种传输方式,如果指纹门控未通过,则尝试另一种。通过的那一种会被锁定,探测 2 复用该方式——混合目标文件无需逐主机标注。
锁定是关键。如果探测 2 可以在另一种传输方式上重试,那么无回复就不再能归因于版本检查,而只能归因于"两条字节路径之一未应答",这正是制造虚假 VULNERABLE 的方式。
先尝试哪种传输方式由端口决定,这并非表面功夫——两种不匹配的失败速度差异很大:
| 不匹配 | 远端如何解读 | 代价 |
|---|---|---|
| 中继前导 → 直连中心 | int16 元数据 hostType 44 / versionByte 0,未通过 Request.Read 的范围检查 | 一个往返内处理完毕 |
| 直连握手 → 网关 | int32 帧长度 1,012,729,346 | 网关等待永远不会到达的字节;耗尽完整超时 |
因此 auto 模式优先使用拥有该端口的服务:6180 端口优先网关,其他情况优先直连。这样常见情况只需一次尝试,昂贵的错误匹配不会出现在快速路径上。如果探测完全无法打开 TCP,则会短路而不尝试第二种传输方式,因此大规模扫描中的死主机只消耗一次超时,而不是两次。
VULNERABLE 表示"KB4893 修复不存在",而非"这是 9.2.1.33875"。早于 9.2.1 的构建共享相同的版本检查,因此它们应报告协议 6 并被报告为易受攻击(根据代码推断,而非实测——见局限性),但该工具无法区分 9.2.1 与 9.1 或 8.1。如果需要精确构建号,请在控制台 UI 中确认。
# 单主机(默认 TCP/9999)
./cve_2026_58073_check.py vspc.example.com
# 显式端口,多个主机
./cve_2026_58073_check.py vspc.example.com:9999 10.0.0.5
# 扫描列表文件,每行一个目标('#' 注释),紧凑输出
./cve_2026_58073_check.py -f targets.txt --brief
# 面向管道的机器可读输出
./cve_2026_58073_check.py -f targets.txt --json > results.json
# Veeam Cloud Connect 网关——中继传输方式自动检测
./cve_2026_58073_check.py cc-gw.example.com:6180
# 固定传输方式以跳过检测(端口随后默认为 6180)
./cve_2026_58073_check.py --transport gateway cc-gw.example.com
# 无网络访问时验证线路编解码器
./cve_2026_58073_check.py --self-test
未打补丁的控制台(默认两行输出)。[!] 标记和 VULNERABLE 在 TTY 上显示为红色:
$ ./cve_2026_58073_check.py vspc.example.com
[!] vspc.example.com:9999: VULNERABLE [protocol-7-rejected]
ConnectionHub rejects protocol 7 but accepts 6, so the KB4893 fixes are absent (<= 9.2.1.33875)
已打补丁的控制台:
$ ./cve_2026_58073_check.py patched.example.com
[+] patched.example.com:9999: PATCHED [protocol-7-accepted]
ConnectionHub accepts protocol 7, so the KB4893 fixes are present (>= 9.3.0.35057)
网关目标,中继传输方式自动检测。(gateway) 后缀表示得出判定所使用的传输方式:
$ ./cve_2026_58073_check.py cc-gw.example.com:6180
[!] cc-gw.example.com:6180 (gateway): VULNERABLE [protocol-7-rejected]
ConnectionHub rejects protocol 7 but accepts 6, so the KB4893 fixes are absent (<= 9.2.1.33875)
扫描整个环境,每主机一行对齐输出(--brief)。如果任何主机为 VULNERABLE,退出状态为 1,否则为 0——便于在脚本中使用:
$ ./cve_2026_58073_check.py -f targets.txt --brief; echo "exit: $?"
VULNERABLE vspc.example.com:9999 protocol-7-rejected
PATCHED patched.example.com:9999 protocol-7-accepted
UNAFFECTED fileserver.example.com:9999 not-vspc
ERROR unused.example.com:9999 unreachable
exit: 1
面向管道的机器可读输出(--json)。每个目标包含每次探测,因此可以从证据重新推导结论,而非仅凭信任。transport 是得出判定所使用的传输方式,每次探测都带有其使用的传输方式——因此自动检测的目标也会显示被拒绝的尝试:
$ ./cve_2026_58073_check.py vspc.example.com --json
[
{
"target": "vspc.example.com:9999",
"host": "vspc.example.com",
"port": 9999,
"transport": "direct",
"verdict": "VULNERABLE",
"reason": "protocol-7-rejected",
"detail": "ConnectionHub rejects protocol 7 but accepts 6, so the KB4893 fixes are absent (<= 9.2.1.33875)",
"protocol_version": 6,
"affected_cves": [
"CVE-2026-58073",
"CVE-2026-58072",
"CVE-2026-58071",
"CVE-2026-58067"
],
"probes": [
{
"version_byte": 6,
"transport": "direct",
"connected": true,
"responded": true,
"status": "Error",
"message": "Cannot connect transmitter. Requested receiver not found (receiver name:bf-probe-b7c40be0-e2e8-41dc-9fc3-cbbd7345954a)",
"error": ""
},
{
"version_byte": 7,
"transport": "direct",
"connected": true,
"responded": false,
"status": "",
"message": "",
"error": ""
}
]
}
]
| 代码 | 含义 |
|---|---|
0 | 没有目标为 VULNERABLE |
1 | 至少一个目标为 VULNERABLE |
2 | 用法错误(参数错误 / 目标文件不可读) |
--transport auto 的网关部分;固定使用 --transport direct 可将未经测试的路径完全排除在扫描之外。VULNERABLE 判定反映的是补丁状态,而非是否有人利用了该控制台。利用行为会在已打补丁和未打补丁的构建中都在控制台日志中留下自己的痕迹;请另行排查。升级到 Veeam Service Provider Console 9.3.0.35057 或更高版本(KB4893)。所有四个问题都在这一个构建中修复,且没有 9.2.x 反向移植,因此修复方式是版本升级而非热修复。
升级不会做两件事。它不会限制谁能访问 TCP/9999,该端口应只应答管理代理所在的子网。它也不会撤销控制台已签发的代理证书,包括在未打补丁期间签发给攻击者的证书。如果你发现被利用的证据,请向 Veeam 支持开立案例,获取关于受损代理证书的指导:轮换证书并非文档化流程,而且你在门户中可以管理的证书并非签署代理证书的 CA。
此代码根据 MIT 许可证 分发。
未经双方事先同意而使用此工具攻击目标属于违法行为。最终用户有责任遵守所有适用的地方、州和联邦法律。开发者不承担任何责任,也不对因使用本程序造成的任何滥用或损害负责。
| 3, 4, 5, 6, 7 |
| 标志 | 描述 |
|---|
targets | 一个或多个 HOST[:PORT](端口默认为 9999,使用 --transport gateway 时为 6180) |
-f, --targets-file FILE | 从文件读取目标(每行一个;# 注释) |
--transport {auto,direct,gateway} | 如何到达 ConnectionHub。auto(默认)按目标检测;gateway 前置 Cloud Connect 中继前导并将端口默认为 6180 |
-p, --port PORT | 覆盖默认端口 |
--timeout SECS | 每次探测的超时时间(默认:8) |
--workers N | 并发目标数(默认:16);输出保持输入顺序 |
-b, --brief | 每个目标单行对齐输出——适合扫描大量主机 |
--json | 输出结构化 JSON,包括每个目标发送的每次探测 |
--no-color | 禁用彩色输出(同时遵循 NO_COLOR 和非 TTY 环境) |
--self-test | 验证 .NET 线路编解码器并退出;不访问网络 |
| 判定 | 原因标签 | 含义 |
|---|
VULNERABLE | protocol-7-rejected | 已确认的 VSPC ConnectionHub,接受协议 6 但拒绝 7。KB4893 修复不存在(<= 9.2.1.33875)。 |
PATCHED | protocol-7-accepted | 已确认的 VSPC ConnectionHub,接受协议 7。KB4893 修复已存在(>= 9.3.0.35057)。 |
UNAFFECTED | not-vspc | 接受 TCP 但未在任何尝试的传输方式上应答有效的 ConnectionHub 握手,因此不是 VSPC ConnectionHub。 |
INCONCLUSIVE | unexpected-reply | 对指纹探测的应答不是 Requested receiver not found。 |
INCONCLUSIVE | inconclusive-discriminator | 通过指纹门控,但对版本 7 探测的应答既不是通过也不是失败——或者第二次连接完全失败。请重试。 |
ERROR | unreachable | 无法连接,或 Cloud Connect 网关在首次尝试的传输方式上拒绝了中继前导(在 auto 模式下,这意味着任何端口为 6180 的目标)。 |