☑️Injections

First lets look at how SQL databases work with web applications. Once a DBMS is installed and set up on the back-end server and is up and running, the web applications can start utilizing it to store and retrieve data.

For example, within a PHP web application, we can connect to our database, and start using the MySQL database through MySQL syntax, right within PHP, as follows:

$conn = new mysqli("localhost", "root", "password", "users");
$query = "select * from logins";
$result = $conn->query($query);

Then, the query's output will be stored in $result, and we can print it to the page or use it in any other way. The below PHP code will print all returned results of the SQL query in new lines:

while($row = $result->fetch_assoc() ){
	echo $row["name"]."<br>";
}

Web applications also usually use user-input when retrieving data. For example, when a user uses the search function to search for other users, their search input is passed to the web application, which uses the input to search within the databases:

$searchInput =  $_POST['findUser'];
$query = "select * from logins where username like '%$searchInput'";
$result = $conn->query($query);

If we use user-input within an SQL query, and if not securely coded, it may cause a variety of issues, like SQL Injection vulnerabilities.

What is injection?

In the above example, we accept user input and pass it directly to the SQL query without sanitization.

Sanitization refers to the removal of any special characters in user-input, in order to break any injection attempts.

Injection occurs when an application misinterprets user input as actual code rather than a string, changing the code flow and executing it. This can occur by escaping user-input bounds by injecting a special character like ('), and then writing code to be executed, like JavaScript code or SQL in SQL Injections. Unless the user input is sanitized, it is very likely to execute the injected code and run it.

For example, if we search for 1'; DROP TABLE users;, the search input would be:

So, the final SQL query executed would be as follows:

Types of SQL Injections

SQL Injections are categorized based on how and where we retrieve their output.

In-Band

In simple cases, the output of both the intended and the new query may be printed directly on the front end, and we can directly read it. This is known as In-band SQL injection, and it has two types: Union Based and Error Based.

With Union Based SQL injection, we may have to specify the exact location, 'i.e., column', which we can read, so the query will direct the output to be printed there.

As for Error Based SQL injection, it is used when we can get the PHP or SQL errors in the front-end, and so we may intentionally cause an SQL error that returns the output of our query.

Blind

In more complicated cases, we may not get the output printed, so we may utilize SQL logic to retrieve the output character by character. This is known as Blind SQL injection, and it also has two types: Boolean Based and Time Based.

With Boolean Based SQL injection, we can use SQL conditional statements to control whether the page returns any output at all, 'i.e., original query response,' if our conditional statement returns true.

As for Time Based SQL injections, we use SQL conditional statements that delay the page response if the conditional statement returns true using the Sleep() function.

Out-Of-Band

Finally, in some cases, we may not have direct access to the output whatsoever, so we may have to direct the output to a remote location, 'i.e., DNS record,' and then attempt to retrieve it from there. This is known as Out-of-band SQL injection.

Note: For now we only focus on In-Band SQL Injections.

Subverting Query Logic

Before we start subverting the web application's logic and attempting to bypass the authentication, we first have to test whether the login form is vulnerable to SQL injection. To do that, we will try to add one of the below payloads after our username and see if it causes any errors or changes how the page behaves:

Payload
URL Encoded

'

%27

"

%22

#

%23

;

%3B

)

%29

OR Injection

Let's say we have a login form and the query looks like this:

First we can use the OR injection. In SQL, AND is evaluated first unless parentheses are used to change the order of precedence. So if pass tom' OR '1' = '1 as the username, the query looks like this:

Well, a ' is added after the last 1. Here, first the AND is evaluated. And then the OR and in this case because OR is in the middle, the whole query always returns true if the username exists! Here's what it actually looks like if we think about the order of precendence:

So the password becomes irrelevant and we can log in as any user as long as the username is valid it will work.

Comment Injection

The second method is using comments. In SQL anything after -- is considered a comment and ignored by SQL. We can use it to ignore the password and only log in by using the username.

If we pass tom' -- as the username (spaces matter here), the query will look like:

We can use --, # as a comment in SQL.

Union Clause

