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.
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:
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.
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,
RQ_SEND_RESPONSE | RQ_BEGIN_REQUEST, 0);
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:
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();
return RQ_NOTIFICATION_CONTINUE;
}
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 iis_controller.py script will perform all of this, providing a command-line interface to interact with the backdoor.
Four arguments are implemented on the script:
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:
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:
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 192.168.1.74 server with the password SIMPLEPASS and the whoami command is executed successfully.
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:
This blog post was written by Rio Sherri.