Last updated on October 3, 2020
In this new post I’m going to talk about one of the best known and most frequent techniques to find today: SQL injections. I will make a very simple introduction to initiate those who do not know how to perform these types of attacks, and then explain other types of SQL Injection more complicated.
The SQL injection technique allows you to discover information from a database, elevate privileges, impersonate users and perform a denial of service.
In order to correctly perform a SQL injection, it is necessary to find a fault in the verification of the input parameters. This happens when only the parameters are checked on the client side or when the checks performed are incorrect or incomplete.
The problem arises when the programmer constructs the SQL statements as a text string to which the parameters entered by the user are concatenated. In this way, when the string has just been built, it is not possible to distinguish which part of the string are commands and which part are parameters.
Example of SQL Injection attack
We only have a form with a username and password, as we would find on any other website. If we try to introduce any value, for example “carlos” and “pass“, it indicates us that the credentials are invalid:
When you enter the credentials, it is probably running a SQL query with the following structure:
SqlQuery = " SELECT IDUser from user_table WHERE user ='$User' AND password = '$Pwd'"
Where $User and $Pwd are two variables that are obtained from the form when a user enters their credentials. That way, with the credentials that I have introduced previously, a request has been made to the database, asking that the user ID be selected from the “user_table” table whose user field is “carlos” and the password field “pass“:
SqlQuery = " SELECT IDUser from user_table WHERE user ='carlos' AND password = 'pass'"
Since no user is found with this combination of name and password, the error message “Invalid Username/Password. Please try again.“ is returned.
Okay, now we’ll test if you perform any kind of check on your parameters. To do this, we will try to introduce a single quote ( ‘ ) at the end of the user name, putting user “carlos’ ” and pasword “pass“. Let’s see what happens:
The error message is different! Now it tells us that an error has occurred in the SQL syntax. This is because by putting an extra quotation mark, the SQL statement has now been misshapen:
SqlQuery = " SELECT IDUser from user_table WHERE user ='carlos'' AND password = 'pass'"
As soon as we get a message similar to this one, it is clear that this web page is vulnerable to SQL Injection. Now we have to check if we are able to exploit it. Let’s add in the user field a SQL command that will be confused with the parameter and modify the SQL statement. The command is as follows:
Thus, the SQL statement will become the next one:
SqlQuery = " SELECT IDUser from user_table WHERE user ='' or '1' = '1' -- a' AND password = 'pass'"
That way the statement says “Select the user_table IDUser where the user will be ‘ ‘ or 1 equals 1”. Since 1 is equal to 1, it doesn’t matter if the user is that or not, because the statement will be True in any case.
The hyphens ( – – ) are used in SQL to indicate comments, so when you put them at the end, everything that follows will be discarded (that way, the end of the previous query does not make us a badly formed query). It is important to put a space and any character behind the hyphens, because although a priori it would be the same, sometimes when passing it to the database does not recognize it as a comment if there are only two hyphens at the end of the injectable parameter.
Let’s see what the server says when you enter this:
It’s done! We have succeeded in entering the database. This has been a very simple example to introduce the SQL Injection databases.
Depending on what we put in the parameters, we can get different results from the database. In this way we have accessed with the authentication of the first user in the database.
If we wanted to access with a specific user, we should have written:
User = “any” Password = ” ‘ or user = ‘carlos
To make the SQL query look like this:
SqlQuery = " SELECT IDUser from user_table WHERE user ='cualquiera' AND password = '' or user = 'carlos'"
If what we want is to obtain information about a specific database table, for example, the “admin_table” table, then we must adapt the query to obtain this information, introducing in the user “ ‘; SELECT * from admin_table; — a “:
SqlQuery = " SELECT IDUser from user_table WHERE user =''; SELECT * from admin_table; -- a' AND password = ''"
Or we can also make this same query through a UNION.
And not only can we read from the database, but we can modify it (UPDATE), delete it (DELETE) or add false information (INSERT).
When trying to exploit a website to try SQL Injection, the first thing we need to find out is what type of database it uses. Depending on the type of database, the SQL syntax differs. The most used databases are Oracle, MSSQL, MySQL and PostgreSQL.
I recommend this link to pentestmonkey.net, where there is a Cheat Sheet with examples of different queries that can be done depending on what we want to do and the type of database that is. It has been very useful to me in many occasions.
Types of SQL Injection attacks
There are different types of attacks to exploit SQL Injection on a web. The type of attack to be carried out depends fundamentally on how the query is being carried out and what the page returns when trying to enter a SQLi:
- Staqued Queries. It consists of placing new queries at the end of the injectable query. The previous example that we have seen belongs to this type. It is the best method since it is the one that allows more things to be taken from the database, so it is the best option if it is available.
- Union query based. Recovers data by adding a query to the original using the UNION command. You need to be able to see the results of the query on the web page for it to work.
- Error based. Manipulates error messages to display database data. An example of this type of SQLi can be found in the Game of Thrones CTF that I published some time ago.
- Inline queries. This type of attack consists of embedding one query in another (SELECT(SELECT…)…).
- Boolean blind. It consists of making true/false queries and, according to the changes in the answers, discovering information about the database. For example, if we inject ‘ or ‘1’ = ‘1’ and it returns us an error message A, and we inject ‘ or ‘1’ = ‘2’ and it returns us another error message B that is different from the error message A, we can now inject ‘ or current_user = ‘carlos’. If it returns error message A, the user is carlos, if it returns error message B, it is not. By testing with injections like this, we can find out all the information contained in the database.
- Time based blind. The logic is the same as in the previous case, but instead of contrasting between different answers, check different response times. For example, to find out if the user is carlos, we would inject ‘ or (current_user = ‘carlos’ and WAITFOR DELAY ‘0:0:10’). If the user is carlos, the query will take 10 seconds longer than usual to run, if not, the response time will be the usual on that website.
As you can guess, performing these attacks manually can be very tedious. To automate the process, the SQLMap tool was created. This tool allows you to dump the entire database once you have found a pattern, testing hundreds of payloads with different statements.
However, many people settle for passing SQLMap with the default options, and if they don’t find an injectable command, they give up. SQLMap is a very powerful tool, but you need to configure it well to take full advantage of its potential. That’s why I’ll describe the main configuration parameters of SQLMap below.
- – – prefix: It will go before each query. For example, ” admin’ “.
- – – sufix: It will always go after every query. For example, ” – – a “.
- – – test-filter: filter the payloads to the guy you put in. For example, with ‘- -test-filter=ORDER BY’ only queries containing ‘ORDER BY’ will be executed..
- – -test-skip: take out the payloads of the guy you put in. For example, ‘- -test-skip=ORDER BY’ will execute all queries except those containing ‘ORDER BY’.
- – v3: verbosity
- – p <parámetro vulnerable>: indicate which parameter is vulnerable to the sqli.
- – – technique: technique to be used. It can be Stacked queries (S), Union query based (U), Error based (E), Inline queries (I), Boolean blind (B) and Time based blind (T). For example, with – – technique=SB we would be indicating that we want you to try to inject the different sentences associated with the Stacked queries method and the Boolean blind method.
- Risk: risk of error. The payloads with the least risk are those with risk 1, and those with risk 2.
- Level: number of requests per payload. Level 1 makes few requests while level 5 makes many.
- – – string: indicate which text string should appear in the response when the result is TRUE.
- – – no-string: you indicate the text string that should appear in the answer when the result is FALSE.
- – – regexp: you indicate a regular expression that must coincide with the answer when the result is TRUE.
- – – code: you indicate the HTTP code that the server should send when the result is TRUE.
- – – second-order: If SQLi affects a page other than the one that is vulnerable, you specify the page here and it will check the response on this page and not on the one in which you are injecting the payload.
In addition, there is a Burp Suite extension that integrates SQLMap. Its name is Burp C02, and you just have to fill in the different options and the extension generates the necessary command:
In this case, the command would be:
sqlmap -u 'https://hackinglethani.com/es/ctf-juego-de-tronos/' --level=5 --risk=3 --string='user or password wrong' --technique=QTBS --cookie='ACCESOSESSID=a123e4fb567ba8c9'
Soon I will upload a blog explaining how I got all the information from a database with one of the most difficult SQL Injection I have found so far.