SQL Injection Union Based Exploitation : Part 1
We have posted a lot on SQL injection . There are various techniques and ways of exploiting the SQLinjection loopholes in the Web Application . Many of us exploit SQL Injection holes without knowing what is actually happening on the backend. It might be possible to penetration test a few easy sites by followingtutorials exactly as they are. But to actually master the art of SQL Injection, you need to know what is happening and how to alter the way it works. I truly believe that knowing how something works and how to alter the way it works is what differentiates a hacker from a skid. This tutorial is going to be long, please bear with me. I’m going to explain every single step in a detailed manner. It is always good to know the language we are working with, in this case it is SQL.
I suggest you to take a look at this before reading the tutorial. It will help you to understand the concepts quicker: http://www.w3schools.com/sql/
How do I check if a website is vulnerable to SQLi?
You can check if a website/web app is vulnerable to SQLi by putting a single quote (‘) at the end of the URL.
(Note: This might not work for advanced injection techniques like time based injection)
If the web page throws an error at us when a single quote (‘) is added, the webpage might be vulnerable. The error generally looks like this:
(Note: This might not work for advanced injection techniques like time based injection)
If the web page throws an error at us when a single quote (‘) is added, the webpage might be vulnerable. The error generally looks like this:
To understand how this works, you will have to know what is happening on the backend when you visit a website which is data driven (that is, in simpler terms, which uses a database or retrieves info from a database to be shown on the page).
Let’s say this is our potential vulnerable website which is data driven:
Code:
http://www.example.com/index.php?id=1
So when we visit the site, a query is made to the database to find and retrieve the data row which has an ID of ‘1’.
Let’s take a look at the piece code (query) which makes this happen:
Code:
$id = $_GET['id'];
$sql = "SELECT * FROM profiles WHERE id='$id' LIMIT 0,1";
As you can see, the variable $id is being assigned to the GET request ‘id’ without being properly sanitized (or sanitized at all). So when we put a single quote (‘), the whole query gets messed up:
Code:
http://www.example.com/index.php?id=1'
The query becomes:
Code:
$sql = "SELECT * FROM profiles WHERE id='1'' LIMIT 0,1";
That extra quote after 1, messes it all. The DB gets confused and throws an error at us. This is just to make sure if our queries get executed on the DB or not.
Note: Sometimes single quote won’t work and you will have to try double quotes. It depends on the type of quotes the variable is enclosed in. Put a backslash (\) at the end of the URL to find out which quote to use, sometimes the query even has brackets.
As you can see, the backslash is getting enclosed in single quotes. So, I’m supposed to use a single quote to mess the query up.
So earlier, we successfully messed up the query but putting a single quote (‘). Now its time to fix it. Leave a space and put two dashes and a plus (–+) after the single quote.
So it becomes:
Code:
http://www.example.com/index.php?id=1' --+
If the above injection fixes the query (that is, if the page is being displayed as it is supposed to be), we are working with a “String Based Injection”.
Let’s break it down.
Let’s break it down.
Two dashes and a plus (–+) is actually a multi-line comment in SQL. Or the plus sign (+) can be considered as a space. The plus sign might not get passed on to the actual query in some cases. When it is injected, the query becomes:
Code:
$sql = "SELECT * FROM profiles WHERE id='1'--+' LIMIT 0,1";
Now there are no extra quotes in the middle to mess up the query and it is also a valid query. Whatever is after the –+ is considered as a comment and is ignored by the DB. Since the query is valid, DB returns the right info.
In some cases, the above query doesn’t fix the query. If that is the case, we are working with a “Normal Union Based Injection”
Let’s take a look at the code/query that causes it:
Code:
$sql = 'SELECT * FROM profiles WHERE id=$id LIMIT 0,1';
As you can see, the variable isn’t enclosed in quotes. So it is useless to use a quote and a multi line comment. So, we inject in this way:
Code:
http://www.example.com/index.php?id=1 --
Then the query becomes:
Code:
$sql = 'SELECT * FROM profiles WHERE id=$id -- LIMIT 0,1';
So no extra queries in the middle, just nice and clean. So this is a valid query and the DB responds with the right info.
Now that we know that the site is vulnerable to SQLi, we will have to find out the number of columns being queried by the page. For example, if the ‘profiles’ tables has ‘name’, ‘age’ ‘bio’ columns and if the query is:
Code:
SELECT name, age FROM profiles WHERE id=$id LIMIT 0,1;
That means, the page is querying 2 columns from the DB. And those column data is showed on the page.
Counting Columns:
To count the number of column being queried by the page, we use an “ORDER BY” statement.
If you have a string based injection, the payload becomes:
Code:
http://www.example.com/index.php?id=1' ORDER BY x --+
If you have a normal union based injection, the payload becomes:
Code:
http://www.example.com/index.php?id=1 ORDER BY x --
Basically the difference between String Based Injection and Normal Union Based Injection is the way we mess up and fix the queries, the rest is same for both.
Since we don’t know the number of columns, we are going to guess it.
For a string based injection, the payload is (if you are working with a normal union based injection, just remove the quote and the plus):
Code:
http://www.example.com/index.php?id=1' ORDER BY 10 --+
You get some error …….
So that means that the number of columns is not correct. It should be less than that. I’m going to try 5 this time:
Code:
http://www.example.com/index.php?id=1' ORDER BY 5 --+
I get the same “Unknown Clause” error. So the number is definitely less than 5. Going to try 3 now.
Code:
http://www.example.com/index.php?id=1' ORDER BY 3 --+
No error! That means the number of columns is either greater than or equal to 3. Let’s try 4 now.
Code:
http://www.example.com/index.php?id=1' ORDER BY 4 --+
I get the same “Unknown Clause” error. I get no error for 3 and I get an error for 4. So this means, the number of columns is equal to 3.
So now that we know the number of columns being queried by the page, we need to know which of the columns actually get printed out on to the page. For example, say 3 columns are being queried for and only two of them are being printed on to the page. So we inject into any of the column being printed. There is no point in injecting into a column which is not visible, as we have to see the DB’s response to actually proceed in injecting.
Finding the Appropriate Columns to Inject to Inject Into:
We can consider these “visible columns” as the “most vulnerable columns”. We use an “UNION SELECT” statement to find out the “most vulnerable columns”. UNION statement is used to combine the result of multiple SELECT statements at once. If look closely, we had a select statement at the beginning of the query. So to it, we are putting another SELECT statement, so we have to use a UNION SELECT to combine the results of those two SELECT queries.
NOTE: Always put a “-” minus sign before the GET value. In this case the ‘id’ value. We have to do this because the result shows only the first query result on the page and our injection is not shown if the vulnerable GET request has a valid value. ID value can’t be negative, so by putting the minus sign before it, we are making it an invalid value, thus, only our injection result shows up and not the actual query result. This is important.
If you have a string based injection, the payload becomes:
Code:
http://www.example.com/index.php?id=-1' UNION SELECT 1,2,3 --+
If you have a normal union based injection, the payload becomes:
Code:
http://www.example.com/index.php?id=-1 UNION SELECT 1,2,3 --
When I use that payload, the query becomes:
In the case of String Based Inject:
Code:
$sql = 'SELECT * FROM profiles WHERE id='$id' UNION SELECT 1,2,3 --+' LIMIT 0,1';
In the case of Normal Union Based Inject:
Code:
$sql = 'SELECT * FROM profiles WHERE id=$id UNION SELECT 1,2,3 -- LIMIT 0,1';
The page gives me 2 numbers. They are the visible or most vulnerable columns:
Now, it means, I can inject into either the 2nd or the 3rd column.
The tutorial is continued in the Second Part . Link to Second Part