【upload-labs】pass-19~pass20完结篇
【pass-19】00截断
1、源码分析
2、测试流程
先尝试上传一个一句话木马muma.php
用burp抓包:
在raw中将加号的2b替换为null的00
变换后结果:
如图所示,上传成功!
然后直接菜刀连接即可。
小结
00截断的原理前面提到过,不明白的小伙伴可以取看看传送门
我觉得是否可以利用00截断的本质,还是要看最后文件的保存路径用户是否可控。
【pass-20】特殊+windows特性绕过
1、源码分析
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){
//mime check
$allow_type = array('image/jpeg','image/png','image/gif'); //创建一个白名单校验MIME
if(!in_array($_FILES['upload_file']['type'],$allow_type)){
$msg = "禁止上传该类型文件!";
}else{
//check filename
$file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
if (!is_array($file)) { //判断save_name是否是一个数组 ???
$file = explode('.', strtolower($file)); //explode() 函数把字符串打散为数组,以点为分割
}
$ext = end($file); //end返回最后一个元素的值
$allow_suffix = array('jpg','png','gif'); //创建一个白名单用于过滤后缀
if (!in_array($ext, $allow_suffix)) {
$msg = "禁止上传该后缀文件!";
}else{
$file_name = reset($file) . '.' . $file[count($file) - 1]; //reset()返回第一个元素的值
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' .$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$msg = "文件上传成功!";
$is_upload = true;
} else {
$msg = "文件上传失败!";
}
}
}
}else{
$msg = "请选择要上传的文件!";
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
前面MIME的校验很好绕过,关键是这句$file_name = reset($file) . '.' . $file[count($file) - 1];
,文件名的组成是打散后的第一个元素+点+最后一个数组元素,我们可控的就是元素值,而且元素值是以点区分的。
就比如shell.php.jpg,那文件名的组合应该为shell.jpg,apache无法解析,在后缀名上做文章好像行不通,换成shell.php.xxx白名单过不了,咋办呢
再往前看,if (!is_array($file))
这句话有点奇怪,为什么要判断文件名是不是数组呢?如果上传的文件名本来就是数组,那这句话就能绕过,而且数组内容我们可以自己定制。
2、测试流程
上传一个muma.php,用burp抓包:
更改后:
这里直接将文件名改为数组,从而绕过了数组打散,而save_name[2]中的jpg也可以绕过后缀白名单的过滤,文件名形成的后缀是索引为数组长度减一的元素save_name[1],而save_name[1]我们没有设置,所以直接为空。
最后文件名拼接应该为shell.php.
,此时由因为windows的特性,会在保存文件时自动去除后缀末尾的点。
所以shell.php被成功保存。
我们来测试一下猜想:
放包:
如图所示,上传成功!
最后用菜刀连接即可。
小结
本关的突破点主要在if (!is_array($file))
和$file_name = reset($file) . '.' . $file[count($file) - 1];
这两句话,比较特殊的是构造一个数组文件名绕过,并且结合Windows的特性。