Vulnerable Applications: exploring the DVWA #5

6 minute read

Today we will be taking a look at SQL Injections! What are they? What can you do with them? and what can you do to stop them? Most importantly, we’ll see them in action when we run through the DVWA’s challenges.

What are SQL Injections?

SQL Injections basically are programmer mistakes. In an application the programmer did not correctly sanitize the input given tot the application and the result is that a different SQL statement is executed than intended.

The trick with SQL Injections is that they are generally quite easy to find. All you need is a single '. That’s right, a single quote. If an application is susceptible to this kind of problem it will generally throw an error when you input the '. The error, for MySQL, looks like this:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘’’’’ at line 1

So, you found a vulnerability, now what? If it is part of a website you do not own or have been given permission to test, then you should disclose the problem to the owner and stop right there. If it is your own site or you have permission, then you can continue on to see how bad it is.

The most basic example

Lets go through a simple example. Suppose you have a login form in your application and it takes a username and password as input. Imagine that, in order to validate the credentials, you write the below SQL query. If a row is returned, the user can log in.

SELECT *
  FROM users
 WHERE username='youruser'
   AND password='yourpass'

Obviously, in the real world, you would not do it this way, especially the unhashed password!

Anyway, back to the vulnerability. If you can add anything to this query to trick it into authenticating you, you can log into the application as any user. So what would be needed for this? Well, look at the following SQL query.

SELECT *
  FROM users
 WHERE username='' OR 1=1 
    -- ' AND password='yourpass'

This is the same query, but the youruser input was changed to ' OR 1=1 -- and now the query will return a list of all users in the database. Generally an application with such a vulnerability will only check if there is at least 1 row returned and logs you in as the user in the first row. Most of the time this will be the admin user.

Getting data from a database

Now that you know how an SQL Injection works, how can you utilize it to retrieve data from a database? It is simpler then you might think.

Again, lets start with an example query. This time a list of products from a database, as you might find in a webshop.

SELECT id, name, description, price
  FROM products
 WHERE name like '%searchterm%'

The above query will list the id, name, description and price of all products in the where the name contains the searchterm. This is our injectionpoint.

To add our own data to this query we can simply use a UNION SELECT statment. This type of statement executes a second query and merges it with the result of the first query. Key here is that we need to return the exact same number of columns as the 1st query.

To try this out we can request the name of the current database.

SELECT id, name, description, price
  FROM products
 WHERE name like '%%'
 UNION 
SELECT 1, database(), 2, 3 
    -- searchterm%'

So our input to the search term would’ve been %' UNION SELECT 1, database(), 2, 3 --. This will add the name of the database to the end of the results and in your product overview you should now have the last row displaying the database name.

With this technique you can retrieve the entire contents of the database. You will need to concatenate the value of many columns into a single column most of the time, but that is a small inconvenience. In order to retrieve the whole database you need to know an awful lot about how a particular database works, where it stores its schema, where users are stored etc. Luckily there is a site you can use for this: Pentest Monkey SQL Injection Cheat Sheet. It shows you common queries to run to retrieve meta data from a database.

Remediation

The only real way to deal with this type of attack is to use paramterized queries when talking to your database. The driver will then take care of correctly escaping the input strings. If you use this approach then you are probably safe from this type of attack.

The DVWA

Lets take a look at the Damn Vulnerable Web Application. Using the ' in the SQL Injection search field shows us the expected error.

Low security

Let’s try our most basic example that we already went through.

Basic Injection

As my DVWA runs inside Docker it is using SQLite as a database, the comment character is # instead of --. I used ' or 1=1 # as an input and all the users were list. That was easy enough. Before we go into the internals of the database, lets take a look at the other security settings.

Medium security

Well, that is interesting. We are presented with a drop down and not an entry field.

Dropdown Injection

There is nowhere to enter our injection, so what can we do now? In our previous sessions we utilized the mitmproxy to intercept requests. We’ll do that again and intercept the POST from the client to the server and insert our injection there.

To intercept this request all you need to do is to set the intercept filter to ~m POST when you are about to press the Submit button. Within mitmproxy you will be able to edit the form data (just follow the on screen instructions). The trick, in this case is that a ' does not work.

mitm

In the new version the programmer used mysql_real_escape_string() to sanitize the string, but failed to put the variable $id between quotes. So a small adjustment to our attempt (1 or 1=1) and we have the same list of users.

High security

At the high level we are back to our old tricks. The first exploit works; ' or 1=1 #, but now we have to submit it through a second screen. The use of the second screen and session variables is a great deal of pain to implement, but it adds absolutely no defense to the problem it is trying to solve.

Impossible security

The impossible level is just that, impossible. The programmer used parameterized queries and saved the day. Not only was the proper approach used, as an added bonus the exact type of the variable was given. So anything else than an INT will result in the code not working. A proper fix to the problem.

Automation

As with all great things; SQL Injections have some great tools to help you out. This article is already running a little long, so I will write a second post on doing the attacks in an automated manner as a bonus.