Shell Wars: Episode II - Attack of the Code {Review}

Greenwolf
Greenwolf Security
Published in
7 min readOct 5, 2020

Welcome back everyone, to Shell Wars: Episode Two!

For the last few months I’ve been taking Offensive Security’s OSWE course, which has a specific focus on code review. So, when a few weeks ago I was performing a black box application test on behalf of a large corporate client, and I was lucky enough to find a vulnerability which morphed the assessment into a white box review, I was excited to put my new skills to the test.

Path Traversal Arbitrary File Read

After running my baseline checks and Burp active scan, I saw that it has reported a path traversal issue in a file download endpoint.

Retesting this with repeater confirmed the finding:

Now this wasn’t a file inclusion vulnerability (LFI/RFI), so I wasn’t able to pull in and execute PHP code. But what it did allow me to do was start downloading the PHP source code of the application. Going up one directory allowed me to download the source of the vulnerable file, seeing what was wrong this code.

Going up another 2 directories found the index.php file of the application, and this is where things started to get interesting. The rest of the site was all closely linked together using includes, so starting from index.php, it was possible to enumerate and then download all the .php files. Then inspect these and enumerate and download all the .php files in these too. The allowed the entire source code to be exfiltrated from the server for further analysis.

This took a few hours of manual work, but eventually I had in my possession the entirety of the source code. At this point I made the decision to switch from a black box testing approach, to using white box code review techniques.

I did however need to be smart about how I approached it, as the codebase was 655,137 lines of PHP. Far too much to read completely in the remaining 2 days of the engagement.

Locating SQL Injection

One of the first things I do on a white box assessment after familiarising myself with the general application flow, is to look for SQL Injection. An easy first port of call is to grep through the codebase and look for lines which contain both “SELECT” and “$_GET”, which means a user submitted parameter is being included directly in an SQL Query. This is not exhausting as if the user submitted parameter is stored on in a variable above and then the variable is included in the query string it would be missed. But this is a good first step before moving onto more thorough review.

In this case it resulted in 391 instances of potential SQL Injection being found.

Looking through the results there were many areas vulnerable to SQL Injection. I settled on attempting to exploit one which was returning a number of rows to another query, which made it blind SQL Injection. The vulnerable cooked looked like this:

I used the MySQL BENCHMARK function to ENCODE the string ‘MSG’ 50 million times. This slowed down the processing of the server by a factor of 10, proving the SQL Injection was working.

This would allow us to extract items from the database, however it was noted that throughout the source code that passwords were stored as sha1 hashes. This meant that which it may be possible to crack them, more work would be needed to gain authenticated access to the application.

Unauthenticated Arbitrary Account Password Reset

Another key part of any code review assessment is to look at the authentication functionality of the application. Looking through the code, it was found that the code to update a user’s password, suffered from serious design flaws.

Firstly, it was found that a user’s password could be set by providing the users database ID number, and secondly that this functionality did not require any authentication. The code looked very similar to this. Note how if the type parameter is set to password_update, then the user_id in the database is set the user_id parameter, and the password in the database is set to a sha1 hashed value of the password parameter.

This was tested successfully using the following request in Burp:

This meant we were now in the position of needing the user_id to reset a user’s password. If we also know the user’s username, we can use the reset password to authenticate to the application.

Lucky for us we already had a way to extract usernames and user_id’s from the database with our blind SQL Injection vulnerability, and instead of extracting and cracking the password hash, we could now just reset the target users password and log in as them.

A Malicious File Upload

After achieving authenticated access, the rest of the codebase was open to review. One of the most common ways to get code execution in a PHP application is to upload a simple PHP file which executes a parameter as a system command.

I began by just searching for the word “upload” in the codebase. This returned only 223 lines to focus my efforts on.

Looking through these using Sublime Text found that many of them were uploading target files to folders outside of the web applications path, making them inaccessible externally. Still more have blacklists implemented.

However, as an attacker, all we ever need is for the developer to make one mistake, which they did on one upload endpoint. On this particular endpoint they had implemented 2 stage validation, where an initial request was sent with the file name, to check its extension. Then if this returned successfully a second request was sent uploading the file contents. You can see in the code below how the session_check.php file is include to enforce authentication on this endpoint. The upload folder is set to ‘upload/’, and then beside a few disallowed characters, no other filtering is applied to the upload.

This meant it was possible upload a legitimate .txt file and edit the second request to change it to our simple PHP web shell.

This uploaded the PHP file to a directory we could access, and there were no limitations on the directory to prevent PHP execution (such as a .htaccess file). We then achieved remote command execution by sending operating system commands to the ‘cmd’ parameter oh the cmd.php file.

So today we walked through how a path traversal in a file download function allowed the exfiltration of all of the applications source code, at which point it was possible to pinpoint an SQL Injection which was abused to reveal usernames. A flaw in a password reset function was used to achieve authenticated access, at which point a web shell was uploaded to the target server.

A quick word on remediation here for the blue team. I hope the above shows how important it is to do validation of user input across all areas of the application. Escaping Path Traversal strings and SQL Injection characters should have prevented these vulnerabilities, as well as checking the file upload type server side.

The password reset functionality is fundamentally flawed as it uses a database ID number to reset the password, rather than using the user’s email. It also should not be possible to choose what the password is reset to. A quick fix would be to send a random password to the user’s email, while a more secure and long-term solution would be to send a password reset link with a token in the URL, which has been stored hashed server side (to prevent a bypass with SQL Injection).

I hope you all enjoyed reading along, this test was a lot of fun and what really encouraged me to write this post was that I got to use all the skills I learnt during my OSWE training course. If you found the above vulnerabilities interesting, and want to improve your white box application assessment, I would highly recommend it! I’ll be releasing a review of the course soon too, so remember to subscribe for notifications if you would like to read more about it.

Thank you very much for reading, I hope you visit again soon!

For more information on the vulnerabilities mentioned through this post, please see the following resources.

--

--