SQL Injection Attack in DVWA with Low Security Level

Audrey Betsy Rumapea
6 min readSep 26, 2021

Damn Vulnerable Web App (DVWA) is a web application that is coded in PHP and uses MySQL database, where we can practice some common web vulnerabilities with different levels of security. Basically, it is a place where we can legally test our hacking ability. In this article, we’re only going to talk about one of the attack in DVWA, SQL injection.

SQL injection, also known as SQLi, is an attack that executes malicious SQL code. SQL itself is a query language that can access, modify, and delete data. Hence, SQL injection allows attacker to do a lot of things with a web’s database, ranging from accessing all data in database (e.g. finding data for all students such as illustrated below) to altering (e.g. changing bank account’s balances) and deleting data.

SQL injection based on 1=1 is always true

Trying SQL Injection in DVWA

As stated above, DVWA has several security levels, which are low, medium, high, and impossible.

  1. Low: Vulnerable, no security measures at all. Usually used as example of bad coding practices in websites.
  2. Medium: Security measures exist but fail to secure. It challenges users to refine their exploitation techniques.
  3. High: Harder or alternative bad practices (compared to medium security level).
  4. Impossible: Secure. Used as a comparison to the vulnerable source code.

In this article, as stated on the title, we will use low vulnerability level. Are you ready? Let’s go.

Preparation

Here, I used XAMPP as my web server, so I had to activate Apache and MySQL first. Next, open localhost/dvwa which will show DVWA’s login page. To log in, enter ‘admin’ as username and ‘password’ as password.

DVWA’s main page

The default security level for DVWA is ‘impossible’. Therefore, we have to change it into ‘low’. To do it, go to DVWA security, select the ‘low’ security level, and press ‘submit’.

Changing DVWA security level

White Box Testing

In DVWA’s SQL injection page, there is a form where users can input user ID. If users press submit, it will return the data (ID, first name, and surname) of a record which has the inputted user ID.

Here’s the low security level code for requesting input for users. To acquire this source code, I executed C:\xampp\htdocs\dvwa\vulnerabilities\sqli\source>low.php in my computer. Do note that it might be different in your computer.

<?phpif( isset( $_REQUEST[ 'Submit' ] ) ) {
// Get input
$id = $_REQUEST[ 'id' ];
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
mysqli_close($GLOBALS["___mysqli_ston"]);
}
?>

You can see that it sets input as variable ‘id’.

$id = $_REQUEST[ 'id' ];

Then, it executes the query below.

$query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";

Logically, this query is correct. However, it’s a dynamic SQL query, which means it directly uses user’s input into the query. The web form in DVWA doesn’t have limitations in inputs, so attackers can input additional commands in the web form. Hence, it is vulnerable to attacks, which will be demonstrated below.

A. Based on always true value

By using a value which will always remain true, we can fetch all the data in database. An example of always true value is ‘1’=’1' or ‘2’=’2', etc. So, in a query, it will look like this.

SELECT first_name, last_name FROM users WHERE user_id = '<anything>' OR <always true value>

For our example today, I’m going to replace <anything> with ‘a’ and <always true value> with ‘1’=’1'

SELECT first_name, last_name FROM users WHERE user_id = 'a' OR '1'='1'

So, we need to assign a’ or ‘1’=‘1 to variable $id.

Assigning input as variable $id

As you can see, it shows ID, first name, and surname for all IDs in database.

B. Union-based

Union clause allows attackers to execute additional Select queries and add results to the original query. It can be used to get data from other tables. However, you need to make sure that:

  • Each query return the same amount of columns
  • The data types in each column must be compatible between queries

In this article, I will try to look up the columns available in Users table. To do that, I will assign ‘ and ‘1’=’1' UNION SELECT null, CONCAT(table_name,0x0a,column_name) FROM information_schema.columns WHERE table_name = ‘users’ # to variable $id so that the query looks like this:

$query  = "SELECT first_name, last_name FROM users WHERE user_id = '' and '1'='1' UNION SELECT null, CONCAT(table_name,0x0a,column_name) FROM information_schema.columns WHERE table_name = 'users' #';";

Here’s the result of the query execution.

It shows that Users table have 10 columns: user_id (the identifier), first_name, last_name, user, password, avatar, last_login, failed_login, CURRENT_CONNECTIONS, and TOTAL_CONNECTIONS.

Then, we’ll try to get user_id, first_name, last_name, user, password, avatar, last_login, failed_login of all users. I divide the data into 2 CONCAT clauses. The first CONCAT consists of user_id, first_name, last_name, user, and password, while the second CONCAT consists of avatar, last_login, and failed_login. Below is the query executed.

$query  = "SELECT first_name, last_name FROM users WHERE user_id = '' or '1'='1' UNION SELECT CONCAT(user_id,0x0a,first_name,0x0a,last_name,0x0a,user,0x0a,password),CONCAT(avatar,0x0a,last_login,0x0a,failed_login) FROM users #';";

And here is the result of the query.

From the data above, we can even get the password of the users, which are actually really sensitive and shouldn’t be exposed. So, the next question is..

How To Avoid SQL Injection?

  • Check if the input is numeric

IDs are usually integers in databases. To avoid additional commands in the inputs, we can check the input type and ignore the input if it’s not an integer. To achieve this, we can use the code below.

if(is_numeric( $id ))
  • Ensure that there is only one record as result of query execution

The web form actually wants users to only input 1 user ID so that it can give the corresponding data. However, the attacks enable attackers to execute a query that provides data for more, if not all, user IDs. We can use LIMIT to avoid this vulnerability.

$query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;

I’ve also read that there are even more secure fixes to the code, such as:

  1. Using prepared statements with parameterized queries. If we use prepared statements, attacker can’t change the intent of a query. If an attacker enters the userID of tom’ or ‘1’=’1, the parameterized query will look for a username which matches string tom’ or ‘1’=’1.
  2. Using stored procedures. It also uses SQL statements with parameters, but the SQL code for a stored procedure is defined and stored in the database.
  3. Allow-list input validation. This validation makes sure that only valid user inputs are executed.

To sum up, we’ve learned the definition of SQL injection, source code with low level security, example of the attacks caused by low level security in source code, and also how to improve the code’s security. Bye for now!

This article is written by Audrey Betsy Rumapea (18218039) to fulfill Task 2: DVWA White Boxing for II4033 Digital Forensic

--

--