File Upload Attacks¶
Mentor's Note
File upload is one of the highest-value attack surfaces on the web. If you can write a file the server will execute, you usually own the box. Treat every upload form as a potential remote code execution (RCE) primitive until you prove otherwise.
This series breaks the topic into focused, bite-sized lessons so you can revise one idea at a time. Read it top to bottom the first time, then use the cheatsheet for last-minute review before the exam.
The Core Idea¶
Almost every modern app lets users upload something — profile pictures, PDFs, attachments, avatars. The moment an app accepts user-controlled files, it accepts the risk of storing attacker-controlled data on its own server. If the file type and contents aren't strictly validated, you can often upload a script the server will run for you.
These bugs are consistently rated High/Critical for one reason: a successful arbitrary file upload is one short step from full server compromise. The worst case is an unauthenticated arbitrary file upload — anyone, no login required, drops a payload and gets code execution.
What File Uploads Get You¶
The headline outcome is RCE via a web shell or reverse shell. But even when you can't upload arbitrary code, a weak upload feature is still dangerous:
| Outcome | How |
|---|---|
| Remote Code Execution | Upload a server-side script (.php, .aspx, .jsp) the server executes. |
| Stored XSS | Upload an HTML or SVG file containing JavaScript. |
| XXE / SSRF | Upload a malicious SVG or XML-based document (DOCX is XML under the hood). |
| Denial of Service | Decompression bombs (zip bombs), pixel-flood images, or filling the disk. |
| Overwrite critical files | Path traversal in the filename (../../) to clobber config or app files. |
| Second-order attacks | Upload a file later processed by a vulnerable back-end library. |
Vulnerable libraries count too
File upload bugs aren't only about sloppy validation code. Outdated image/PDF/parsing libraries (ImageMagick "ImageTragick", libvips, Ghostscript, etc.) are routinely exploitable through an otherwise "safe" upload.
The Methodology¶
A repeatable workflow keeps you efficient under exam pressure:
- Test for absent validation — can you just upload a script?
- Fingerprint the stack — what language/framework runs the app? Your payload must match it.
- Prove code execution — upload a harmless "Hello World" script first.
- Weaponize — drop a web shell or reverse shell.
- If blocked, bypass — start with client-side validation (the weakest), then server-side filters (extension blacklists → whitelists → Content-Type/MIME → magic bytes).
- If RCE is impossible — pivot to limited-upload attacks (XSS, XXE, SSRF, DoS) and filename injections.
Decision flow
Can I upload any file? → Absent validation: upload a shell. Blocked in the browser only? → Client-side bypass. Server rejects the extension? → Blacklist / Whitelist bypasses. Server checks the file type? → Content-Type / MIME / magic bytes. Can't get RCE at all? → Limited file uploads.
How to Use This Series¶
Work through the lessons in order — each builds on the last:
-
Identify the server language so your payload actually executes.
-
The simplest case — no checks at all — plus proving code execution.
-
Web shells and reverse shells: ready-made, custom, and
msfvenom. -
Defeat browser-only checks with a proxy or the DevTools console.
-
Fuzz for forgotten extensions a blacklist never thought to block.
-
Double extensions, character injection, and weak regex.
-
Spoof Content-Type and forge magic bytes to fool content checks.
-
XSS, XXE, SSRF, DoS, and filename injection when RCE is off the table.
-
How to actually secure an upload feature (the defender's view).
-
One-page quick reference for exam day.
Master Tooling Reference¶
| Job | Primary | Alternatives |
|---|---|---|
| Tech fingerprinting | Wappalyzer | whatweb, httpx, nmap http-enum, BuiltWith |
| Extension fuzzing | Burp Intruder | ffuf, wfuzz |
| Intercept/modify upload | Burp Suite | Caido, OWASP ZAP, mitmproxy |
| PHP web shell | <?php system($_REQUEST['cmd']); ?> |
phpbash, weevely, p0wny-shell, b374k, WSO |
| .NET/ASP shell | <% eval request("cmd") %> |
China Chopper, Antak (Nishang) |
| Reverse shell payload | pentestmonkey | revshells.com, msfvenom, SecLists |
| Listener | nc -lvnp |
rlwrap nc, pwncat-cs, socat |
| Magic bytes / file type | file, xxd |
hexedit, Burp hex view |
| Shell wordlists/payloads | SecLists /Web-Shells/ |
PayloadsAllTheThings (Upload Insecure Files) |
The one rule that matters
Client-side validation is a UX feature, never a security control. Every upload restriction must be enforced server-side. The bypasses in this series exist because that rule is broken so often.