最近在iwebsec靶场通关文件上传漏洞模块时,发现这个看似简单的漏洞类型竟藏着不少门道。作为Web安全中最常见的高危漏洞之一,文件上传功能如果防护不当,轻则导致网站被挂马,重则可能引发服务器沦陷。今天我就结合实战经验,详细拆解文件上传漏洞的攻防要点。
文件上传漏洞本质上源于服务端对用户提交的文件内容、类型、扩展名等验证不严。攻击者通过构造恶意文件(如webshell)绕过前端验证,将可执行脚本上传至服务器,从而获取系统控制权。iwebsec靶场精心设计了12种不同防护级别的文件上传场景,正好可以用来系统性地掌握各种绕过手法。
最简单的漏洞类型往往只依赖前端JavaScript验证文件扩展名。在iwebsec的第一关中,页面通过以下代码检查上传文件:
javascript复制function checkFile() {
var file = document.getElementById("upload").value;
if (!/\.(jpg|png|gif)$/.test(file)) {
alert("仅允许上传jpg/png/gif文件");
return false;
}
}
绕过方法极其简单:
shell.php修改为shell.jpg通过前端验证shell.php提交关键点:前端验证永远不可信,服务端必须做二次校验。实际开发中建议使用
FileReader读取文件头进行基础验证。
第二关增加了服务端MIME类型检查,常见防御代码如下:
php复制if($_FILES['file']['type'] != 'image/jpeg'){
die("文件类型不正确");
}
绕过方案:
image/jpeg实测发现服务端对image/jpeg、image/png等类型检查存在差异。更安全的做法应该是结合文件头魔数校验,例如:
php复制$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES['file']['tmp_name']);
finfo_close($finfo);
当服务端采用黑名单机制时,这些手法往往有效:
.php5、.phtml、.phps.PhP、.pHpshell.jpg.phpshell.php%00.jpg(PHP<5.3.4)shell.php.iwebsec第五关演示了Apache解析特性:如果遇到不认识的后缀,会向前寻找可解析的扩展名。因此shell.php.xxx可能被当作PHP执行。
更安全的系统会采用白名单机制,此时需要组合利用其他漏洞:
%00截断(需特定PHP版本)
code复制POST /upload.php HTTP/1.1
Content-Disposition: form-data; name="file"; filename="shell.jpg%00.php"
.htaccess覆盖(需上传权限)
htaccess复制AddType application/x-httpd-php .jpg
文件包含组合拳
shell.jpg?file=uploads/shell.jpg当服务端检测文件内容时,这些方法值得尝试:
bash复制copy /b normal.jpg + shell.php webshell.jpg
php复制exif_read_data('uploaded.jpg'); // 读取注释执行代码
xml复制<svg xmlns="http://www.w3.org/2000/svg" onload="alert(1)"/>
企业级防护应实施分层验证:
pathinfo()而非explode())php复制$signatures = [
'FFD8FF' => 'image/jpeg',
'89504E' => 'image/png'
];
Nginx安全配置示例:
nginx复制location ^~ /uploads/ {
deny all;
location ~* \.(jpg|png|gif)$ {
allow all;
add_header Content-Type "image/jpeg";
}
}
PHP.ini关键设置:
ini复制file_uploads = On
upload_max_filesize = 2M
upload_tmp_dir = /tmp
cgi.fix_pathinfo=0
某些系统先保存文件再校验,可利用时间差攻击:
/uploads/tmp_[随机].php解决方案:
inotify监控上传目录当使用OSS/S3存储时需注意:
AWS S3策略示例:
json复制{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::mybucket/uploads/*",
"Condition": {
"StringLike": {
"s3:ObjectTag/content-type": [
"text/x-php*",
"application/x-php*"
]
}
}
}
]
}
对于渗透测试人员,推荐这些检测工具:
Burp插件:
自定义脚本:
python复制def generate_payloads():
extensions = ['php', 'php5', 'phtml']
transforms = ['', '.jpg', '%00.jpg']
return [f"shell.{ext}{tr}" for ext in extensions for tr in transforms]
YARA规则检测webshell:
yara复制rule webshell {
strings:
$eval = "eval(" nocase
$system = "system(" nocase
condition:
any of them
}
在iwebsec通关过程中,我发现最有效的学习方式是先尝试手动绕过,再分析服务端源码,最后编写自动化检测脚本。比如第9关需要修改Content-Disposition中的filename字段,而第11关则需要利用Windows特性绕过路径检测。