Post

SQLI Injection Tutorial.

SQLI Tutorial; Types, Authentication Bypass.

SQLI Injection Tutorial.

This is just a basic tutorial. I strongly recommend you visit my GitHub account if you want to find more information on this topic. Github-Hacking Web.

SQL Injection (SQLI).

A SQL injection occurs when an attacker attempts to pass input that changes the final SQL query sent by the web application to the database, enabling the user to perform other unintended SQL queries directly against the database.
There are many ways to accomplish this. To get a SQL injection to work, the attacker must first inject SQL code and then subvert the web application logic by changing the original query or executing a completely new one.
First, the attacker has to inject code outside the expected user input limits, so it does not get executed as simple user input. In the most basic case, this is done by injecting a single quote (‘) or a double quote (“) to escape the limits of user input and inject data directly into the SQL query.
Once an attacker can inject, they have to look for a way to execute a different SQL query. This can be done using SQL code to make up a working query that executes both the intended and the new SQL queries.
Finally, to retrieve our new query’s output, we have to interpret it or capture it on the web application’s front end.

SQL Code.

It’s essential to know SQL code to perform effective SQL injection exploitation. If you want to learn more about SQL or need a reference, you can find the following files in my Fundamentals GitHub repository, where I cover the following content:

SQL Injection Types:



Sublime's custom image


In-band SQLi.

The attacker uses the same channel of communication to launch their attacks and to gather their results. In-band SQLi’s simplicity and efficiency make it one of the most common types of SQLi attack. There are two sub-variations of this method:

  • Union-based SQLi: Is an in-band SQL injection technique that leverages the UNION SQL operator to combine the results of two or more SELECT statements into a single result which is then returned as part of the HTTP response.

  • Errorbased SQLi: The attacker performs actions that cause the database to produce error messages. The attacker can potentially use the data provided by these error messages to gather information about the structure of the database.

Inferential SQLi (Blind SQLi).

In an inferential SQLi attack, no data is actually transferred via the web application and the attacker would not be able to see the result of an attack in-band** (which is why such attacks are commonly referred to as “blind SQL Injection attacks”). Instead, *an attacker is able to reconstruct the database structure by sending payloads, observing the web application’s response and the resulting behavior of the database server.
Blind SQL injections can be classified as follows:

  • Blind-boolean-based SQLI: The attacker sends a SQL query to the database prompting the application to return a result. The result will vary depending on whether the query is true or false. Based on the result, the information within the HTTP response will modify or stay unchanged. The attacker can then work out if the message generated a true or false result.

  • Blind-time-based SQLI: We use SQL conditional statements that delay the page response if the conditional statement returns true using the Sleep() function. The attacker can see from the time the database takes to respond, whether a query is true or false.

Out-of-band SQLI.

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, and then attempt to retrieve it from there. This is known as Out-of-band SQL injection.
Out-of-band SQL Injection is not very common, mostly because it depends on features being enabled on the database server being used by the web application.



SQL Injection Authentication Bypass.

Index.

  1. SQLI Discovery.
  2. OR Injection.
  3. Authentication Bypass.

SQLi Discovery

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 |

In some cases, we may have to use the URL encoded version of the payload. An example of this is when we put our payload directly in the URL ‘i.e. HTTP GET request’.

So, let us start by injecting a single quote: 2 We see that a SQL error was thrown instead of the Login Failed message. The page threw an error because the resulting query was:

