注意:有关 File Upload 漏洞的基础知识与原理已在上篇文章指出,此处不再解释。
可参考该文章https://www.cnblogs.com/lky-sec/articles/21412117
本文仅用于网络安全学习与防御研究。所有测试均在本人本地部署、合法授权的 DVWA 靶场中进行,禁止将相关方法用于任何未授权系统。
中等难度 File Upload
一 测试范围与环境
本次测试目标为本地 DVWA 靶场中的 File Upload 模块。
| 测试环境 | 本地 DVWA 靶场 |
| 安全等级 | Medium |
| 测试系统 | Kali Linux |
| 测试工具 | Firefox、Burp Suite |
| 测试方式 | 黑盒测试、请求分析、源码审计 |
| 授权情况 | 本人本地靶场,合法授权 |
二 页面与请求分析
1. 设置难度等级
进入 DVWA Security,将安全等级设置为 Medium,随后进入 File Upload 模块。

2. 观察模块正常功能
使用自己创建的文档test1.txt进行提交,发现页面返回结果提示,仅能提交JPEG/PNG。可知模块正常功能为提交JPEG/PNG格式文件。

3. 使用 Burp Suite 进行抓包分析
开启Burp Suite Proxy模块进行拦截,提交一次正常请求。

从当前 HTTP 请求可以确定,Medium File Upload 模块上传文件时会向服务器提交文件名、文件字段中的 Content-Type、文件内容以及 MAX_FILE_SIZE。且MAX_FILE_SIZE数值为100000(后续分析源码是文件大小需小于100000字节)
三 手工黑盒测试
1.修改文件类型
前面分析可知,模块只可提交JPEG/PNG类型,将请求发送至Repeater模块,尝试将test1.txt文件字段的Content-Type修改后发送。

由返回结果可知,文件上传成功,分析可知,该结果说明程序的文件类型判断依赖客户端提供的Content-Type,并且没有校验文件扩展名和真实图片内容。接下来进一步验证上传目录是否具有脚本解析能力。
2.构造脚本
构建php脚本文件,上传进行提交,修改文件字段的Content-Type后发送。

3.验证上传目录的脚本解析行为
将返回结果../../hackable/uploads/test2.php拼接到浏览器URL处,发现文件内容被执行,返回PHP版本等信息。说明当前服务器允许在该目录中解析PHP脚本。

四 代码审计
1.点击view source查看源码
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
// Is it an image?
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) ) {
// Can we move the file to the upload folder?
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>
2.源码分析
Medium 等级首先获取上传文件的文件名、MIME 类型和文件大小:
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
随后程序对上传文件进行限制,只允许:
image/jpeg
image/png
并要求文件大小小于100000字节:
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) )
相比 Low 等级,Medium 增加了文件类型和文件大小校验。
但这里的 $uploaded_type 来源于客户端上传请求中的 Content-Type,该值可以通过 Burp Suite 直接修改。因此攻击者可以将 PHP 文件的 Content-Type 修改为 image/jpeg 或 image/png,从而绕过 MIME 类型检查。
同时,程序仍然直接使用原始文件名:
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
并通过 move_uploaded_file() 将文件保存到 Web 可访问的上传目录中,没有进一步检查文件扩展名或文件真实内容。
因此,该漏洞的主要原因是:程序仅依赖客户端可控的 MIME 类型判断文件类型,缺少对文件扩展名和真实文件内容的服务端校验。
3.修复方案
1)对上传文件扩展名进行白名单校验,仅允许 JPEG、JPG、PNG 等合法图片格式。
2)使用服务端文件检测函数校验真实 MIME 类型,不信任客户端提交的 Content-Type。
3)对上传图片进行内容解析,确认文件能够被正常识别为图片。
4)对上传文件重新生成随机文件名,避免直接使用用户提交的原始文件名。
5)严格限制上传文件大小,并在服务端进行校验。
6)将上传目录设置为不可执行目录,禁止 PHP 等脚本文件被解析执行。
7)将上传文件存储在 Web 根目录之外,通过受控接口进行访问。
8)对上传失败、类型异常和高频上传行为进行日志记录与安全监控。
五 Low与Medium差异
| 上传目录 | hackable/uploads/ | hackable/uploads/ |
| 文件名处理 | 使用 basename() 获取原始文件名 | 使用 basename() 获取原始文件名 |
| 文件类型校验 | 无 | 校验 MIME 类型 |
| 允许的 MIME 类型 | 不限制 | image/jpeg、image/png |
| 文件大小校验 | 无 | 限制小于 100000 字节 |
| 文件扩展名校验 | 无 | 无 |
| 文件真实内容校验 | 无 | 无 |
| 是否信任客户端 Content-Type | 不涉及 | 是 |
| 文件重命名 | 无 | 无 |
| 文件保存方式 | move_uploaded_file() | move_uploaded_file() |
| PHP 文件直接上传 | 可以 | 默认无法通过类型校验 |
| 修改 MIME 类型绕过 | 不需要 | 可以绕过类型校验 |
| 主要防护措施 | 无明显上传限制 | 增加 MIME 类型和文件大小限制 |
| 主要安全问题 | 未对上传文件进行有效校验 | MIME 类型可由客户端控制,且未校验扩展名和真实文件内容 |
网硕互联帮助中心




评论前必须登录!
注册