经典版
漏洞原理:我们上传一个zip的压缩包,它会解压然后删除其中不是.jpg .gig .png的文件
-
function check_dir($dir)
:这是一个PHP函数的定义,它接受一个参数$dir
,代表要检查的目录路径。 -
$handle = opendir($dir);
:使用opendir
函数打开指定目录,并将返回的目录句柄赋值给变量$handle
。 -
while (($f = readdir($handle)) !== false)
:使用readdir
函数循环读取目录中的文件,每次循环将文件名赋给变量$f
。 -
if (!in_array($f, array('.', '..'))) { ... }
:在每次循环中,检查当前文件名是否为当前目录(.
)或父目录(..
),如果不是,则执行下面的操作。 -
$ext = strtolower(substr(strrchr($f, '.'), 1));
:使用strrchr
函数找到文件名中的最后一个.
,然后使用substr
截取文件扩展名,并用strtolower
将其转换为小写。 -
if (!in_array($ext, array('jpg', 'gif', 'png'))) { unlink($dir . $f); }
:如果文件的扩展名不是jpg、gif或png,则使用unlink
函数删除该文件。
<?php
header("Content-Type:text/html; charset=utf-8");
require_once('pclzip.lib.php');
$file = $_FILES['file'];
if ($file['size'] == 0) {
exit("请勿上传空文件");
}
$name = $file['name'];
$dir = 'uploads/';
$ext = strtolower(substr(strrchr($name, '.'), 1));
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);
}
}
}
}
if (!is_dir($dir)) {
mkdir($dir);
}
$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') {
$archive = new PclZip($file['tmp_name']);
if ($archive->extract(PCLZIP_OPT_PATH, $temp_dir, PCLZIP_OPT_REPLACE_NEWER) == 0) {
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被删除了。
绕过方法:我们把php文件单独放在一个文件夹中,然后将这个文件夹和图片一起压缩成zip,然后上传
这个bbb文件夹里面的111.php就没有被删除了,然后就可以连接蚁剑了
升级版
上面主要是没有进行递归删除导致的绕过,后面进行了递归删除
<?php
header("Content-Type:text/html; charset=utf-8");
require_once('pclzip.lib.php');
$file = $_FILES['file'];
if ($file['size'] == 0) {
exit("请勿上传空文件");
}
$name = $file['name'];
$dir = 'uploads/';
$ext = strtolower(substr(strrchr($name, '.'), 1));
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 (!is_dir($dir)) {
mkdir($dir);
}
$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 = new ZipArchive;
// if(!$zip->open($file['tmp_name'])) {
// echo "fail";
// return false;
// }
// if(!$zip->extractTo($temp_dir)) {
// // check_dir($temp_dir);
// exit('fail to zip');
// }
$archive = new PclZip($file['tmp_name']);
if ($archive->extract(PCLZIP_OPT_PATH, $temp_dir, PCLZIP_OPT_REPLACE_NEWER) == 0) {
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文件!');
}
我们发现,bbb中的111.php就被删除了
但是代码逻辑是先解压,后删除,我们就用条件竞争来绕过
因为我发现,同时使用burp上传和访问,经过多次尝试没有成功,我换了个操作,使用手动上传zip,burp访问php,多次手动上传之后,成功了
在我们的uploads下面生成了一句话木马文件,直接连蚁剑
至此,phpcms告一段落