0xma Cyber Security Articles




April 12, 2022

Second Order SQL Injection - Example 2

In this tutorial, we will see how to perform a second order SQL injection. The SQL injection will be performed on an item from the drop down list which the developer forgot to filter for bad characters. After revealing the contents of the database, we will see how to write a PHP file on the web server and gain reverse shell on the box.

This is the main page of the website. It takes a username and we can select our country from the drop-down list.

Main page of the website.

Let's enter a username and select a country.

Entering a username and selecting a country.

Once the username is submitted, it lists all the users in that particular country.

Viewing the users in a country.

The HTTP request that is used to submit a username in Burp Suite. It takes two paramters: username and country.

User submission HTTP request in Burp Suite.

Upon receiving the HTTP request, the web application sends us a 302 redirect to "/account.php". Note that it also sets a cookie which is the MD5 sum of the username.

302 redirect from the web application in Burp Suite.

Next, a GET request is sent to "/account.php" with the cookie sent in the 302 redirect response.

GET request in response to a 302 redirect response in Burp Suite.

Finally, the 200 response which displays the "Welcome" message.

200 response from the Burp Suite.

Running the username through md5sum shows the MD5 sum of the username which is the same as the cookie sent in the GET request.

md5sum of the username.

Now that we have an understanding of the web application, let's try to perform our SQL injection attack. Right-click on the HTTP request that is used to submit the username and country and send it to Burp Repeater.

Sending the user submission HTTP request to Burp Repeater.

Since the country name is not submitted by the user in an input box, the developer hasn't filtered it for bad characters. Let's add a single-quote (') after the country name to see how the web application handles it.

Adding a single-quote to perform a SQL injection in Burp Repeater.

Following the redirect leads to "/account.php".

Redirected to account.php.

We can make a MD5 sum of the username using the terminal or we can also copy this MD5 sum from the "Set-Cookie" response header.

Running the username through md5sum.

The next step is to right-click on the page and click on "Inspect". Let's paste in the MD5 sum of the user for the cookie and reload the page. Modifying the cookie of the page is important because we need to access the page to which this particular user belongs (in this case it is Austria).

Pasting in the MD5 sum of the username.

Note the single quote (') after the country name: Austria. It also reveals an error. This can be an indication of a SQL injection vulnerability.

SQL injection vulnerability indication.

The assumption is that this is the SQL query used to retrieve the usernames that belong to a particular country. The query returns one column called "username". If one column is returned then using a UNION statement with one value shouldn't return an error.

Assumption of the SQL query used on the web server.

Let's test this theory by adding a UNION statement with one value and send the request.

Testing for a UNION injection using Burp Repeater.

Again, it is important to modify the cookie so we could access the users for Austria.

Modifying the cookie in the browser.

We can see that "1" is returned back to us. It is an indication of a successful UNION-based SQL injection.

Successful UNION based SQL injection.

Let's see if we can return a string.

Testing a string with a UNION based SQL injection.

Good. 0xma is returned back to us.

Successful UNION-based SQL injection.

The user() function returns the current user that has access to the database.

SQL injection to find the user that accesses the database.

The user with which we are accessing the database is "uhc".

The page displays the database access user.

It reveals the databases in the system.

SQL injection command to reveal the databases.

The system has four databases.

Database names revealed.

It displays the table names in the "registration" database.

Displaying the table names in the registration database.

The "registration" database has one table in it called "registration".

Table names in the registration database.

It displays the column names in the "registration" table.

Displaying the column names in the registration table.

The "registration" table has four columns in it: username, userhash, country and regtime.

Column names in the registration table.

It displays the contents of the "username" column.

Displaying the contents of the username column.

The usernames in the "registration" table.

Usernames in the registration table.

Next, let's find out what privileges does the "uhc" user have on the box.

SQL injection to find the privileges of a user on the DBMS.

It lists all the privileges of the "uhc" user. One of the important privileges is the "CREATE" privilege, which allows us to write files on the web server.

Displaying all the privileges of the database user.

It writes a PHP web shell on the target which will allow us to execute commands via the "cmd" parameter.

Writing a PHP web shell on the web server.

Trying to access the web shell displays a warning. The web shell requires a parameter with a command to be executed.

Accessing the web shell without a command.

It runs the id command. We have access to the web server as the "www-data" user.

Running the id command reveals the www-data user.

Let's send this request to Burp Repeater so that we could easily execute other commands.

Sending the request to Burp Repeater.

It is a simple Bash command that will give us a reverse shell.

Bash reverse shell command.

However, it is important to URL encode the command before sending it to the web server.

URL encoding the command before sending it to the web server.

Send the URL encoded command.

Sending the URL encoded command through Burp Repeater.

A reverse shell is received from the web server.

Receiving a reverse shell from the web server.

It also possible to run commands from the terminal using curl.

Executing commands via curl from the terminal.

Command execution is successful and a reverse shell is received from the web server.

Receiving a reverse shell from the web server.

Our next goal is to automate this SQL injection technique. This Python script prompts us to enter a username to register, and also the SQL query that we want to run.

Running the SQL injection Python script.

Note that the username that is registered and the SQL query that is executed is separated by a colon (:).

Executing SQL query using the Python script.

Executing SQL query using the Python script.

Executing SQL query using the Python script.

Executing SQL query using the Python script.

The Python script sends all the requests through Burp Suite.

Traffic passing through Burp Suite.

This is another variation of the above Python script. This script doesn't prompt us to enter a username, instead it randomly generates a string and registers that as our username.

Python script to execute SQL query.

These are the users which the script have registered on the web application while executing SQL queries.

Executing the SQL queries through the Python script.

I want to show another technique that I learned from ippsec's walkthrough. This technique involves creating a Flask proxy server that can be accessed on the localhost and it forwards our traffic to the target.

Flask proxy server script.

Flask proxy server is running on port 80.

Running the Flask proxy server on port 80.

Accessing the localhost from the browser returns "Web App with Python Flask!".

Accessing the proxy server from browser.

The Flask proxy shows that it received a connection from the localhost.

Flask proxy logging the traffic.

It reads the "country" parameter from the GET request and displays it.

Flask proxy server script to read the country parameter.

Flask proxy server is running on port 80.

Running the Flask proxy server on port 80.

Note that "0xma" is passed as the country name and it gets displayed.

Accessing the proxy server from browser and passing a country name.

The Flask proxy shows that it received a connection from the localhost with a "country" parameter.

Flask proxy logging the traffic.

Let's modify the script to generate a random string for the username that it will register. The country name will be taken from the GET request.

Flask proxy server script to read the country parameter and generates a random username.

Flask proxy server is running on port 80.

Running the Flask proxy server on port 80.

Note that it accepts a country name from URL and sends a randomly generated username to the web application.

Accessing the proxy server from browser and passing a country name with a random username.

The Flask proxy shows that it received a connection from the localhost with a "country" parameter.

Flask proxy logging the traffic.

Let's capture the request in Burp Intercept and save it to a file.

Capturing the request in Burp Intercept.

It is saved as "reg_request".

Saving the request from Burp Intercept.

It is time to run sqlmap using the captured request. It detects the SQL injection vulnerability and will allow us to dump the contents of the database if we choose to do so.

Running sqlmap to identify SQL injection vulnerability. Running sqlmap to identify SQL injection vulnerability.

And at last, it is the PHP script on the web server that registers the user.

PHP script to register the username.

If you liked reading this article, you can follow me on Twitter: mujtabareads.