#1 前言
猛兽来了,我们应该将其绝杀在门外,但是有些人非得把它放进屋内,才杀之,你们难道不知道猛兽的嘴里可能叼了一个炸药包吗? 砰!!!结果全都完完了…
#2 叼着炸药包的猛兽来了
请先看下面这段代码
1 2 3 4 5 6 7 8 9 |
<?php if(isset($_GET['src'])){ copy($_GET['src'],$_GET['dst']); //... unlink($_GET['dst']); //... } ?> |
这段代码实际意义不大,不过,没关系我们重在研究嘛,一种典型的”将猛兽放进室内,才杀之”的案例,我们来看看
猛兽放进室内:
1 |
copy($_GET['src'],$_GET['dst']); |
这条猛兽不安全,杀之:
1 |
unlink($_GET['dst']); |
炸药包:
1 |
$_GET['dst']-->此炸药包非彼炸药包,此炸药包的作用是生成恶意文件 :-) |
上述代码即存在本文所讲的设计缺陷
1 |
copy($_GET['src'],$_GET['dst']); |
可将任意文件copy成恶意文件,如木马,后来发现这个文件不安全,后面的unlink($_GET[‘dst’]);将之删除…
但是,各位厂商们 你们可曾想到这个木马可能在你们删除之前,生成了新的木马文件,结果可想而知,SO… 还请在设计产品时多考虑考虑….
#3 PHPCMS案例
PHPCMS相应的设计缺陷在上传头像的功能处,我们来看看其代码
/phpsso_server/phpcms/modules/phpsso/index.php 第572行开始 uploadavatar()函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
public function uploadavatar() { //根据用户id创建文件夹 if(isset($this->data['uid']) && isset($this->data['avatardata'])) { $this->uid = $this->data['uid']; $this->avatardata = $this->data['avatardata']; } else { exit('0'); } $dir1 = ceil($this->uid / 10000); $dir2 = ceil($this->uid % 10000 / 1000); //创建图片存储文件夹 $avatarfile = pc_base::load_config('system', 'upload_path').'avatar/'; $dir = $avatarfile.$dir1.'/'.$dir2.'/'.$this->uid.'/'; if(!file_exists($dir)) { mkdir($dir, 0777, true); } //存储flashpost图片 $filename = $dir.$this->uid.'.zip'; file_put_contents($filename, $this->avatardata); pc_base::load_sys_func('dir'); //解压缩文件 pc_base::load_app_class('pclzip', 'phpsso', 0); $archive = new PclZip($filename); $archive->allow_ext = array('jpg'); $list = $archive->extract(PCLZIP_OPT_PATH, $dir,PCLZIP_OPT_REMOVE_ALL_PATH); //判断文件安全,删除压缩包和非jpg图片 $avatararr = array('180x180.jpg', '30x30.jpg', '45x45.jpg', '90x90.jpg'); $files = glob($dir."*"); foreach($files as $_files) { if(is_dir($_files)) dir_delete($_files); if(!in_array(basename($_files), $avatararr)) @unlink($_files); } if($handle = opendir($dir)) { while(false !== ($file = readdir($handle))) { if($file !== '.' && $file !== '..') { if(!in_array($file, $avatararr)) { @unlink($dir.$file); } else { $info = @getimagesize($dir.$file); if(!$info || $info[2] !=2) { @unlink($dir.$file); } } } } closedir($handle); } $this->db->update(array('avatar'=>1), array('uid'=>$this->uid)); exit('1'); } |
大概意思是解压ZIP文件,再删除非jpg文件,目录等(看见了吧,产生了#2所述的设计缺陷,典型的引狼入室,再杀之的设计理念),但由于在此处出现过上传漏洞,增加了这么一行代码:
1 |
$archive->allow_ext = array('jpg'); |
只允许jpg格式文件,不允许php后缀的文件,这为我们下面的漏洞利用带来了不少的麻烦,但别急,后面我会讲到突破的方法…
#4 突破限制产生php临时文件
虽然代码限制了只能是jpg格式的文件,但我们的文件名可以是1.php.php.jpg 对吧,
想到什么没有呢?对!采用文件名截断…行动吧
(为了方便调试,我们加入如下代码,即在解压zip文件后,删除非jpg文件前中断代码的执行)
1 2 3 4 5 6 7 |
$archive = new PclZip($filename); exit('zanting....');//我们添加的调试代码 $archive->allow_ext = array('jpg'); $list = $archive->extract(PCLZIP_OPT_PATH, $dir,PCLZIP_OPT_REMOVE_ALL_PATH); |
结果,成功在目录下生成了1.php文件
转载一些有意思的漏洞。
原文:http://www.wooyun.org/bugs/wooyun-2014-049794