代码审计---文件上传
字数 1661 2025-08-09 22:00:46
代码审计之文件上传漏洞详解
文件上传漏洞概述
文件上传漏洞是指Web应用程序在处理用户上传文件时,未对上传文件的类型、内容、扩展名等进行严格验证,导致攻击者可以上传恶意文件(如Webshell、病毒、木马等)到服务器上,从而获取系统权限或进行其他恶意操作。
常见文件上传漏洞类型
1. 前端验证绕过
漏洞原理:仅依赖JavaScript进行文件类型验证,攻击者可以禁用JS或修改前端代码绕过验证。
审计要点:
- 检查是否仅在前端使用
accept属性或JS验证文件类型 - 查看是否有服务端验证逻辑
2. MIME类型验证绕过
漏洞原理:仅检查HTTP头中的Content-Type,攻击者可伪造MIME类型。
审计要点:
- 检查代码中是否仅验证
$_FILES['file']['type'] - 是否使用
mime_content_type()或文件头验证
3. 文件扩展名验证不严
漏洞原理:
- 黑名单机制不完整(遗漏可执行扩展名)
- 大小写绕过(如.PHp)
- 特殊后缀(如.php5, .phtml)
- 双扩展名绕过(如.php.jpg)
审计要点:
- 检查扩展名验证是黑名单还是白名单
- 是否处理了大小写、点号、空格等特殊情况
- 是否使用
pathinfo()或explode()分割文件名
4. 文件内容验证缺失
漏洞原理:不检查文件实际内容,仅凭扩展名判断文件类型。
审计要点:
- 是否检查文件头标识(如
FFD8FF为JPEG) - 是否使用
getimagesize()验证图片文件 - 是否对文件内容进行二次渲染
5. 目录路径可控
漏洞原理:上传路径或文件名用户可控,可能导致目录穿越。
审计要点:
- 检查上传路径是否拼接用户输入
- 是否过滤
../等路径穿越字符 - 是否使用
basename()处理文件名
6. 条件竞争漏洞
漏洞原理:文件上传后未立即重命名或检查,攻击者可利用时间差执行恶意文件。
审计要点:
- 检查上传后处理流程是否存在时间窗口
- 是否先保存后验证
代码审计实战要点
1. 定位文件上传功能
查找以下关键字:
$_FILES
move_uploaded_file()
<input type="file">
enctype="multipart/form-data"
2. 验证逻辑分析
检查是否存在以下安全措施:
// 白名单验证
$allowedExts = array("gif", "jpeg", "jpg", "png");
$extension = end(explode(".", $_FILES["file"]["name"]));
// 文件类型验证
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES['file']['tmp_name']);
// 文件内容验证
if (!getimagesize($_FILES["file"]["tmp_name"])) {
die("不是有效的图片文件");
}
// 重命名处理
$new_name = md5(uniqid()).'.'.$extension;
3. 常见危险函数
move_uploaded_file()- 未经验证直接保存文件copy()- 可能用于复制上传文件file_put_contents()- 可能直接写入用户可控内容
防御措施
1. 严格的验证策略
// 白名单验证扩展名
$allowed = ['jpg', 'png', 'gif'];
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if (!in_array($ext, $allowed)) {
die('不允许的文件类型');
}
// 验证MIME类型
$allowedMime = ['image/jpeg', 'image/png', 'image/gif'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES['file']['tmp_name']);
if (!in_array($mime, $allowedMime)) {
die('非法的文件类型');
}
// 验证文件内容
if (!getimagesize($_FILES['file']['tmp_name'])) {
die('不是有效的图片文件');
}
2. 安全处理措施
- 上传目录设置为不可执行
- 重命名上传文件(如使用MD5随机名称)
- 去除文件元数据(对图片进行二次渲染)
- 设置正确的文件权限
- 使用独立域名存放上传文件
3. 其他安全建议
- 限制上传文件大小
- 记录上传日志
- 对压缩包文件进行病毒扫描
- 定期审计服务器上的可疑文件
实战案例
案例1:简单文件上传漏洞
<?php
if (isset($_POST['submit'])) {
$file = $_FILES['file'];
move_uploaded_file($file['tmp_name'], 'uploads/'.$file['name']);
echo "文件上传成功!";
}
?>
漏洞分析:
- 无任何验证措施
- 文件名和内容完全可控
- 可直接上传PHP等脚本文件
案例2:不完整的黑名单验证
<?php
$blacklist = array('.php', '.asp', '.jsp');
$file_name = $_FILES['file']['name'];
foreach ($blacklist as $item) {
if (preg_match('/'.$item.'$/i', $file_name)) {
die('不允许的文件类型');
}
}
move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/'.$file_name);
?>
绕过方法:
- 使用
.php5,.phtml等扩展名 - 使用大小写如
.PhP - 使用双扩展名如
shell.php.jpg
案例3:安全的文件上传实现
<?php
$allowed_ext = ['jpg', 'png', 'gif'];
$allowed_mime = ['image/jpeg', 'image/png', 'image/gif'];
$max_size = 1024 * 1024; // 1MB
if (isset($_POST['submit'])) {
$file = $_FILES['file'];
// 验证错误代码
if ($file['error'] !== UPLOAD_ERR_OK) {
die('上传错误: '.$file['error']);
}
// 验证文件大小
if ($file['size'] > $max_size) {
die('文件过大');
}
// 验证扩展名
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($ext, $allowed_ext)) {
die('不允许的文件类型');
}
// 验证MIME类型
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file['tmp_name']);
if (!in_array($mime, $allowed_mime)) {
die('非法的文件类型');
}
// 验证图片内容
if (!getimagesize($file['tmp_name'])) {
die('不是有效的图片文件');
}
// 安全重命名
$new_name = md5(uniqid()).'.'.$ext;
$upload_path = 'uploads/'.$new_name;
if (move_uploaded_file($file['tmp_name'], $upload_path)) {
echo '文件上传成功!';
} else {
echo '文件保存失败';
}
}
?>
高级绕过技巧
1. 图片马制作
将Webshell代码插入图片的注释或EXIF数据中:
exiftool -Comment='<?php system($_GET["cmd"]); ?>' image.jpg -o webshell.php
2. 文件头伪造
在PHP文件开头添加图片文件头:
GIF89a
<?php phpinfo(); ?>
3. 条件竞争利用
当服务器先保存后验证时,快速访问上传的临时文件:
import requests
while True:
r = requests.get('http://target/uploads/temp.php')
if 'success' in r.text:
break
自动化审计工具
- RIPS - PHP代码静态分析工具
- Fortify - 商业代码审计工具
- Checkmarx - 商业SAST解决方案
- SonarQube - 开源代码质量检测平台
总结
文件上传漏洞是Web安全中最常见也最危险的漏洞之一。在代码审计过程中,需要重点关注:
- 验证逻辑是否全面(扩展名、MIME、内容)
- 是否使用白名单而非黑名单
- 文件保存处理是否安全
- 是否存在条件竞争问题
- 上传目录权限设置是否合理
通过全面的验证和严格的安全措施,可以有效防范文件上传漏洞带来的安全风险。