2081 字
10 分钟
文件上传

💡 字多 ≠ 有价值

周报不是为了表现工作量,而是给团队提供最基本的“信息透明”。尽量挑选重要信息来写。

文件上传及下载漏洞学习周报#

汇报人:莫家豪 日期: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.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-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 靶场/实战检测清单(步骤化)#

  1. 在 Burp Proxy 拦截上传请求,观察 Content-Disposition: filename= 与 Content-Type。

  2. Repeater:替换文件内容为 <?php phpinfo();?> 或 <?php system($_GET['cmd']);?>,修改 filename 为常见可执行后缀,观察响应与返回路径/URL。

  3. 尝试:修改 Content-Type(image/png/jpeg)、双扩展、尾部拼接、null 编码、URL encoded 文件名、上传 .htaccess(如果可行)。

  4. 上传合法图片并用工具(exiftool)修改 EXIF,尝试把 payload 藏在 EXIF、注释或尾部。

  5. 测试 PUT 方法(很多服务器/框架允许 PUT 上传到路径)。

  6. 若上传成功但未执行:寻找别的目录(比如 CDN/存储服务、另一个主机后端)或路径混淆导致不同解析策略。

  7. 路径遍历测试:在下载/查看接口注入 ../ 或编码形式 %2e%2e%2f。

  8. 使用 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 与后续的访问触发可能依赖于服务器配置,需结合实际响应判断。)


七、防御与修复(面向开发/运维的可执行清单)#

防御要分层:输入校验 → 存储策略 → 运行时限制 → 监控与审计。

核心防御措施(要点)#

  1. 扩展名白名单(最基础):只允许确切列表(如 jpg/png/gif/pdf),并在后端小写化检查。
$allowed_ext = ["jpg","png","gif"];
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if (!in_array($extension, $allowed_ext)) { die("非法文件类型"); }
  1. 内容/文件头检测:使用 finfo_file()、getimagesize() 等函数验证真实文件类型(不要只信 Content-Type header 或文件扩展)。

  2. 文件名策略:不要使用用户上传的文件名直接保存;采用安全重命名(随机/哈希 + 时间戳),并去掉可疑字符。

  3. 存储位置:将上传目录放在webroot 之外,或确保上传目录针对可执行脚本关闭解析(例如 Options -ExecCGI、不映射为 PHP 执行)。

  4. 禁止执行权限:上传目录禁止执行(通过服务器配置:Nginx/Apache 配置或文件系统权限),并设置严格的 umask 与用户权限。

  5. 限制大小/类型/数量:设置合理的单文件与总上传大小上限,防止 DoS。

  6. 路径规范化与白名单访问:下载接口只接受内部文件 ID → 从数据库映射到物理路径,使用 realpath() 并验证是否在白名单根目录内(防止 ../)。

  7. 不在可控目录写入可执行配置:禁止用户上传 .htaccess、服务器配置文件或脚本模版。

  8. 杀毒/扫描:对上传文件进行静态签名扫描/动态沙箱扫描(敏感场景)。

  9. 日志与告警:记录上传、文件名、IP、响应,异常模式(上传可执行文件、失败的执行尝试)触发告警。

  10. 对外暴露控制:如果必须把文件放到可访问目录,确保返回的 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 不在 webroot
move_uploaded_file($tmpfile, $dest);
// 4. 记录日志
error_log("UPLOAD: $ip uploaded $filename -> $safe_name");

八、检测/验收清单#

  • 上传点是否只接受白名单后缀并校验真实文件头?

  • 上传目录是否在 webroot 外或禁用脚本执行?

  • 是否对 Content-Type、filename 做信任校验?(是否仅基于 header 决定类型?)

  • 是否允许 PUT、WebDAV、或其他非标准上传方法?

  • 是否存在 .htaccess 或配置文件被覆盖的风险?(能否上传 .htaccess)

  • 下载接口是否对 ../ 路径进行规范化并限制根目录?

  • 上传文件是否命名为用户可控名并可能覆盖已有关键文件?

  • 是否有日志/告警对异常上传(可执行文件、异常大小)进行告警?


九、#

  • 不要只靠黑名单:黑名单易漏且难维护,攻击者可用另类后缀或解析差异绕过。

  • 不要只靠前端限制:前端可被绕过(禁 JS 或直接用 Burp)。

  • 服务器配置差异:同一域名后端可能由反向代理/多台主机处理,目录的解析策略可能不同,测试时注意不同主机的差异。

文件上传
https://lab404.cn/posts/file-upload/
作者
见山
发布于
2025-11-20
许可协议
CC BY-NC-SA 4.0