逐梦论坛's Archiver

shillan 发表于 2014-12-17 03:45

Discuz 5.x/6.x/7.x投票SQL注入分析+修复方法

感觉应该是editpost.inc.php里投票的漏洞。因为dz已经确定不会再修补7.x以前的漏洞了,所以直接贴细节吧 。
  问题出在 editpost.inc.php的281行,对用户提交的polloption数组直接解析出来带入SQL语句,因为默认只对数组值过滤,而不过滤键,所以会导致一个DELETE注入。[code]$pollarray['options'] = $polloption;
if($pollarray['options']) {
if(count($pollarray['options']) > $maxpolloptions) {
showmessage('post_poll_option_toomany');
}
foreach($pollarray['options'] as $key => $value) { //这里直接解析出来没处理$key
if(!trim($value)) {
$db->query("DELETE FROM {$tablepre}polloptions WHERE polloptionid='$key' AND tid='$tid'");
unset($pollarray['options'][$key]);
}
}[/code]利用方法:
用注册账户发布一个投票帖子,然后点击“编辑”,如下图
[attach]5112[/attach]

[attach]5111[/attach]
因为代码判断trim($value)为空才执行下面的语句,所以一定要把范冰冰删掉。
返回结果已经成功注入了:
[attach]5110[/attach]
修补方法:
如果不方便升级到Discuz X的话,可以修改editpost.inc.php文件,增加一行:[code]$key=addslashes($key);[/code]

shillan 发表于 2014-12-17 03:46

[p=25, 2, left]首先说一下 这洞需要有权限发布投票才行 刚注册的会员是不能发布投票的
我看了下默认发布投票需要的权限 需要从注册会员开始才有发布投票的权限
[/p][p=25, 2, left][url=http://www.wooyun.org/upload/201408/08011459cbc4c347ec713c3f956c2835197c1f92.jpg][img=600,0]http://www.wooyun.org/upload/201408/08011459cbc4c347ec713c3f956c2835197c1f92.jpg[/img][/url][/p]
[p=25, 2, left][url=http://www.wooyun.org/upload/201408/08013442c4c5ed144ad678df4dde4507853ca293.jpg][img=600,0]http://www.wooyun.org/upload/201408/08013442c4c5ed144ad678df4dde4507853ca293.jpg[/img][/url][/p][p=25, 2, left]
看了一下注册会员所需要的积分是50分
50分 上传个头像 做个任务就差不多了(所以狗哥 这不算限制条件把?)
_________________________________________________________________________
在post.php中
从263行开始 也就是最后的那几行
[/p][code]if($action == 'newthread') {
        ($forum['allowpost'] == -1) && showmessage('forum_access_disallow');
        require_once DISCUZ_ROOT.'./include/newthread.inc.php';
} elseif($action == 'reply') {
        ($forum['allowreply'] == -1) && showmessage('forum_access_disallow');
        require_once DISCUZ_ROOT.'./include/newreply.inc.php';
} elseif($action == 'edit') {
        ($forum['allowpost'] == -1) && showmessage('forum_access_disallow');
        require_once DISCUZ_ROOT.'./include/editpost.inc.php';
} elseif($action == 'newtrade') {
        ($forum['allowpost'] == -1) && showmessage('forum_access_disallow');
        require_once DISCUZ_ROOT.'./include/newtrade.inc.php';
}[/code][p=25, 2, left]

包含了这么多文件进来 我找了这个文件看了起来include/editpost.inc.php
然后在include/editpost.inc.php 第272行左右

[/p][code]if($thread['special'] == 1 && ($alloweditpoll || $isorigauthor) && !empty($polls)) {
                                $pollarray = '';
                                $pollarray['options'] = $polloption;
                                if($pollarray['options']) {
                                        if(count($pollarray['options']) > $maxpolloptions) {
                                                showmessage('post_poll_option_toomany');
                                        }
                                        foreach($pollarray['options'] as $key => $value) {
                                                if(!trim($value)) {
                                                        $db->query("DELETE FROM {$tablepre}polloptions WHERE polloptionid='$key' AND tid='$tid'");
                                                        unset($pollarray['options'][$key]);
                                                }
                                        }
                                        $polladd = ', special=\'1\'';[/code][p=25, 2, left]

foreach($pollarray['options'] as $key => $value) {

这里直接把数组中的key带入到了delete查询当中。

再来看一下dz的全局文件

[/p][code]foreach(array('_COOKIE', '_POST', '_GET') as $_request) {
        foreach($_request as $_key => $_value) {
                $_key{0} != '_' && $_key = daddslashes($_value);
        }
}
code 区域function daddslashes($string, $force = 0) {
        !defined('MAGIC_QUOTES_GPC') && define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
        if(!MAGIC_QUOTES_GPC || $force) {
                if(is_array($string)) {
                        foreach($string as $key => $val) {
                                $string[$key] = daddslashes($val, $force);
                        }
                } else {
                        $string = addslashes($string);
                }
        }
        return $string;
}[/code][p=25, 2, left]

这里先判断了gpc是否开启 如果没有开启 就用addslashes再来转义

这里对数组中的value进行转义 key无过滤。

[/p][code]$db->query("DELETE FROM {$tablepre}polloptions WHERE polloptionid='$key' AND tid='$tid'[/code][p=25, 2, left]

所以再进行这个查询的时候 我们就可以引入单引号了。
_______________________________________________________________
在执行循环之前有一个条件

if($thread['special'] == 1 && ($alloweditpoll || $isorigauthor) && !empty($polls))

这里($alloweditpoll || $isorigauthor) $isorigauthor判断是不是你是作者 如果你编辑的是你的文章的话 肯定是true。 $polls 这个直接就可以控制。

$thread['special'] == 1 之前我一直在纠结这个是啥东西。。

后面看了看发文章的时候的代码 这个$thread['special'] == 1代表的就是发布的是投票。

那如果我们自己发布一个投票 然后再编辑 就可以进入这里了。

[/p][p=25, 2, left][url=http://www.wooyun.org/upload/201408/0801521942529ff6611176d8e095a6a8185815e7.jpg][img=600,0]http://www.wooyun.org/upload/201408/0801521942529ff6611176d8e095a6a8185815e7.jpg[/img][/url][/p][p=25, 2, left]

首先发布一个投票。 发布完后 再点击编辑。
然后再抓一下包。
这里我输出了一下

[/p][code]$polladd = '';
                        if($thread['special'] == 1 && ($alloweditpoll || $isorigauthor) && !empty($polls)) {
                                $pollarray = '';
                               
                                $pollarray['options'] = $polloption;
                        var_dump ($polloption);exit;//输出[/code][p=25, 2, left][url=http://www.wooyun.org/upload/201408/08015529f9aba8a3a679fbb4475045dad39e3277.jpg][img=600,0]http://www.wooyun.org/upload/201408/08015529f9aba8a3a679fbb4475045dad39e3277.jpg[/img][/url][/p][p=25, 2, left]

我擦 一看竟然已经有值了?

在这里我本来已经准备放弃了, 但是还是抱着试一试的态度 在url写了这个

[/p][p=25, 2, left][url=http://www.wooyun.org/upload/201408/08020717a79215e4b613759e293ec970f0214934.jpg][img=600,0]http://www.wooyun.org/upload/201408/08020717a79215e4b613759e293ec970f0214934.jpg[/img][/url][/p][p=25, 2, left]

发现还是可以控制 而且单引号 理所应当的没有被转义。

那不是就可以注入了吗? 构造一下语句。

[/p][code]if(!trim($value)) {
                                                        $db->query("DELETE FROM {$tablepre}polloptions WHERE polloptionid='$key' AND tid='$tid'");[/code][p=25, 2, left]

因为这里 数组中的value为false的时候才会进去
所以这里数组的value我们就不写

[/p][p=25, 2, left][url=http://www.wooyun.org/upload/201408/08020913559a3912f35b9f727b56209b31af4c95.jpg][img=600,0]http://www.wooyun.org/upload/201408/08020913559a3912f35b9f727b56209b31af4c95.jpg[/img][/url][/p][p=25, 2, left]

成功出数据。[/p]漏洞证明:
[p=25, 2, left][url=http://www.wooyun.org/upload/201408/08020913559a3912f35b9f727b56209b31af4c95.jpg][img=600,0]http://www.wooyun.org/upload/201408/08020913559a3912f35b9f727b56209b31af4c95.jpg[/img][/url][/p]

修复方案:[p=25, 2, left]foreach($pollarray['options'] as $key => $value) {

  [color=Red]$key=addslashes($key);[/color]

  if(!trim($value)) {

  $db->query("DELETE FROM {$tablepre}polloptions WHERE polloptionid='$key' AND tid='$tid'");

? 还是看你们把。[/p]

itqpCFu 发表于 2015-6-29 18:36

[img]http://gd2.alicdn.com/imgextra/i2/44650515/TB2NMSZcVXXXXcMXXXXXXXXXXXX_!!44650515.jpg[/img]

页: [1]

Powered by Discuz! Archiver 7.2  © 2001-2009 Comsenz Inc.