Another type of SQL injection is injecting entire SQL queries executed along with the original query. This section will demonstrate this by using the MySQL Union clause to do SQL Union Injection.

The Union clause is used to combine results from multiple SELECT statements. This means that through a UNION injection, we will be able to SELECT and dump data from all across the DBMS, from multiple tables and databases.

Example

As we can see, UNION combined the output of both SELECT statements into one, so entries from the ports table and the ships table were combined into a single output with four rows. As we can see, some of the rows belong to the ports table while others belong to the ships table.

Note: The data types of the selected columns on all positions should be the same.

Even Column

A UNION statement can only operate on SELECT statements with an equal number of columns. For example, if we attempt to UNION two queries that have results with a different number of columns, we get the following error:

Un-even Column

We will find out that the original query will usually not have the same number of columns as the SQL query we want to execute, so we will have to work around that. For example, suppose we only had one column. In that case, we want to SELECT, we can put junk data for the remaining required columns so that the total number of columns we are UNIONing with remains the same as the original query.

For example, we can use any string as our junk data, and the query will return the string as its output for that column. If we UNION with the string "junk", the SELECT query would be SELECT "junk" from passwords, which will always return junk. We can also use numbers. For example, the query SELECT 1 from passwords will always return 1 as the output.

Note: When filling other columns with junk data, we must ensure that the data type matches the columns data type, otherwise the query will return an error. For the sake of simplicity, we will use numbers as our junk data, which will also become handy for tracking our payloads positions, as we will discuss later.

Tip: For advanced SQL injection, we may want to simply use 'NULL' to fill other columns, as 'NULL' fits all data types.

The products table has two columns in the above example, so we have to UNION with two columns. If we only wanted to get one column 'e.g. username', we have to do username, 2, such that we have the same number of columns:

Suppose the passwords table contains the following data:

username
password

Alice

secret1

Bob

secret2

Charlie

secret3

The query will return:

username
2

Alice

2

Bob

2

Charlie

2

If we had more columns in the table of the original query, we have to add more numbers to create the remaining required columns. For example, if the original query used SELECT on a table with four columns, our UNION injection would be:

This query would return:

As we can see, our wanted output of the 'UNION SELECT username from passwords' query is found at the first column of the second row, while the numbers filled the remaining columns.

Union Injection

If the site is vulnerable to SQL injection, we can use UNION clause to detect the number of colums. This following image shows a table fom a web application:

Most of the time the web app will exculde some of the columns, the index columns for example. We can detect the total number of colums in the table in two ways:

  • Using ORDER BY

  • Using UNION

Using ORDER BY

The ORDER BY function is used to sort the table result by a column. So if we try to sort by each columns incrementing the number until we hit an error, we can figure out the total number of columns.

Sorting by column 5 on the other hand gives us an error. So we know the total number of column in that table is 4.

Using UNION

The other method is to attempt a Union injection with a different number of columns until we successfully get the results back. The first method always returns the results until we hit an error, while this method always gives an error until we get a success. We can start by injecting a 3 column UNION query:

When we try till number 4 which is the correct number of columns we get:

This time we successfully get the results, meaning once again that the table has 4 columns. We can use either method to determine the number of columns. Once we know the number of columns, we know how to form our payload, and we can proceed to the next step.

Location Of Injection

While a query may return multiple columns, the web application may only display some of them. So, if we inject our query in a column that is not printed on the page, we will not get its output. This is why we need to determine which columns are printed to the page, to determine where to place our injection. In the previous example, while the injected query returned 1, 2, 3, and 4, we saw only 2, 3, and 4 displayed back to us on the page as the output data:

It is very common that not every column will be displayed back to the user. For example, the ID field is often used to link different tables together, but the user doesn't need to see it. This tells us that columns 2 and 3, and 4 are printed to place our injection in any of them. We cannot place our injection at the beginning, or its output will not be printed.

This is the benefit of using numbers as our junk data, as it makes it easy to track which columns are printed, so we know at which column to place our query.

We can also put other functions instead of numbers to get details about the database. For example @@version will print the version of the database.

Last updated