1. 项目概述
最近在整理内部安全资产时,又回顾了Cacti这个老牌监控系统的几个历史高危漏洞,其中CVE-2022-46169这个前台未授权命令注入漏洞,其利用链的巧妙和危害性都颇具代表性。它不像一些需要复杂交互的漏洞,攻击者只需要构造一个特殊的HTTP请求,就能在未登录的情况下,在服务器上执行任意命令,直接获取系统权限。对于仍在运行受影响版本(1.2.17至1.2.22)的Cacti实例来说,这无异于门户大开。今天,我就从一个安全研究兼运维的角度,带大家完整地走一遍这个漏洞的复现过程。我会详细拆解漏洞的成因、利用条件,并提供一个可操作的、从环境搭建到成功获取 /etc/passwd 文件内容的完整复现指南。无论你是想深入理解漏洞原理的安全研究员,还是负责排查线上风险的运维工程师,这篇文章都能给你提供清晰的路径和实用的排查思路。
2. 漏洞原理深度解析
2.1 Cacti与 remote_agent.php 的功能背景
Cacti是一套基于PHP/MySQL开发的网络流量监测图形分析工具,它通过SNMP协议从网络设备获取数据,并使用RRDtool绘制成直观的图形。在分布式监控场景中,Cacti允许部署“数据收集器”(Data Collector)。这些收集器运行在被监控设备或代理主机上,定期执行数据收集任务,然后将结果回传给中心的Cacti服务器。
remote_agent.php 正是为这种分布式架构设计的。它是一个位于Cacti Web根目录下的脚本,运行在数据收集器上。中心Cacti服务器会向这个脚本发起请求,以触发数据收集任务或获取状态。为了保证通信安全,这个脚本设计了一套客户端IP地址校验机制:它只接受来自预定义IP地址(在Cacti的“Settings” -> “Polling”中配置的“Remote Pollers”)的请求。
2.2 漏洞核心: X-Forwarded-For 头校验逻辑缺陷
漏洞的根源在于 remote_agent.php 中对客户端IP的校验逻辑存在缺陷。我们先来看一下存在漏洞的代码逻辑(基于Cacti 1.2.22版本):
脚本首先会尝试从几个常见的HTTP头中获取客户端的真实IP,优先级顺序通常是: X-Forwarded-For (XFF) > X-Real-IP > $_SERVER[‘REMOTE_ADDR’] 。这么做的本意是为了在反向代理(如Nginx)后的环境中能正确识别原始客户端。
问题出在后续的校验函数 remote_client_authorized() 中。这个函数会将获取到的“客户端IP”与Cacti配置文件中允许的IP列表进行比对。关键在于,当请求来自本地( 127.0.0.1 或 ::1 )时,校验会被 绕过 。这是为了方便本地进程调用。
攻击者利用的正是这一点。他们可以在HTTP请求中手动添加一个 X-Forwarded-For: 127.0.0.1 的请求头。有漏洞的代码会优先采用这个头中的值作为客户端IP。由于这个值是 127.0.0.1 (本地回环地址),IP校验逻辑被成功绕过,攻击者的请求被误认为是合法的本地请求,从而获得了执行后续操作的权限。
注意 :这里有一个常见的误解,认为攻击者需要将请求发送到
127.0.0.1。实际上并非如此。攻击者仍然是向目标服务器的公网IP和端口发送请求,只是在HTTP头中伪造了IP信息。漏洞在于服务端程序 信任并使用了 这个未经验证的、用户可控的请求头。
2.3 命令注入点: poller_id 参数的处理
绕过IP校验只是第一步,真正的杀伤力在于后续的命令注入。 remote_agent.php 脚本在通过校验后,会根据请求参数执行相应的动作,其中一个是 polldata 。
在 polldata 处理流程中,脚本会使用 proc_open() 函数调用一个外部命令,这个命令的构成中包含了从请求参数中获取的 poller_id 值。关键问题在于,此处的 poller_id 参数在拼接进命令行之前, 没有经过任何有效的过滤或转义 。
攻击者可以构造一个特殊的 poller_id 值,例如 ; id 。当这个值被拼接到系统命令中时,就变成了类似 /usr/bin/php -q /path/to/poller.php --poller-id=; id 这样的形式。在Linux的Shell中,分号 ; 是命令分隔符,这意味着 poller.php 命令执行后,紧接着会执行
265



被折叠的 条评论
为什么被折叠?



