目录
📔环境
phpStudy搭建的测试网站
📔绕过任意文件上传漏洞(压缩包文件无递归删除)复现
📓原理
$temp_dir = $dir . 'member/1/'; //传入文件解压后放在member/1/的路径下
if (!is_dir($temp_dir)) { //判断文件是否原本存在不存在就mkdir一个member/1的文件
mkdir($temp_dir);
}
$file = $_FILES['file'];
if (!$file) {
exit("请勿上传空文件");
}
$name = $file['name'];
$dir = 'upload/'; //存放路径
$ext = strtolower(substr(strrchr($name, '.'), 1));
//删除zip解压后的路径1下的web.php
function check_dir($dir) //查看路径
{
//打开路径文件
$handle = opendir($dir);
//开始循环判断
while (($f = readdir($handle)) !== false) {
if (!in_array($f, array('.', '..'))) {
$ext = strtolower(substr(strrchr($f, '.'), 1));
if (!in_array($ext, array('jpg', 'gif', 'png'))) {
unlink($dir . $f);
}
}
}
}
mkdir($dir);
if (!is_dir($dir)) {
mkdir($dir);
}
这里的效果是解压压缩文件并查验是否符合'jpg', 'gif', 'png'文件类型,如果不符合就直接unlink删除
📓方法
由于上面的只是删除了上传文件中的木马而并没有递归删除上传文件中文件夹下的木马所以我们可以在压缩文件夹中再放入一个文件夹(内含图片+一句话文件)
📓步骤
📔绕过任意文件上传漏洞(压缩包文件递归删除)复现
📓原理
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);
}
}
}
}
}
这次与之前不同的是增加了一条判断语句,判断了解压的文件下是否还存在文件夹,如果存在就检查发现可以木马直接删除达到了递归删除的效果
📓方法
由于它的删除是按照先解压后删除所以我们可以利用时间竞争来绕过,首先需要在web.php中写入如下方法:
<?php fputs(fopen('../../../../payload.php','w'),'<?php phpinfo();?>'); ?>
📓步骤
总结:时间竞争漏洞利用原理其实就是在解压文件后与删除限制的文件之间的时间空隙来利用提前在限制的文件中写好的利用代码在非解压目录下生成新的不会被删除的新文件(木马),通过这个木马来拿下网站
📔绕过任意文件上传漏洞(文件名随机数.未递归删除)复现
📓原理
$temp_dir = $dir.md5(time(). rand(1000,9999)).'/'; //随机数生成文件,无法确定文件路径及文件名
if (in_array($ext, array('zip', 'jpg', 'gif', 'png'))) {
if ($ext == 'zip') { // 解压zip文件
$zip = new ZipArchive; //新建一个ZipArchive的对象
if(!$zip->open($file['tmp_name'])) { //打开zip文件
echo "fail"; //打开失败
return false; //返回false
}
if(!$zip->extractTo($temp_dir)) { //解压到临时目录
check_dir($temp_dir); //递归删除临时目录
exit("fail to extract"); //解压失败
}
#这里如果解压出错
if ($archive->extract(PCLZIP_OPT_PATH, $temp_dir, PCLZIP_OPT_REPLACE_NEWER) == 0) {
exit("解压失败");
}
#下面的递归删除就不会执行
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);
}
}
}
}
}
原理:这里我们通过利用解压文件在解压过程出错会导致后面的递归删除操作不会执行的特点
if (in_array($ext, array('zip', 'jpg', 'gif', 'png'))) { if ($ext == 'zip') { // 解压zip文件 $zip = new ZipArchive; //新建一个ZipArchive的对象 if(!$zip->open($file['tmp_name'])) { //打开zip文件 echo "fail"; //打开失败 return false; //返回false } if(!$zip->extractTo($temp_dir)) { //解压到临时目录 exit("fail to extract"); //解压失败 }
📓方法
如果我们让上传的压缩包在解压过程出现错误那么就不会删除掉我们的php文件,前提是这个解压软件容忍程度要低,能够在出现错误后解压失败,终止解压,而容忍程度高会导致一些小错误忽略,成功解压文件,这样就达不到我们的需求,所以在Windows系统下7zip解压软件的容忍度相对其他软件较低,而这里是php中解压我们的文件,所以就依赖于PHP自带的ZipArchive库了,由于该库容忍程度较高,所以我们接着就考虑软件部分,这里我们需要使用010editor工具来构造一个校验码错误的压缩文件,致使该文件在php的ZipArchive库在解压时出现错误,由于Windows下不允许文件名中包含冒号(:),所以我们考虑修改在工具中将a.txt的deFileName属性的值改成"a.tx+冒号"的方法使其php解压时出现错误
📓步骤
1.生成
2.修改
3.脚本测试
3.验证前我们需要写一个php软件目录下的解压脚本,作用是验证解压失败的过程
<?php function unzip($zipname,$path) { //解压缩函数 $zip = new ZipArchive; //新建一个ZipArchive的对象 if(!$zip->open($zipname)) { //打开压缩包 echo "fail"; //如果打开失败,则终止函数 return false; //返回false,表示解压缩失败 } if(!$zip->extractTo($path)) { //解压缩到指定的文件夹 echo "fail to extract"; //解压失败 return false; //返回false } $zip->close(); //关闭处理的zip文件 return true; //解压缩成功 } if(unzip('./test.zip','./')) { //解压缩到当前文件夹 echo "success zip"; //解压成功 }else { echo "failt to unzip"; //解压失败 }
按照正常的逻辑这里解压失败后文件夹中还是会将php文件解压出来,但是却没有
4.注意
如果你也出现上面的情况请试试下面说的方法:这里有一个小坑注意,你在压缩前面的文件时要注意他们在压缩文件中的顺序,意思就是你创建的一个php文件在创建的txt文件的上面就可以成功,只有这样在解压失败后它还是能够保留并将php文件成功解压出来
只有先创建txt文件后创建php文件才会有如下图的位置
5.上传验证
上传我们处理过的压缩包验证木马是否上传成功
📔绕过任意文件上传漏洞(文件名随机数.递归删除)复现
📓原理
$temp_dir = $dir.md5(time(). rand(1000,9999)).'/';
// $temp_dir = $dir . 'member/1/';
if (!is_dir($temp_dir)) {
mkdir($temp_dir);
}
if (in_array($ext, array('zip', 'jpg', 'gif', 'png'))) {
if ($ext == 'zip') { // 解压zip文件
$zip = new ZipArchive; //新建一个ZipArchive的对象
if(!$zip->open($file['tmp_name'])) { //打开zip文件
echo "fail"; //打开失败
return false; //返回false
}
if(!$zip->extractTo($temp_dir)) { //解压到临时目录
check_dir($temp_dir); //递归删除临时目录
exit("fail to extract"); //解压失败
}
在之前的漏洞基础上它补充了一个递归删除的方法,这样做会将解压后的文件夹中的文件再进行递归删除
$archive = new PclZip($file['tmp_name']); //新建一个PclZip的对象 // foreach($archive->listContent() as $value){ //获取解压后的文件列表 // $filename = $value["filename"]; //获取文件名 // if(preg_match('/\.php$/', $filename)){ //如果是php文件 // exit("压缩包内不允许含有php文件!"); //退出 // } // } if ($archive->extract(PCLZIP_OPT_PATH, $temp_dir, PCLZIP_OPT_REPLACE_NEWER) == 0) { check_dir($dir); exit("解压失败"); }
📓方法
虽然它对解压后的文件又进行了递归删除那么我们还可以考虑在压缩包解压的那一刻就让我们的php文件直接上传到非解压路径就可以避免被删除了,这里还是需要使用010editor工具来进行修改
../../php文件
📓步骤
1.生成
2.修改
这里需要修改掉php文件解压后的目标路径 ,还要同时修改掉txt文件的后缀让其解压失败然后保留php文件
3.上传验证
上传修改后端压缩包并在修改后的路径下查看是否有php文件生成
查看解压后文件路径查看修改后的路径下是否有php文件生成
📔防御方式
📓建立三道防御
1.使用imagecreatejpeg()函数,处理上传的图片通过打乱图片结构使恶意图片马无法生效
2.不要给文件执行权限,让上传的马所在文件无执行的权限
3.将上传文件放入临时文件夹中,这样即便木马上传成功但是它在临时文件夹中不会对我们网站造成危险