IIS Raid – Backdooring IIS Using Native Modules

IIS Raid – Backdooring IIS Using Native Modules


Back in 2018, PaloAlto Unit42 publicly documented RGDoor, an IIS backdoor used by the APT34. The article highlighted some details which sparked my interest and inspired me to write IIS-Raid, an IIS backdoor module that allows red-team operators to keep a stealthy persistence on IIS web-servers.

In this blogpost, we will discuss some of the key components of this tool, how it was built and demonstrate its features.

Native Modules and IIS-Raid

A native module is a Win32 DLL that can be used to extend IIS in order to provide the desired functionality of your applications. In essence, IIS Raid is a native IIS module that abuses the extensibility of IIS to backdoor the web server and carry out custom actions defined by an attacker.

IIS allows you to extend the server using modules which can be developed in two ways:

  • Managed Modules – Using the .NET extensibility API-s
  • Native Modules – Using the IIS Native server extensibility API-s

There are advantages and disadvantages for both of the methods, but it was determined that building a native module would provide better functionality as the API is more rich than the .NET one, even though the development time would be longer.

Before actually starting to write the tool, research was performed to identify previous work in this space. The first write up we identified, described how to backdoor IIS but the information was somewhat limited and no POC was public.

Another project was also noted which had Proof of Concept code and was built on C#. However, no publicly available native modules were found.

Building IIS-Raid

The core of any IIS Module, is the creation of a DLL that exports the RegisterModule function. This function responsible for registering the module on the server, creating the http module factory and registering all the events that will be handled by the module.

In the case of IIS-Raid, the RegisterModule function looks like this :

CMyHttpModuleFactory * pFactory = NULL;

HRESULT __stdcall RegisterModule(DWORD dwServerVersion, IHttpModuleRegistrationInfo * pModuleInfo, IHttpServer * pHttpServer)

    HRESULT hr = S_OK;

    // Factory class is responsible for manufacturing instance of our module for each request.
    pFactory = new CMyHttpModuleFactory();

    // Register for the server events.
    hr = pModuleInfo->SetRequestNotifications(pFactory, 

    return hr;

First, we implement our module factory, which is responsible for manufacturing the instances of our module for each request. After creating an instance of the MyHttpModuleFactory object, the SetRequestNotification method is called in order to instruct IIS to handle specific events with our module.

In the example above, we register only two events:

  • RQ_SEND_RESPONSE – Gives our module the ability to process the response.
  • RQ_BEGIN_REQUEST – Gives our module the ability to process the request.

After successfully registering the events, the module factory needs to implement the functions to handle them. For example, when a request level module is registered for the RQ_BEGIN_REQUEST event, IIS will call the module’s OnBeginRequest method when a request enters the integrated request processing pipeline.

A simple example which initialises the lpMethod variable with the request method can be found below:

REQUEST_NOTIFICATION_STATUS CMyHttpModule::OnBeginRequest(IN IHttpContext* pHttpContext, IN OUT IHttpEventProvider* pProvider)
    IHttpRequest* pHttpRequest = pHttpContext->GetRequest();
    LPCSTR lpMethod = pHttpRequest->GetHttpMethod();

The examples above are simplified and don’t show the entire implementation of IIS-RAID but give enough information to understand its internals.

More information for the implementation can be found on the source code or from the following URLs :

When installed, IIS-Raid will process every request and method, check if the X-Password header exists and compare it against the hardcoded password. In case the value specified by the header doesn’t match the password, the request will continue normally, without giving any indications of the backdoor.

If the header value matches the password, it will search for the communication header and extract its content. Additionally, it will base64 decode it and compare it against the predefined commands and process the instructions if any.

The script will perform all of this, providing a command-line interface to interact with the backdoor.

Four arguments are implemented on the script:

  • –url : The URL that will be used to communicate with the backdoor. [Required]
  • –password – The pre-shared password on the backdoor [Required]
  • –header – The header to use for communication in case it was changed from the default one.
  • –method – Change the method to either GET or POST.

It should be noted that whatever URL is passed to the script, the backdoor will operate successfully. This is useful to evade security teams from detecting the backdoor traffic from the legitimate one based on webserver logs.

Some of the features that are currently implemented in this version are:

  • Interactive Command Execution – Allows the execution of commands and retrieve the output.
  • Shellcode Injection – Extend functionality by injecting custom shellcode.
  • Web Password Extractor – Extract passwords from Web Forms in clear-text.

Customisation and Deployment

Before using and compiling the module, you need to change some of the options. To authenticate to the backdoor, the controller uses a pre-shared password with the module. As this is the only mechanism preventing someone else from accessing the backdoor, the default password must be changed.

Apart from the password, other backdoor options can be modified on the Functions.h file:

The COM_HEADER definition is the header name used to perform the communication between the backdoor and the controller.

The PASS_FILE definition is the file path where the extracted credentials from the web forms will be saved.

The PASSWORD definition is the password that will be used to authenticate to the backdoor.

Having the module configured and compiled correctly, it’s time to deploy it on your targets.

There are several methods to install native modules:

  • Manually editing the IIS configuration store
  • Using IIS Manager
  • Using the AppCmd.exe command line tool

During operations, we try to avoid the use of Graphical User Interface (GUI) tools on target systems. For this reason, the AppCmd method can be used to register the module and successfully backdoor the webserver.

After compiling and uploading the DLL into the target system, you can execute the following command:

C:\Windows\system32\inetsrv\APPCMD.EXE install module /name:Module Name /image:"%windir%\System32\inetsrv\IIS-Backdoor.dll" /add:true

As shown by the image above, the module was loaded successfully.

In the example below, a connection is created to the server with the password SIMPLEPASS and the whoami command is executed successfully.

Demo and Links

The source code for the tool has been published on github.

To see IIS-Raid in action you can watch the video demonstration :


One of the objectives of releasing this tool was to increase awareness and allow companies to detect this methodology. The released source code doesn’t include any encryption by default as this would likely decrease the probability of detection.

Below you can find some methods to detect the communication traffic or the module deployment:

  • Monitor command line logging telemetry for execution of appcmd.exe as previously noted. The noise that will be generated by legitimate installations will likely be low making it a good indicator for detection.
  • If you can intercept the traffic to your web servers, check if any base64 encoded header data starts with any of the following strings:
    • PIN|G
    • CMD|
    • INJ|
  • Search for the existence of X-Password and X-Chrome-Variations headers


This blog post was written by Rio Sherri.

written by

MDSec Research

Ready to engage
with MDSec?

Copyright 2021 MDSec