| 字段 | 详情 |
|---|
| 产品 | Cacti |
| 受影响版本 | 1.2.22 |
| 漏洞类型 | 未认证操作系统命令注入 |
| CVE | CVE-2022-46169 |
| CWE | CWE-77 — 命令注入 |
| 严重性 | 严重 |
| CVSS v3.1 | 9.8 |
| 攻击向量 | 网络 |
| 认证要求 | 无 |
| 用户交互 | 无 |
| 影响 | 机密性 / 完整性 / 可用性 |
| 修复版本 | 1.2.23 |
| 受影响组件 | remote_agent.php |
| 附加组件 | lib/functions.php |
| 主要受影响操作 | polldata |
已发布的 CVSS 向量为:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
官方公告将其评级为 9.8 严重。(GitHub)
实际上有两个漏洞被串联利用。
第一阶段 — 授权绕过
Cacti 的 remote_agent.php 接受未经正常认证的请求,但会尝试判断请求者是否为授权的轮询器(poller)。
授权流程实际上执行如下操作:
HTTP 请求
│
▼
remote_agent.php
│
▼
remote_client_authorized()
│
▼
get_client_addr()
│
▼
gethostbyaddr()
│
▼
poller 表主机名比对
问题出在 get_client_addr()。
在 1.2.22 版本中,该函数会检查多个源自 HTTP 的服务器变量,包括转发客户端 IP 的请求头。公告解释称,攻击者可控的 HTTP_* 值可以影响该函数返回的 IP 地址。(GitHub)
这意味着应用程序可能被欺骗,使其相信:
攻击者
↓
"我的 IP 是 Cacti 服务器"
↓
gethostbyaddr()
↓
Cacti 服务器主机名
↓
与 poller 表匹配
↓
已授权
因此,攻击者无需拥有合法的 Cacti 账户。
绕过授权检查后,值得关注的端点功能是 polldata 操作。
相关的执行路径大致如下:
remote_agent.php
│
▼
polldata
│
▼
poll_for_data()
│
├── host_id
├── local_data_ids
└── poller_id
│
▼
poller_item 查询
│
▼
POLLER_ACTION_SCRIPT_PHP
│
▼
proc_open()
│
▼
操作系统命令执行
关键的错误在于对 poller_id 的处理。
应用程序使用以下方式获取该值:
get_nfilter_request_var()
而不是强制要求其为整数。
该攻击者可控的值最终会成为传递给 PHP proc_open() 的命令的一部分。官方公告明确将其认定为命令注入的原语。(GitHub)
概念上:
攻击者可控输入
↓
poller_id
↓
字符串拼接
↓
proc_open()
↓
操作系统命令
这是该漏洞的关键部分。
对于你的 PoC 分析而言,有趣的一点是单独任何一个漏洞都不是全部。
这是一个漏洞链:
┌──────────────────────────┐
│ 未认证攻击者 │
└────────────┬─────────────┘
│
▼
remote_agent.php
│
▼
通过客户端 IP 逻辑
实现授权绕过
│
▼
polldata
│
▼
poller_item 查询
│
▼
POLLER_ACTION_SCRIPT_PHP
│
▼
攻击者输入
→ poller_id
│
▼
proc_open()
│
▼
命令执行
│
▼
RCE
在你的报告中,这是一个非常重要的区分点:
CVE-2022-46169 不仅仅是"remote_agent.php 中的一个糟糕参数"。它是一个授权绕过 + 命令注入的链式漏洞。
官方公告确认,可利用的执行条件要求存在一个 action 为 POLLER_ACTION_SCRIPT_PHP 的 poller_item。(GitHub)
你的 PoC 应明确记录这一点,因为它是一个重要的分析细节。
目标环境需要配置一个合适的 poller_item,其 action 为:
POLLER_ACTION_SCRIPT_PHP
Cacti 公告指出,这在生产环境中很常见,因为预定义模板(如 Device - Uptime 和 Device - Polling Time)可以创建这些条目。(GitHub)
所以不要写:
"每个 Cacti 1.2.22 安装都自动可利用。"
更准确的技术表述是:
Cacti 1.2.22 存在漏洞,而命令执行是否成功取决于是否存在合适的
poller_item配置。
host_id 和 local_data_id 很重要poll_for_data() 并不会直接执行所提供的 poller_id。
它首先使用与以下值对应的参数查询 poller_item:
host_id
local_data_id
然后检查所返回条目的 action。
可利用的条件实际上为:
host_id
+
local_data_id
↓
poller_item
↓
action == POLLER_ACTION_SCRIPT_PHP
↓
可利用的执行路径
原始公告指出,这些标识符可以被发现,因为相关条目存在于应用程序的数据库中,并且生产环境中很可能存在合适的条目。(GitHub)
对于公开的 PoC,我建议明确演示这一前提条件,而不是将其隐藏。
对于你要发布的内容,我建议让 PoC 演示命令执行,但不向读者提供武器化的反向 Shell 载荷。
例如,将你的演示结构设计为:
1. 在隔离的虚拟机中部署 Cacti 1.2.22
2. 使用 POLLER_ACTION_SCRIPT_PHP 配置一个 poller_item
3. 确认 remote_agent.php 可访问
4. 演示授权决策被影响
5. 到达 polldata 执行路径
6. 使用无害的命令执行标记
7. 捕获产生的应用程序/日志证据
8. 升级到 1.2.23
9. 重复测试
10. 演示该漏洞不再可利用
这样既能提供合法的漏洞演示,又不会把报告变成现成的互联网 RCE 武器。
你可以将漏洞代码分为三个区域。
remote_agent.php负责暴露远程代理功能并分发所请求的操作。
remote_agent.php
│
└── action = polldata
│
▼
poll_for_data()
lib/functions.php包含 get_client_addr()。
问题设计在于,在判断请求者的实际网络地址时,信任了源自 HTTP 的值。
官方公告列出了多个在回退到实际远程地址之前会被检查的 HTTP 相关变量。(GitHub)
proc_open()最终的危险汇聚点是构造通过 proc_open() 执行的 PHP 命令。
公告将可利用的流程标识为:
poller_id
↓
get_nfilter_request_var()
↓
命令构造
↓
proc_open()
(GitHub)
Cacti 公告指出了两项重要的修复措施。
首先,poller_id 应被视为整数:
get_nfilter_request_var()
↓
get_filter_request_var()
其次,该值在并入命令之前还应进行 shell 转义:
escapeshellarg($poller_id)
公告特别建议同时采取这两项措施。(GitHub)
授权方面也需要停止允许攻击者任意影响用于授权的客户端 IP。(GitHub)
Cacti 1.2.22
│
├── 存在漏洞
├── 授权绕过
├── 命令注入
└── 潜在的未认证 RCE
Cacti 1.2.23
│
└── CVE-2022-46169 已修复
厂商公告将 1.2.22 列为受影响版本,并将 1.2.23 列为已修复的 1.2.x 版本。(GitHub)
Amazon 的安全公告独立地将该问题描述为允许未认证攻击者执行任意命令,并给出了 9.8 的 CVSS 评分。(AWS Training and Certification)
我会使用类似这样的标题:
CVE-2022-46169 — Cacti 1.2.22 未认证命令注入 / RCE
或者更技术化一些:
CVE-2022-46169:Cacti 1.2.22 远程代理授权绕过与命令注入链分析
你的漏洞摘要可以这样写:
Cacti 1.2.22 的远程代理功能中存在一个严重的漏洞链。攻击者可以操纵客户端地址判定逻辑来绕过远程代理的授权检查。一旦到达
polldata功能,对poller_id参数的验证不足使得攻击者可控的数据能够到达通过proc_open()执行的命令。在包含POLLER_ACTION_SCRIPT_PHP轮询器条目的配置下,这可能导致未认证的远程命令执行。该问题已在 Cacti 1.2.23 中修复。 (GitHub)
对你的研究有一个重要的更正: 不要将此漏洞与 CVE-2023-39362 混淆。那个后来的 Cacti RCE 影响的是 1.2.24,并在 1.2.25 中修复,因此它不是你在 1.2.22 PoC 中想要的漏洞。(NVD)