SQLi Series: An Introduction to SQL Injection

Web applications often need to store data to better serve their customers. An example would be storing customer login information or comments submitted by users on the webpage. There are many ways of storing data for customers, but a popular way is to store the information in a SQL database.

A common and basic use of web applications and SQL databases is to handle user login information and functionality. In many web applications a user submits a username and password into a form. The web application takes the submitted data and searches the database to determine if it’s a valid credential set. If it is, then the web application will log the user in.

SQL Injection

If the web application does not properly handle user input, an attacker might be able to create malicious input that changes the SQL query that performs that login task behind the scenes. Such SQL injection attacks take a lot of manual effort to discover and exploit, but they are a critical part of the web application penetration tests that we perform at Raxis.

This blog explains how an attacker could find and exploit a SQL injection, or SQLi, vulnerability.

Creating an Exploitable Login Webpage

Let’s build a simple web application that asks for a username and password and returns the user’s ID. In order to help show the SQL injection attack, the application will also show the query used and the input from the login page. The SQL code the application uses (with user input parameters filled in) can be seen at the bottom of each screenshot.

First let’s take a look at the results for the admin logging in normally.

Successful login showing SQL query

We can see that the user entered the admin username and password. We also see that our sample PHP web application uses a query where the username and password must match for success. If both match then, for our testing purposes, it returns the user ID which is printed out at the bottom.

Here the admin’s account has the ID of 1.

In the next example, the admin username is entered correctly, but the wrong password is supplied.

Unsuccessful login showing the SQL query

Again we can see the information that was input into the application and the query. However, since the password does not match the one in the database, we don’t get the user ID.

Exploiting the Webpage to Login

In the example queries above we saw that the username and password input was passed into the query without modification.

So what happens if we close the single quote around the username?

Attempted SQL injection with a single quote

We see that, even though the correct password was entered, the single quote at the end of the username prevents the query from returning a correct result. In this case we get the same error message as if the username and password were incorrect, but other web applications might crash in different ways indicating there was a backend issue.

In MySQL the # symbol denotes a comment, which makes the database ignore everything after it. Let’s try adding a # after that single quote we just added:

Successful SQL injection bypassing the password

Now we see that, even though we submitted the wrong password, the application considers the SQL query successful and returns the correct user ID. The question is What is happening here?

Let’s take a closer look at the query and the input from the user.

The input in the username field has injected two special SQL characters: the (single quote) and the #.

This changes the query itself because the user input is directly inserted into the query.

Highlighting that the MySQL # comment symbol allowed the SQL injection to work

The single quote closes the username entry so that the text that comes after is read as part of the SQL query. This means that the # is interpreted as the comment symbol, meaning that the rest of the query is simply ignored.

Basically, that means that the query is now just running as

SELECT id, username, password FROM users WHERE username=’admin’

Since the admin user exists, we get the successful result of the user id of 1, even with the wrong password.

This also means that we can login as any user, provided that we know their username. Just change the admin username to the desired username.

Using the same injection string to login as another user

Exploiting the Webpage to Get Data

Now logging in as any user is fun and all, but what else can we do? Well, we can come up with SQL queries that dump information from the database.

Let’s use the UNION operator to inject another SQL query that goes along with the query created by the application. We should note that, since the sample web application only shows one column at a time, we need to switch what we are asking for first so that the application will show us more information.

Here is what happens when we add a UNION SELECT for all the user IDs from the users table to the SQL injection we are entering in the username field:

SQL injection adding UNION SELECT to get a list of all user IDs.

After asking for the IDs, we enter a new SQL injection and ask for the usernames:

SQL injection adding UNION SELECT to get a list of all usernames.

And finally, we perform a SQL injection requesting the passwords:

SQL injection adding UNION SELECT to get a list of all passwords.

A Quick Note on Password Hashes

This is a good time to note why using password hashes (instead of saving passwords in plaintext) is a good idea. If password hashes were in use, an attacker would have to crack the passwords in order for them to be useful in a SQL injection attack.

Automated Exploitation with SQLMap

While we can do attacks such as these manually, sometimes, after identifying a vulnerability, it is easier to use tools to exploit it for you. In real life scenarios, SQLi attacks don’t return the SQL statement, and it takes some trial and error to discover how the application is reacting to our input.

My go-to tool for SQL injection attacks once I find a sign of them is always SQLMap. Here is a screenshot of SQLMap dumping the users table from the SQLi database the web application above uses.

The SQLMap tool performing the same exploit we did manually

SQLMap makes it a lot easier to dump information from a database when an application is susceptible to SQLi attacks. While here it dumped the same information we just did, it is capable of finding every table and column and dumping everything.

More Than SQLi

We should also note there are other ways of getting information from a database, including timing attacks in which a database waits to respond if something is true while responding quickly if it’s not. Timing attacks allow us to guess what input is valid and what is not valid. Maybe we will take a look at a timing attack example in another post.

In Conclusion

Now that we have a basic understanding of what SQL injection is and the types of exploits that can be done with it, my next posts in this series will go into specific attacks and how to perform them.

As always, remember that these tutorials are guides for penetration testers and people looking to understand their penetration test results better. Attempting these attacks on any sites that don’t belong to you or where you don’t have legal documentation granting you access to perform ethical penetration testing is illegal and punishable under law.

More posts