extract(PCLZIP_OPT_PATH, $temp_dir, PCLZIP_OPT_REPLACE_NEWER) == 0) { //解压压缩包
check_dir($dir);
exit("解压失败");
}
check_dir($temp_dir);
exit('上传成功!');
} else {
move_uploaded_file($file['tmp_name'], $temp_dir . '/' . $file['name']);
check_dir($temp_dir);
exit('上传成功!');
}
} else {
exit('仅允许上传zip、jpg、gif、png文件!');
}
源码分析判断:压缩包解压后仅删除文件,没有删除文件夹的操作,且没有进行递归删除,所以只需要将.php文件放入文件夹中压缩后再上传,就不会被删除。
我们创建一个文件,将图片和.php文件包含进去,然后再放入一个文件夹后再压缩
显示上传成功,
我们打开upload文件查看是否将.php文件上传上去
由于第一次没有递归删除,导致漏洞的出现,第二次过滤函数加上了递归删除步骤
function check_dir($dir){
$handle = opendir($dir);
while(($f = readdir($handle)) !== false){
if(!in_array($f, array('.', '..'))){
if(is_dir($dir.$f)){ //判断该文件中是否有文件夹
check_dir($dir.$f.'/'); //再次调用该函数进入文件夹中再次删除
}else{
$ext = strtolower(substr(strrchr($f, '.'), 1));
if(!in_array($ext, array('jpg', 'gif', 'png'))){
unlink($dir.$f);
}
}
}
}
}
此时我们就可以使用时间竞争,在还没有删除文件之前访问到.php文件,使其生成一个新的文件
'); ?>
在php文件中写入该代码,在访问到此文件后,../../../payload.php
表示在上三层目录中生成名为payload.php
的文件,内容为。
现在先使用burpsuite抓包,然后将抓到的包放入爆破模块里面,随便找一个数字,设置其运行2000次
我们在浏览器中访问该.php文件,虽然理论上可以成功,但是这个一般实际上成不成功看运气,这次实验中文件夹中有图片了,但是.php文件没有生成。
第二次可以使用时间竞争就是因为可以猜到文件名,但是第三次修改时将文件名进行了一个随机数的设置,此时我们就无法猜到文件名,时间竞争的方法就不能使用了
$temp_dir = $dir.md5(time(). rand(1000,9999)).'/';
但是在代码中还是有问题,就是在解压文件时,解压失败后就直接退出了,没有删除等其他操作,我们只需要构造一个解压到一半就出错的压缩包,然后这个压缩包中要保证自己写的.php文件是可以完整解压出来的。
手动上传结果:
构造解压到一半出错的数据包:
1.用010 editor 修改deCrc的值保存(PHP自带的ZipArchive库容忍度比较高,不适用)
2.在010editor中将2.txt的deFileName属性的值改成“2.tx:”(本次采用这种)
3.在Linux下也有类似的方法,我们可以将文件名改成5个斜杠(/)
上传文件报错:
压缩包中php文件必须排在其他文件前面。
解压出错后再次递归删除文件
if (in_array($ext, array('zip', 'jpg', 'gif', 'png'))) {
if ($ext == 'zip') {
$zip = new ZipArchive;
if(!$zip->open($file['tmp_name'])) {
echo "fail";
return false;
}
if(!$zip->extractTo($temp_dir)) {
check_dir($temp_dir);
exit("fail to extract");
}
$archive = new PclZip($file['tmp_name']);
foreach($archive->listContent() as $value){
$filename = $value["filename"];
if(preg_match('/\.php$/', $filename)){
exit("压缩包内不允许含有php文件!");
}
}
绕过方法:
将一句话木马的文件解压后将文件名设置为…/…/…/文件.php(文件名长一点),这样文件就会一解压就放入了上级目录,就无法递归删除,两个.php文件都要修改名字