1. 源码分析
$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){
//检查MIME
$allow_type = array('image/jpeg','image/png','image/gif');
if(!in_array($_FILES['upload_file']['type'],$allow_type)){
$msg = "禁止上传该类型文件!";
}else{
//检查文件名
$file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
if (!is_array($file)) {
$file = explode('.', strtolower($file));
}
$ext = end($file);
$allow_suffix = array('jpg','png','gif');
if (!in_array($ext, $allow_suffix)) {
$msg = "禁止上传该后缀文件!";
}else{
$file_name = reset($file) . '.' . $file[count($file) - 1];
$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 = "请选择要上传的文件!";
}
这道题是将上传的文件名和后缀存储在数组中,然后进行判断。如果逻辑写的有问题会造成安全隐患,导致不可预期的上传。这种上传攻击,它是属于攻击者白盒审计后发现
的漏洞居多。
上面的代码先检查上传的文件的类型,如果不是白名单里面的类型就禁止上传,文件类型校验通过之后会检查save_name
参数是否为空,如果为空就用实际的文件名,如果不空就用save_name
参数的值赋值给$file
。然后判断$file
是否为数组,如果不是数组就以点为分隔符建立数组。如果是数组就用数组的第一个值拼接$file[count($file) - 1]
的值,所以绕过思路就是上传多个save_name
的值组成数组,数组第二个值下标必须大于 1 即可,数组第二个的值就获取不了,字符串拼接起来就变成了数组的第一个值。
2.上传
可以看到将第二个值的下标设置大于1,经过$file_name = reset($file) . '.' . $file[count($file) - 1];
字符串连接后变成xxx.php.
,实测我的可以上传并访问,如果报错可以上传xxx.php/
,加过连接以后变成xxx.php/.
,利用move_uploaded_file()
函数中 /.
会自动忽略
的特性,移动到指定目录。