Hacking SQL Server Stored Procedures
Hacking SQL Server Stored Procedures
Introduction
https://www.netspi.com/blog/technical/network-penetration-testing/hacking-sql-server-stored-procedures-part-3-sqli-and-user-impersonation/
If you read the first two blogs in this series then you already know that SQL
Server roles and privileges can be misconfigured in ways that allow users to
escalate their privileges to a sysadmin (database administrator). Even when
those roles and privileges are configured correctly, sometimes stored
procedures can still be a threat. In this blog I’ve covered how SQL injection
can be identified and exploited to escalate privileges in SQL Server stored
procedures when they are configured to execute with higher privileges using
the WITH EXECUTE AS clause or certificate signing. I’ve also provided a
lab setup guide for those of you who want to try this at home. To my
knowledge this work with SQL Server 2005 to 2014. This should be
interesting to penetration testers, application developers, and dev-ops. Feel
free to jump down to the attack section if you’re not big on labs. 🙂
2. Install SQL Server by following the wizard, but make sure to choose
mixed-mode authentication and run the service as LocalSystem for the sake
of the lab.
3. Log into the SQL Server with the SA account setup during installation
using the SQL Server Management Studio application.
4. Press the “New Query” button and use the TSQL below to create a least
privilege login.
-- Select database
USE master
GO
-- Create login
CREATE LOGIN MyUser WITH PASSWORD = 'MyPassword!';
GO
-- Set login’s default database
ALTER LOGIN [MyUser] with default_database = [master];
GO
5. Set the “master” database as trustworthy. Configuring a database as trusted
using the “is_trustworthy_on” flag allows certain objects within the database
to access external resources like network shares, mail functions, and objects
in other databases that are on the same SQL Server instance. This flag is set
to disabled by default (except MSDB), but some DBAs still choose to enable
it for a number of reasons. For the purpose of this lab, we will be enabling it
so we can execute operating system commands via xp_cmdshell from within
stored procedures setup using the WITH EXECUTE AS OWNER (sa in this
case). However, it should be noted the setting also affects CLR-based stored
procedures, UDFs, and Triggers. For more information on the
“is_trustworthy_on” flag you can take a look at
https://support.microsoft.com/kb/2183687.First, configure the “MASTER”
database as trustworthy.
ALTER DATABASE master SET TRUSTWORTHY ON
Then verify that the configuration was set with the following query.
SELECT a.name,b.is_trustworthy_on
FROM master..sysdatabases as a
INNER JOIN sys.databases as b
ON a.name=b.name;
Below is a screenshot of the expected result.
6. Use the TSQL below to enable xp_cmdshell. Enabling this now will
simplify the labs later, but it could be enabled by an attacker even if we
didn’t enable it.
1. Log into the SQL Server with the “sa” login and create the vulnerable
stored procedure using the TSQL below. The stored procedure will return a
list of database names that match the search string passed to it, as well as the
“tempdb” database.
After the script is run it exports all of the stored procedures into a csv file and
.sql files.
Creating a Vulnerable Stored
Procedure Signed with a Certificate
Another way to provide stored procedures with privileges to access objects
external to the current database is by signing them with a certificate. Some of
the advantages include allowing a least privilege login to execute the stored
procedure with elevated privileges WITHOUT having to:
1. If you are interested in taking a quick look at which logins were created
from a certificate then you can use the query below.
2. Now let’s try finding procedures signed with a certificate for the current
database that also have logins that were generated from them.
-- Get procedure location, name, source, cert name, and cert login, with dynamic SQL
SELECT spr.ROUTINE_CATALOG as DB_NAME,
spr.SPECIFIC_SCHEMA as SCHEMA_NAME,
spr.ROUTINE_NAME as SP_NAME,
spr.ROUTINE_DEFINITION as SP_CODE,
CASE cp.crypt_type
when 'SPVC' then cer.name
when 'CPVC' then Cer.name
when 'SPVA' then ak.name
when 'CPVA' then ak.name
END as CERT_NAME,
sp.name as CERT_LOGIN,
sp.sid as CERT_SID
FROM sys.crypt_properties cp
JOIN sys.objects o ON cp.major_id = o.object_id
LEFT JOIN sys.certificates cer ON cp.thumbprint = cer.thumbprint
LEFT JOIN sys.asymmetric_keys ak ON cp.thumbprint = ak.thumbprint
LEFT JOIN INFORMATION_SCHEMA.ROUTINES spr on spr.ROUTINE_NAME
= o.name
LEFT JOIN sys.server_principals sp on sp.sid = cer.sid
WHERE o.type_desc = 'SQL_STORED_PROCEDURE'AND
(ROUTINE_DEFINITION like '%sp_executesql%' OR
ROUTINE_DEFINITION like '%sp_sqlexec%' OR
ROUTINE_DEFINITION like '%exec @%' OR
ROUTINE_DEFINITION like '%exec (%' OR
ROUTINE_DEFINITION like '%exec(%' OR
ROUTINE_DEFINITION like '%execute @%' OR
ROUTINE_DEFINITION like '%execute (%' OR
ROUTINE_DEFINITION like '%execute(%' OR
ROUTINE_DEFINITION like '%''''''+%' OR
ROUTINE_DEFINITION like '%'''''' +%')
ORDER BY CERT_NAME,ROUTINE_NAME
The expected result is shown in the screenshot below.
Before we start
The goal of this lab is to escalate our privileges in SQL Server by exploiting
stored procedures that use the WITH EXECUTE AS OWNER clause and
certificate signatures. However, I also want show how the trustworthy flag
affects our results. So for now let’s turn it off. Make sure to disable it with
the “sa” login.
You should notice that the “sp_sqli” procedure returns a 0 even though it’s
running as the “sa” login. That’s because the “master” is not set as
trustworthy. Conversely, we can see that the signed procedure “sp_sqli2” can
execute with elevated privileges even though the trustworthy flag has not
been set in the “master” database.
You should be see some type of access denied error. Now let’s try that inside
the “sp_sqli” procedure.
Wrap Up
The issues covered in this blog/lab were intended to help pentesters,
developers, and dev-ops understand how a few common misconfigurations
and coding mistakes can lead to the compromise of an entire SQL Server
instance via stored procedure SQL injection. It’s worth noting that the same
techniques can be used via SQL injection through a web or thick application.
I just thought it would be easier to understand if it was exploited via a direct
database connection. Hopefully the information is useful. Have fun with it,
PS: For those of you looking to reset your lab when you’re all done use the
TSQL below:
USE MASTER
GO
drop proc sp_sqli
drop proc sp_sqli2
drop login sp_sqli2_login
drop login myuser
drop certificate sp_sqli2_cert
drop master key
References
https://msdn.microsoft.com/en-us/library/
ms345102%28SQL.100%29.aspx
https://msdn.microsoft.com/en-us/library/ms181700.aspx
https://msdn.microsoft.com/en-us/library/ms188354.aspx
https://msdn.microsoft.com/en-us/library/ms187861.aspx
https://support.microsoft.com/kb/2183687
https://www.sommarskog.se/grantperm.html#certcrossdb
https://www.netspi.com/blog/technical/network-penetration-testing/
hacking-sql-server-stored-procedures-part-3-sqli-and-user-
impersonation/