26334 total geeks with 3498 solutions
Recent challengers:
 Welcome, you are an anonymous user! [register] [login] Get a yourname@osix.net email address 

Articles

GEEK

User's box
Username:
Password:

Forgot password?
New account

Shoutbox
MaxMouse
It's Friday... That's good enough for me!
CodeX
non stop lolz here but thats soon to end thanks to uni, surely the rest of the world is going good?
stabat
how things are going guys? Here... boring...
CodeX
I must be going wrong on the password lengths then, as long as it was done on ECB
MaxMouse
lol... the key is in hex (MD5: of the string "doit" without the "'s) and is in lower case. Maybe i should have submitted this as a challenge!

Donate
Donate and help us fund new challenges
Donate!
Due Date: Jun 30
June Goal: $40.00
Gross: $0.00
Net Balance: $0.00
Left to go: $40.00
Contributors


News Feeds
The Register
Google joins
Amazon, HP,
Rackspace in easing
HDD data importing
Adobe CEO admits
needs to "tweak"
cloud-only policy
John McAfee
releases NSFW video
on how to uninstall
security code
Speaking in Tech:
We find someone who
hasn"t heard of
Prof Brian Cox
Dish abandons
Sprint sprint, now
in mad dash for
Clearwire
You"re still hired:
Viglen bosses get
to keep jobs for
another year
Nutanix trims down
and fattens up
server-storage
halfbloods
Stay away from the
light, Kodak! Look,
here"s $406m to
keep you alive
Oracle: We WON grey
market software and
Solaris support
case
Dynamo-spawn Riak
spreads to other
clouds
Slashdot
Millions At Risk
From Critical
Vulnerabilities
From WordPress
Plugins
Ubuntu Phone
Carrier Advisory
Group Announced
Cumulus Releases
GNU/Linux For
Datacenter Routers
Relicensing of
MySQL Man Pages
Just a Bug
BT Chief To Become
British Government
Minister
One Year Since
Assange Took Refuge
in Ecuadorian
Embassy
Subversion 1.8
Released But Will
You Still Use Git?
Google Patents
Image-Capturing
Walking Sticks
PDP-11 Still
Working In Nuclear
Plants - For 37
More Years
NSA"s Role In
Terror Cases
Concealed From
Defense Lawyers
Article viewer

SQL Injection



Written by:TroPe
Published by:thinkt4nk
Published on:2004-12-13 16:34:38
Topic:Security
Search OSI about Security.More articles by TroPe.
 viewed 15026 times send this article printer friendly

Digg this!
    Rate this article :
Your code (and mine of course) is vulnerable to SQL injection attacks wherever it uses input parameters to construct SQL statements. I can't stress enough how risky this is. As with XSS bugs (see my article on XSS), SQL injection attacks are caused by placing too much trust in user input and not validating and parsing their input. This article will show you many examples of SQL Injection, including a one line command to shut down almost any MS SQL server that does not parse user input!




I learned alot of this by mistake. I was working for copperfield.com, a large chimney supply company, and for some reason there was this guy out there (a competitor?) who continually hacked my database. It took me forever to figure out how he was doing it. And I am sure you can guess what he was doing. He was using SQL Injections to manipulate my database. The Bastard.

So I read up on this subject, bought some security books, and eventually locked him out. There are a ton of sites out there on this subject, but here it is in a nutshell.

With SQL Injection, an attacker is able to change or add queries that are sent to a database by playing with the input to the web application (like through a form for example). The attack works when a program builds queries based on strings from the client, and passes them to the database server without handling characters that have special meaning to the server.

I'll walk through a few examples to illustrate the problem. The whole point of this article is simple, do not be lazy when it comes to securing your code. If you understand that fully, and plan to (or already are) writing secure code, no need to read on.



Say that we have an SQL-based user database. To make things simple, we say that the user registers his real name only, and that the Java code that picks up his real name from the registration form and stores it in the database looks like this:

Java

   name = request.getParameter("TheName");
   query = "INSERT INTO Usr (RealName) VALUES ('" + name + "')";



or in ASP it would look almost identical...


   name = request.form("TheName");
   query = "INSERT INTO Usr (RealName) VALUES ('" + name + "')";



First let me just say now, please don't code like this. That being said, let's say we registered with the name "Frosty T. Snowman", which would give the database query:


   INSERT INTO Usr (RealName) VALUES ('Frosty T. Snowman')



No problem. But then Bugsy O'Gangster comes along. When he tries to register, the database receives the following query:


   INSERT INTO Usr (RealName) VALUES ('Bugsy O'Gangster')



The query definetly gives an error message, and our friend Bugsy is unable to register. Why? Because the single quote that is part of his name interferes with the single quotes used to mark the start and end of strings in SQL. The single quote is a metacharacter inside an SQL string constant. If we do not handle such metacharacters somehow, our application will not only produce unfortunate error messages, but it will also be vulnerable to attacks. So let's begin the attack.

First we pretend that we're making a web application that requires users to log-in through a form. Not knowing much about security, we just follow the examples in many of the books out there. Here's a snippet from our vulnerable Java program that I really DID find on a net tutorial:


   userName = request.getParameter("SomeUser");
   password = request.getParameter("SomePass");
   query = "SELECT * FROM Usr "
             + "WHERE UserName='" + userName + "' "
             + "AND Password='" + password + "'";



The program retrieves a user name and a password from the input parameters, builds it's query, and passes the query to a database ( that's not shown in the code). o/ Bag Guy Music Start o/

Enter an attacker (us). We know, or can guess, that one of our users is named "MickeyMouse." So we enter the following in the user name fields, and leaves the password empty:


   MickeyMouse' --



As our program just inserts the input unmodified in the query, what eventually is sent to the database looks like this:


   SELECT * FROM Usr WHERE UserName='MickeyMouse' --' AND Password=''



The two hyphens (- -) make up an SQL commennt introducer. In the example above, it effectively inactivates the test for a matching password! If a user named "MickeyMouse" exists in the database, the attacker just logged in as that poor Mickey guy without giving any passwords. As I mentioned in my article about XSS, if you Google a bit you will be shocked at the number of sites you can 'log-in-as-anyone-you-want'. Try a search query on something like, "Enter your username" or "Please login".

So, how do we avoid the problem? The most obvious answer most of you are probably thinking is to filter out that damned double hyphen. But, the hyphens are not part of the problem at all.

Say that we're using MS (Microsoft) Access as the database of our application. Access does not understand the SQL comment introducer. Here's the ASP/VBScript equivalent of the above Java code:


   userName = Request.Form("user")
   password = Request.Form("pass")
   query = "SELECT * FROM Usr "
         & "WHERE UserName='" & userName & "' "_
         & "AND Password='" & password & "'"



We, as the attacker know that regular comments will get us nowhere, so we turn to playing with boolean operator precedence rules. Here's what we enter for the user name this time, still leaving the password empty:


   MickeyMouse' OR 'a'='b



You do see where this is going, don't you? Our application puts it all together, and passes this query to MS Access:


   SELECT * FROM Usr
      WHERE UserName='MickeyMouse' OR 'a'='b'
         AND Password=''



And once again we gain access to Mickey's stuff (us bastards!), this time without using the SQL comment introducer. I will do a little explaining for the newbies to SQL. The boolean operators AND and OR are influenced by certain priority rules. The rules state that AND takes precedence over OR, meaning that the AND part will be executed before the OR part. The AND part is


   'a'='b' AND Password=''



and it returns FALSE, as 'a' doesn't equal 'b', and there probably aren't any empty passwords either. The original query is thus reduced to:


   SELECT * FROM Usr WHERE UserName='MickeyMouse' OR FALSE



As OR requires just one of the operands to be true, it matches the entry with a user name of "MickeyMouse." And that's it, we just commented out the password test using boollean precedence rules.

So you see ,the hyphens were not the problem at all. Not one bit. The security hole happened because the attacker was able to enter a single quote, and have that quote prematurely terminate the SQL string constant. It's all about parsing. When the SQL parser of the database has just read:


   SELECT * FROM Usr WHERE UserName='



that is, all characters up to and including the first single quote, it switches to parsing a string constant. It's in a string context. The quote allows us (the attacker) to switch context, and that is where the problems are.

Based on the code above, it's easy to draw the conclusion that all quotes are bad. Some web programming platforms, like PHP, may automatically escape all incoming quotes for you. The conclusion isn't entirely correct, and escaping all quotes from the client-side is the wrong way to attack the problem. Quotes are bad only when they make a parser switch context, like in our attack above.

In the following example, most characters are bad. And the attack we'll examine will work even if all quote characters are removed from or escaped in the input.

Okay now let's assume we have an ASP program that, among doing many other things, it looks up information on a customer from a given a customer ID. This is done all over the damn net. The customer ID enters the application from the client-side,(in a URL parameter), and gets stored in the custId variable. The program prepares a database query by including customerId in a query string:


   customerId = Request.QueryString("id")
   query = "SELECT * FROM Customer WHERE CustId=" & customerId



There are no quotes in this query, so customerId is supposed to be numeric. But thanks to VBScript being typeless (and many many other scripting languages), an attacker may include more than just decimal digits in the custId variable by changing the id parameter to something like this (which is the most common SQL attack in my opinion ):


   1; DELETE FROM Customer



Our program concatenates the bad guy's input, and passes the following query to the database:


SELECT * FROM Customer WHERE CustId=1; DELETE FROM Customer



The first thing that happens is obvious, it returns a query based upon CustomerID equalling 1. Then a DELETE statement that doesn't look good at all: if the database user used by the application has proper access, every single row will be deleted from the database! I'll say it again, that Bastard!

Of course, the second query could have been anything, not only DELETE. The attacker could, for instance, have used INSERT or UPDATE to put false information into the database. We could do anything we want here. Almost any valid SQL will work.

With MS SQL Server you can even leave the semicolon. Up to you.

What was the darn problem this time? We had no troublesome quote characters. We'll have to turn to parsing and contexts again. When the SQL parser of the database has just read:


   SELECT * FROM Customer WHERE CustId=



It turns to a numeric context: it parses a number. Escaping of quotes will not be enough, as any non-numeric character will make the database server leave the numeric context, and start looking for SQL keywords again. The correct approach is to make sure the data we insert in the query is actually a number, and nothing else. But I'll delay the correct approach even further as I am havinf fun playing the attacker, and continue with examples from applications that don't do it correctly.


So far we've seen how to change queries, and how to manipulate info inside the database. But how about extracting information to gain access to something we're not supposed to see, huh? Most people suggest adding a SELECT statement after a new semicolon. But in most cases that approach won't work, as the new SELECT typically will be returned in a second record set. The application is most likely written to accept only one set.

However, SQL has another construct that aids the attacker: UNION SELECT. With UNION SELECT, two SELECT statements are treated as one. And best of all, the first SELECT dictates the names of the columns, so the application will not notice that another SELECT is interfering.

Example: We have a PHP program that displays news items. Each news item belongs to one of several categories, and it is possible to instruct the program to pick news from a single category only. Here's an excerpt from the program:


   $cat = $_GET["category"];
   $query = "SELECT Id,Title,Abstract FROM News "
             "WHERE Category=" . $cat;



The URL parameter category, which is supposed to contain an integer, dictates what category to show. Along comes us, the attacker, and we happen to know that this application also has a Usr table, with user names and passwords of registered users. To get to that tempting information, we make sure the category parameter is:


   1 UNION SELECT 1,UsrName,Passwd FROM Usr



As always, our application passes incoming data straight to the database, so the poor poor database server eventually executes:


   SELECT Id,Title,Abstract FROM News
   WHERE Category=1 UNION SELECT 1,UsrName,Passwd FROM Usr



The resulting page will contain news titles and news abstracts, mixed with user names and passwords from the Usr table.

But why did the attacker put that number one inside the query? He did so because UNION SELECT puts a couple of constraints on the second SELECT. First, it must contain exactly the same number of columns as the initial SELECT. And second, the data type of each column in the second SELECT must match the type of each column in the first. The attacker just wants the user name and password, which makes up two columns. So he'll have to add a fictitious third column. He knows that user name and password are character columns, and that title and abstract are also characters. Those two pairs match. As id is numeric, he inserts his randomly chosen number as the first column. By that insertion, both UNION SELECT requirements are met.

There's another exploit that is viscious, and I mean vicious! Just by visiting a URL of a server you can actually shut the SQL server down. Of course I would not recommend playing around with this, but it's your life...do what you want:


    http://example/default.asp?id=99;SHUTDOWN



This will, and please trust me on this one, this will shut down a Microsoft SQL Server that does not parse their QueryStrings.

Well, I'd better get back to work (my current client is probably wondering where the hell I am this morning) so I'll end this here. You now know a little about some basic attacks. And the answer to preventing these are simple: write secure code and parse your input.

Take Care,
Trope

Ps. Just kidding about the bail money, so be good think12.





Did you like this article? There are hundreds more.

Comments:
think12
2004-12-13 19:16:58
nice!
bb
2004-12-14 09:30:28
you didnt mention anything about using database stored procedures to handle parameterised sql queries.

in my experience, all software we build use stored procedures for data access. this is some benefits in terms of them being pre-compiled along with their execution plans, but more importantly that the parameters into the sql are explicitly declared.

using this method rather than concatenating string together to build sql statements will protect you from most sqlinjection issues.

not sure if mysql supports sp's yet, but im sure postgress does.
TroPe
2004-12-14 12:46:20
Beware that variables inside a stored procedure aren't always immune to SQL Injection either. If the stored procedure contains constructs that add a second level of parsing, such as EXEC on a string in MS SQL Server, you will have to handle metacharacters again. This time inside the stored procedure.
Chilli
2004-12-14 13:53:40
I don't know or care for MSSQL but in MySQL and others you can specify permissions on operations and tables. There is no way the username used to retrieve data values should be able to SHUTDOWN a system. Always create new users with limited roles and capabilities to reduce the impact of any malicious code.
TroPe
2004-12-14 14:01:32
"Always create new users with limited roles and capabilities to reduce the impact of any malicious code."

Applause from me!
bb
2004-12-14 15:53:22
aaah where possible i do not execute concatenated strings, whether they have been concatted in the app code, or sql layer. the one pain in the ass where we usually do have to build concat strings in sps, is when executing IN statements, as you cant pass in paramaters as a comma separated list of integers to an IN statement.
Anonymous
2008-07-16 16:40:06
Thanks for all you notes and remind
Anonymously add a comment: (or register here)
(registration is really fast and we send you no spam)
BB Code is enabled.
Captcha Number:


Blogs: (People who have posted blogs on this subject..)
MaxMouse
PSP on Mon 7th Sep 10am
I was going to write an article on PSP NIDS, but when i started doing it, it felt as if it dropped a little short of what i wanted it to be, and wasn't particularly long (or interesting to people not associated with the PSP Scene). I did write about it
halsten
Backdoor.W32.Small.PF Analysis on Mon 7th Jan 3am
A long time has passed since my first analysis paper, but here is another one. This time it’s short and small. The package contain all the necessary files to get you started on understanding the malware. I hope it’s better than my last paper. You can chec
halsten
Malware Analysis on Sun 5th Aug 3am
Hello all, in here (http://iamhalsten.thecoderblogs.com/200 7/07/23/malware-analysis/) you can find my latest analysis paper for a malware I've analyzed. The paper is extensively and comprehensively documented. Have fun reading it. -- halsten http://i
sefo
AVG's Restore File As... on Wed 30th Aug 1pm
It is possible to restore infected files from the vault to the 'computer' using the option 'Restore File As'. So I restored as 'blah.xyz' the wmf file AVG found the other day and I put it on the desktop. My surprise was to discover that AVG restored

Test Yourself: (why not try testing your skill on this subject? Clicking the link will start the test.)
Cryptography by TroPe

This test will cover Symmetric cryptography, public keys, key management, and some questions on cryptanalysis. If you know a little something about Crypt stuff, give this test a shot!


     
Your Ad Here
 
Copyright Open Source Institute, 2006