Getting Code Execution
With sysadmin role membership, it’s possible to obtain code execution
on the Windows server hosting the SQL database.
The most well-known way of doing this is by using the xp_cmdshell
stored procedure.
We are going to cover this technique, keeping in mind that because it is well known,
we may find that xp_cmdshell is blocked or monitored.
For this reason, we’ll also cover an alternative technique,
which uses the sp_OACreate stored procedure.
For now, let’s begin with xp_cmdshell.
The xp_cmdshell stored procedure spawns a Windows command shell
and passes a command in a string that is then executed.
The procedure then returns the output of the command.
Since arbitrary command execution is dangerous,
xp_cmdshell has been disabled by default
since Microsoft SQL 2005.
Luckily, sysadmin role membership allows us to enable xp_cmdshell
using advanced options and the sp_configure stored procedure.
To do this, we’ll need to begin with the impersonation of the sa login.
Next, we’ll use the sp_configure stored procedure to activate the advanced options
and then enable xp_cmdshell.
To activate the advanced options as well as xp_cmdshell,
we must remember to update the currently configured values
with the RECONFIGURE statement.
After enabling xp_cmdshell, we’ll execute the whoami command
and display the results.
Once we launch our updated application,
we receive the results of the whoami command.
Excellent,
we have proof of code execution
in the context of the SQL service account!
xp_cmdshell has been used by penetration testers
and malicious actors for more than 15 years.
Because it’s not a well kept secret,
many organizations now monitor its usage
or simply remove it.
The second technique we'll cover in this section
uses the sp_OACreate and sp_OAMethod stored procedures,
to create and execute a new stored procedure
based on OLE.
With this technique, we can instantiate the Windows Script Host,
and use the run method
just like we have done in previous versions of our client side code execution.
To explain this technique in detail, we begin with sp_OACreate,
which has the following prototype.
The procedure takes two arguments.
The first is the OLE object that we want to instantiate
(wscript.shell in our case),
followed by the local variable where we want to store it.
The local variable is created with the DECLARE statement,
which accepts its name and type.
In our case, we'll call the local variable @myshell.
We use two SQL statements to create the local variable
and instantiate the OLE object.
Because @myshell is a local variable,
we must stack the SQL queries
to ensure it exists when sp_oacreate is invoked.
Next, we execute the newly-created stored procedure with the sp_OAMethod procedure,
which has this prototype.
sp_OAMethod accepts the name of the procedure to execute,
the method of the OLE object,
an optional output variable,
and any parameters for the invoked method.
In our case, we'll send the command we want to execute as a parameter.
It's not possible to obtain the results from the executed command
because of the local scope of the @myshell variable.
Before we can execute our new OLE-based procedure,
we must ensure that the “OLE Automation Procedures” setting is enabled.
Although it is disabled by default, we can change this setting
using the sp_configure procedure before creating the stored procedure
since we have the sysadmin role.
With the C# console application updated,
we execute it,
and then launch a command prompt as the admin domain user.
Then we can verify that file.txt was created on dc01.
The contents of the file prove that our technique worked.
We obtained code execution on the host operating system of the SQL server!
In this section, we investigated multiple techniques
for getting code execution in the SQL server
by using stored procedures that are available by default in MS SQL.
In the next section, we're going to expand on this
by introducing a custom assembly.