Misc CTF - Upload Restrictions Bypass
This challenge highlight the potential risks of bad upload handling and how it can lead to remote code execution on server. In this writeup will go back to the basics and discuss the most common ways to bypass upload restrictions to achieve RCE.
Tl;Dr: The upload server don’t check correctly the file type of uploaded images. It’s possible to bypass the filter by uploading php5
, GIF, or JPEG file containing PHP commands that get executed by the server.
Alright! Let’s get into the details now!
Recon
Opening the challenge display the following website:
Once we upload an image we can see it being stored on the server:
While looking at the request information we notice the app is running PHP 5. This might come useful later:
1 | $ curl http://misc.ctf:33432/ -I |
Sending PHP files
So far we know that the file we send is being stored on the server and the server is running PHP. With those informations we can imagine one way to abuse this upload form: If we could manage to send PHP files we could potentially execute our own PHP script on the server and get full control of it.
Let’s see how we can do that.
First to have a file executed as PHP we need this file to have a valid PHP extension to be recognised as such by the server.
Let’s edit the request made when uploading a file by changing filename
parameter to see if we can change our image file to have a .php
extension:
1 | POST /index.php |
And bummer the server return to us a 400 Bad Request
.
After a few different tries it’s easy to notice that the server is using a blacklist and not a whitelist of “valid” file extension since it’s possible to upload .xyz
, .phhp
, .html
and so on.
So now we know that the server is blacklisting .php
extension. And as with every blacklist we know that something will probably be forgotten…
Bypassing file extension restriction
Firstly it’s good to know that not only .php file gets interpreted as PHP by servers, there is some other less used extensions that gets interpreted as-well:
- .phtml
- .php3
- .php4
- .php5
- .inc
Maybe one of those extension is not blacklisted by the server ?
Since we know the server is running PHP5 let’s give a try to .php5
extension:
1 | POST /index.php |
Bingo! The file got uploaded and is now accessible on the server:
1 | $ curl http://misc.ctf:33432/1592382731183.php5 -I |
Note: It was also possible to use capital PHP extension to bypass the filter (.PHP
, .pHp
, etc…)
Alright we have a file that can get executed as PHP, now we need to put actual PHP content in it.
Let’s give a try like before:
1 | POST /index.php |
And again we get hit by a 400 Bad Request
. Seems like there is another check on the file content itself now…
Bypassing File Content Check
If we check the PHP documentation on how to check a file for its type we stumble upon mime_content_type()
:
mime_content_type
Detect MIME Content-type for a file
https://www.php.net/manual/en/function.mime-content-type.php
Well so far we know for sure that GIF and JPEG files are allowed. Can we possibly snuggle PHP into one of those two files?
Including PHP in a GIF file
Reading through the GIF Specification we found that the Comment Extension allows to put a comment in the GIF at the end of the file. We should probably be able to put PHP code there:
1 | 7 6 5 4 3 2 1 0 Field Name Type |
Since PHP mime_content_type()
function validate a file as being a “GIF” simply if the GIF header is present, we should be able to append PHP code to the GIF Header and bypass the upload restriction. Let’s give it a try.
The simplest way is to append our PHP code to the GIF89a
header: GIF89a;<?=phpinfo();
.
Let’s send that:
1 | POST /index.php |
This time the file gets uploaded successfully. We can find our phpinfo being executed when opening the file:
Including PHP in a JPEG file
Following the same idea it’s also possible to append PHP into a JPEG image.
The JPEG header being slightly less complicated than the GIF89a
of GIF we can append our PHP code to an existing JPEG image to keep it simple:
1 | $ echo "<?=phpinfo();" >> myimage.jpg |
And upload it as before:
1 | POST /index.php |
The file gets uploaded successfully. And even though the output contains a bit more rubbish (the actual JPEG bytes), our PHP code get successfully executed:
Using PHP for Remote Code Execution
Having a way to execute PHP on the serveur make it easy to escalate to Remote Code Execution on the server.
We can use for example the system()
function of PHP:
system
system — Execute an external program and display the output
https://www.php.net/manual/en/function.system.php
Let’s create a new malicious file and upload it:
1 | POST /index.php |
And now we should be able to pass our command as cmd
parameters to get executed on server side:
1 | $ curl "http://misc.ctf:33433/1592382731199.php5?cmd=cat/etc/passwd" |
And finally while looking for the Look at Me app source code we find the flag:
1 | $ curl "http://misc.ctf:33433/1592382731199.php5?cmd=cat%20index.php" |
References
- Weak Protections on File Upload | OWASP
- Bypass File Upload Filtering | OSCP Guide
- Six files that are also a valid PHP
Prevention Methods
- Use a server-generated filename if storing uploaded files on disk.
- Inspect the content of uploaded files, and enforce a whitelist of accepted, non-executable content types. Additionally, enforce a blacklist of common executable formats, to hinder hybrid file attacks.
- Enforce a whitelist of accepted, non-executable file extensions.
- If uploaded files are downloaded by users, supply an accurate non-generic Content-Type header, the X-Content-Type-Options: nosniff header, and also a Content-Disposition header that specifies that browsers should handle the file as an attachment.
- Enforce a size limit on uploaded files (for defense-in-depth, this can be implemented both within application code and in the web server’s configuration).
- Reject attempts to upload archive formats such as ZIP.
- Uploaded directory should not have any “execute” permission and all the script handlers should be removed from these directories.
- All the control characters and Unicode ones should be removed from the filenames and their extensions without any exception.
Real Life Example
That’s it folks! As always do not hesitate to contact me for any questions or feedbacks!
See you next time ;)
-hg8