Operator On The Wire
← Back to Knowledge Base
OOTW / Chapter III - Web / 04. File Uploads

Cheatsheet

Use this as a quick reference while testing file upload handling in labs and authorized assessments.


Common Targets

avatar
profile picture
support attachment
document upload
report import
CSV import
image upload
PDF upload
archive upload
admin restore
theme upload
template upload

File Type Tests

Plain text:

proof.txt

HTML proof:

<!doctype html>
<script>
document.body.innerText = document.domain;
</script>

SVG proof:

<svg xmlns="http://www.w3.org/2000/svg" width="600" height="120" onload="document.querySelector('text').textContent=document.domain">
  <text x="20" y="60">waiting</text>
</svg>

Tiny PNG:

printf 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+/p9sAAAAASUVORK5CYII=' | base64 -d > proof.png

Extension Checks

Try:

proof.html
proof.svg
proof.txt
proof.php.txt
proof.txt.html
proof.HTML
proof.jpg
proof.svgz

Watch for:

case-sensitive checks
last-extension-only checks
blacklists
missing SVG handling
original filename reuse
stored filename predictability

MIME Checks

Send a chosen content type:

curl -i -X POST "http://127.0.0.1:5000/file-uploads/basic" \
  -F "file=@upload-proof.html;type=text/html"

SVG as image:

curl -i -X POST "http://127.0.0.1:5000/file-uploads/better" \
  -F "file=@upload-proof.svg;type=image/svg+xml"

Mismatch extension and MIME:

curl -i -X POST "http://127.0.0.1:5000/file-uploads/better" \
  -F "file=@upload-proof.svg;filename=proof.jpg;type=image/svg+xml"

Client-supplied Content-Type is not proof of file safety.


Lab curl Checks

Basic upload:

curl -i -X POST "http://127.0.0.1:5000/file-uploads/basic" \
  -F "file=@upload-proof.html;type=text/html"

Weak blacklist bypass:

curl -i -X POST "http://127.0.0.1:5000/file-uploads/blacklist" \
  -F "file=@upload-proof.html;type=text/html"

Better-stage SVG exploit:

curl -i -X POST "http://127.0.0.1:5000/file-uploads/better" \
  -F "file=@upload-proof.svg;type=image/svg+xml"

Fixed SVG rejection:

curl -i -X POST "http://127.0.0.1:5000/file-uploads/fixed" \
  -F "file=@upload-proof.svg;type=image/svg+xml"

Fixed PNG acceptance:

curl -i -X POST "http://127.0.0.1:5000/file-uploads/fixed" \
  -F "file=@proof.png;type=image/png"

Response Checks

Check headers:

curl -I "http://127.0.0.1:5000/file-uploads/files/basic/upload-proof.html"

Look for:

Content-Type
Content-Disposition
X-Content-Type-Options
Cache-Control

Riskier responses:

Content-Type: text/html
Content-Type: image/svg+xml
inline rendering
missing X-Content-Type-Options: nosniff
same-origin upload URL

Defensive Review

Confirm:

  • The application uses allowlists instead of blacklists.
  • The server checks magic bytes for accepted file types.
  • The server generates stored filenames.
  • Uploads are not stored in executable directories.
  • Active formats such as HTML and SVG are blocked or isolated.
  • Untrusted uploads are served from a separate origin when possible.
  • Files that do not need inline rendering are served as attachments.
  • Upload size limits are enforced.
  • Upload download routes enforce authorization.
  • Rejected uploads are logged.