1
SELECT * FROM logins WHERE username=''' AND password = 'something';

The quote we entered resulted in an odd number of quotes, causing a syntax error.

OR Injection

We would need the query always to return true, regardless of the username and password entered, to bypass the authentication. To do this, we can abuse the OR operator in our SQL injection. The MySQL documentation for operation precedence states that the AND operator would be evaluated before the OR operator.

Operator Precedence

Operator Precedences are shown in the following list, from highest precedence to the lowest. Operators that are shown together on a line have the same precedence.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
INTERVAL
BINARY, COLLATE
!
- (unary minus), ~ (unary bit inversion)
^
*, /, DIV, %, MOD
-, +
<<, >>
&
|
= (comparison), <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN
BETWEEN, CASE, WHEN, THEN, ELSE
NOT
AND, &&
XOR
OR, ||
= (assignment), :=

Injection knowing the username.

An example of a condition that will always return true is '1'='1'. However, to keep the SQL query working and keep an even number of quotes, instead of using (‘1’=’1’), we will remove the last quote and use '1'='1, so the remaining single quote from the original query would be in its place.
So, if we inject the below condition and have an OR operator between it and the original condition, if we know the username it should always return true:

Sublime's custom image


The AND operator will be evaluated first, and it will return false. Then, the OR operator would be evalutated, and if either of the statements is true, it would return TRUE. Since 1=1 always returns true, this query will return true, and it will grant us access.

Sublime's custom image


Injection without knowing the username.

It’s posibble that we don’t know any username, that’s not a problem cause we can make a true query even if we don’t know any username or password.

To successfully log in once again, we will need an overall true query. This can be achieved by injecting an OR condition into the password field too, so it will always return true. Let us try something' or '1'='1 as the password.

1
SELECT * FROM logins WHERE username='' OR '1'='1' AND password = '' OR '1'='1';

The additional OR condition resulted in a true query overall, as the WHERE clause returns everything in the table, and the user present in the first row is logged in. In this case, as both conditions will return TRUE, we do not have to provide a test username and password and can directly start with the ' injection and log in with just ' or '1' = '1.

Sublime's custom image

Authentication Bypass

The payload we have been using is just one of many options, we can see more of them in PayloadsAllTheThings - Authentication Bypass.

Using comments.

The SQLI authentication we have been bypassing in the previous examples was an easy query, sometimes we can face more difficult querys that may break the sense of our injection, like:

1
SELECT * FROM logins WHERE (username='' AND id > 1) AND password = '3590cb8af0bbb9e78c343b52b93773c9';

We see that the query is preventing us to login as the admin because of the condicion id > 1. Additionally, we also see that the password was hashed before being used in the query, even if the password field is empty the server assigns a default hash for it (d41d8cd98f00b204e9800998ecf8427e). This will prevent us from injecting through the password field because the input is changed to a hash.

The way to bypass it is using SQL comments, using them we can ignore a certain part of the query. We can use -- - and #, in addition to an in-line comment /**/ (though this is not usually used in SQL injections).

If you are inputting your payload in the URL within a browser, a (#) symbol is usually considered as a tag, and will not be passed as part of the URL. In order to use (#) as a comment within a browser, we can use ‘%23’, which is an URL encoded (#) symbol.

Let us go back to our previous example and inject 'admin'-- - as our username. The final query will be:

1
SELECT * FROM logins WHERE (username='admin' -- -

As we can see the query is still wrong because we neet to close the brackets. But, if we close the query properly using ' OR '1' = '1') -- -, we will bypass the authentication process.

1
SELECT * FROM logins WHERE (username=' OR '1' = '1') -- -

6



SQLI Union Injection.

As allways the first step must be to find a vulnerable fild, we can do it by injecting some symbols like ' and seeing if we are getting an error.

Sublime's custom image

When we know that the field is vulnerable we need to know how many columns does the database has, we have two different methods to do it, we can use ORDER BY or UNION.

Getting the columns number.

The first step we must follow is knowing how many columns does the database have. We can do it using two different methods:

ORDER BY.

Make a series of requests supplying a numeric value in the parameter, starting with the number 1 and incrementing it with each subsequent request. If changing the number in the input affects the ordering of the results, the input is probably being inserted in to an ORDER BY clause. Increasing this number to 2 should then change the display order of data to order by the second column.

If the number supplied is therefore greater than the number of columns in the results set the query fails.

1
' ORDER BY 2 -- -

RESULT: The query doesn’t fail, meaning that the database has 2 or more columns

Sublime's custom image

1
' ORDER BY 4 -- -

RESULT: The query doesn’t fail, meaning that the database has 4 or more columns

Sublime's custom image

RESULT: The query fails, meaning that the database has less than 5 columns

1
' ORDER BY 5 -- -

Sublime's custom image

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 ORDER BY always returns the results until we hit an error, while this method always gives an error until we get a success.

1
' UNION SELECT 1 -- -

RESULT: We get an error because the database has’t got 1 column.

Sublime's custom image

1
' UNION SELECT 1, 2, 3, 4 -- -

RESULT: We don’t get an error because the database has EXACTLY 4 columns.

Sublime's custom image

1
' UNION SELECT 1, 2, 3, 4, 5 -- -

RESULT: We get an error because the database hasn’t got 5 columns.

Sublime's custom image

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.

To test that we can get actual data from the database ‘rather than just numbers,’ we can use the @@version SQL query as a test and place it in an outputed column and see the result:

1
' UNION SELECT 1, 2, @@version, 4 -- -

Sublime's custom image

We can see the user too.

1
' UNION SELECT 1, 2, user() , 4 -- -

Sublime's custom image



Database Enumeration. INFORMATION_SCHEMA database.

To pull data from tables using UNION SELECT and INFORMATION_SCHEMA database, we need to properly form our SELECT queries. To do so, we need the following information:

Listing Databases.

SCHEMATA

To start our enumeration, we should find what databases are available on the DBMS.

  1. The table SCHEMATA in the INFORMATION_SCHEMA database contains information about all databases on the server. It is used to obtain database names so we can then query them.
  2. The SCHEMA_NAME column contains all the database names currently present. Let us first test this on a local database to see how the query is used:

Sublime's custom image

Note: “mysql”, “sys”, “information_schema”, “performance_schema” databases are default MySQL databases and are present on any server, so we usually ignore them during DB enumeration.

Now, let’s do the same using a UNION SQL injection, with the following payload:

1
' UNION select 1,schema_name,3,4 from INFORMATION_SCHEMA.SCHEMATA-- -

The last command throws all the results before we can see the databases names, so we can just search for 1 “port” to obtain a smoller a output.

1
SG SIN' UNION select 1,schema_name,3,4 from INFORMATION_SCHEMA.SCHEMATA-- -

Sublime's custom image

We see two databases, “ilfreight” and “dev”, apart from the default ones.

Obtaining the database running in the application.

Let us find out which database the web application is running to retrieve ports data from. We can find the current database with the SELECT database() query. We can do this similarly to how we found the DBMS version in the previous section:

1
SG SIN' UNION SELECT 1, database(), 3, 4 -- -

Sublime's custom image

We see that the database name is “ilfreight”. However, the other database (dev) looks interesting. So, let us try to retrieve the tables from it.

Listing Tables.

Before we dump data from the “dev” database, we need to get a list of the tables to query them with a SELECT statement. To find all tables within a database, we can use the TABLES table in the INFORMATION_SCHEMA Database.

The TABLES table contains information about all tables throughout the database. This table contains multiple columns, but we are interested in the TABLE_SCHEMA and TABLE_NAME columns.
The TABLE_NAME column stores table names, while the TABLE_SCHEMA column points to the database each table belongs to. This can be done similarly to how we found the database names. For example, we can use the following payload to find the tables within the “dev” database:

1
sg' UNION select 1,TABLE_NAME,TABLE_SCHEMA,4 from INFORMATION_SCHEMA.TABLES where table_schema='dev'-- -

Note: how we replaced the numbers ‘2’ and ‘3’ with ‘TABLE_NAME’ and ‘TABLE_SCHEMA’, to get the output of both columns in the same query. Note: we added a (where table_schema=’dev’) condition to only return tables from the ‘dev’ database, otherwise we would get all tables in all databases, which can be many.

Sublime's custom image

We see four tables in the dev database, namely credentials, framework, pages, and posts. For example, the credentials table could contain sensitive information to look into it.

Listing Columns.

To dump the data of the credentials table, we first need to find the column names in the table, which can be found in the COLUMNS table in the INFORMATION_SCHEMA database. The COLUMNS table contains information about all columns present in all the databases. This helps us find the column names to query a table for. The COLUMN_NAME, TABLE_NAME, and TABLE_SCHEMA columns can be used to achieve this. As we did before, let us try this payload to find the column names in the credentials table:

1
sg' UNION select 1,COLUMN_NAME,TABLE_NAME,TABLE_SCHEMA from INFORMATION_SCHEMA.COLUMNS where table_name='credentials'-- -

Sublime's custom image

The table has two columns named username and password. We can use this information and dump data from the table.

Dumping Data.

Now that we have all the information, we can form our UNION query to dump data of the username and password columns from the credentials table in the dev database. We can place username and password in place of columns 2 and 3:

1
sg' UNION select 1, username, password, 4 from dev.credentials-- -

Remember: don’t forget to use the dot operator to refer to the ‘credentials’ in the ‘dev’ database, as we are running in the ‘ilfreight’ database, as previously discussed. We were able to get all the entries in the credentials table, which contains sensitive information such as password hashes and an API key.

Sublime's custom image

This is just a basic tutorial. I strongly recommend you visit my GitHub account if you want to find more information on this topic. Github-Hacking Web.

This post is licensed under CC BY 4.0 by the author.