IIS modules: The evolution of web shells and how to detect them 

Web exploitation and web shells are some of the most common entry points in the current threat landscape. Web servers provide an external avenue directly into your corporate network, which often results in web servers being an initial intrusion vector or mechanism of persistence. Monitoring for exploitation and web shells should be a high priority for all networks, and while these detection techniques are targeted towards malicious IIS modules, a lot of these techniques will also provide general web shell detections.

IIS modules and the creation of persistent backdoors by malicious IIS modules has recently been addressed in the Microsoft Security blog titled Malicious IIS modules creating persistent backdoors. In this blog by Microsoft Detection and Response Team (DART), we aim to provide further guidance on detecting malicious IIS modules and other capabilities (such as logging) that you can use during your own investigations. While we will cover Microsoft Defender for Endpoint detections in this blog, these detection methods should be tool agnostic. The queries listed are not definitive detection queries, but rather a base query that you can build on to suit your specific environment.

A history of malicious IIS modules

The concept of malicious IIS has been around since at least 2013. Historical malware analysis shows how crimeware groups used IIS modules to intercept client logons and payment details by using the BeginRequest triggers to read user-provided parameters before the webserver processes them.

One of the first examples of sophisticated IIS modules was discovered in late 2021. The vendor’s ICEAPPLE report details an IIS module that was used by an actor to reflectively load further .NET modules, which by extension, loads further .NET capability. This allowed the actor to have minimal malicious indicators in the base IIS module, then load further capabilities as required.

A more recent example was provided in a recent Microsoft blog, where the actor instead opted for child process execution rather than loading the capability directly into w3wp.exe. This blog delves further into the capability to discuss the different capabilities that malicious IIS modules have access to.

Malicious IIS modules techniques

Event handlers

A core part of IIS module functionality is event handling. Event triggers provide opportunities for code to be called when specific actions happen. IIS modules have access to 27 event triggers by default, including:

  • Begin Request: When a request is received by the webserver.
  • End Request: When a response is about to be sent to the client.
  • Error: When an error happens.
  • Log Request: When a request is about to be logged.

Event handlers, which run when their associated trigger is fired, can allow an actor to essentially setup a proxy on the IIS server. By setting up an event handler on the BeginRequest, EndRequest, and Error event triggers, the actor can intercept all requests before the web service can process them and before the response is sent to the client.

A diagram showing how a malicious IIS module sits between a web server and the client. The malicious IIS module is shown intercepting requests between the web server and client on the BeginRequest, EndRequest, and Error event triggers.
Figure 1. Diagram showing how the malicious IIS module sits between the web server and the client

Event handlers are given full read and write access to the requests, which allows malicious IIS modules to hide web shell communications within any aspect on the web request, turning every page that does and does not exist into a web shell. This can include hiding web shell communications in the parameters, body, headers, or HTTP methods.

These aspects of malicious IIS modules make them very hard to detect in standard IIS logs. You cannot rely on usual web shell detection strategies, such as high frequency page requests or URI patterns. Malicious IIS modules instead require new detection techniques and use of advanced IIS logging.

Request and response tampering

An additional difficulty with malicious IIS modules is that they can tamper with any aspect of the request and/or response. This could include removing web shell commands from parameters or headers and preventing web shell commands from being logged.

IIS Modules can also intercept responses before they are sent, which presents the opportunity for an actor to serve malicious payloads into any response from the website, potentially infecting viewers of the website.

Process creation

‘W3wp.exe’, also known as IIS worker processes, is utilized by web applications that run within IIS. Process creation is the most common indication of a web shell on IIS servers. Monitoring for the creation of common shell tooling (cmd, PowerShell, rundll32, mshta) with the parent process w3wp.exe can help detect low-sophistication IIS modules.

This should not be considered a strong detection for IIS modules. With full integration with C# and the .NET framework, a large amount of functionality can be integrated to execute directly within the IIS process without relying on creating child processes.

.NET assembly loading

A common execution path for actors is to load .NET modules directly into memory through reflectively loading assemblies. This can allow common tools, such as SharpHound or the Potato PrivEsc family, to be loaded without being written to disk. This is also seen as a stealthier alternative to process creation because it’s within the context of w3wp.exe rather than within a child process.

A screenshot showing the details of the event associated with w2wp.exe creating a SweetPotato named pipe. It includes an event description, an event timestamp, the user, the initiating process, and the pipe name.
Figure 2. SweetPotato named pipes being created from within w3wp.exe

As mentioned in the vendor paper earlier, assemblies can be provided arbitrarily to deliver additional functionality. This may be through providing the assembly through the web request or downloading the assembly from an actor-controlled C2. The figure below shows: 

  1. SharpHound being downloaded from an external C2 and loaded through the Reflection Assembly Load method.
  2. Two methods being invoked within the binary and the output directory being set to ProgramData.
A screenshot of a snippet of code showing an IIS module remotely downloading SharpHound and reflectively invoking it.
Figure 3. Example of an IIS module remotely downloading SharpHound and reflectively invoking it

With access to .NET, malicious actors can add additional layers of evasion to prevent detection of their IIS modules, such as encoding or encryption. In the figure below, we can see:

  1. A base64 encoded blob and the size of the decoded assembly.
  2. A new memory allocation is made, where the assembly is decoded and deflated into the new allocation.
  3. The assembly is loaded and invoked, executing the command whoami.
A screenshot of a snippet of code showing SweetPotato being reflectively loaded and invoked.
Figure 4. Example of SweetPotato being reflectively loaded and invoked

Logging and monitoring

Advanced IIS Logs

IIS logs are a great place to start hunting for web shells, but advanced IIS logging is recommended because IIS modules can remove malicious traffic from the standard IIS logs. The IIS Service can provide additional advanced logging, such as the Microsoft IIS Configuration Operational log, which can be enabled through the event log tool by using the following commands:

  • Lists additional logs available for IIS: `wevtutil el | findstr -i IIS`
  • Configuration for the selected log: `wevtutil gl Microsoft-IIS-Configuration/Operational` 
  • Enable the selected log: `wevtutil sl /e:true Microsoft-IIS-Configuration/Operational`
A screenshot of the Windows Terminal showing the results of running two commands. The first command run is "wevtutil.exe el | findstr IIS". The result shows a list of five additional logs available for IIS: Microsoft-IIS-Configuration/Administrative, Microsoft-IIS-Configuration/Analytic, Microsoft-IIS-Configuration/Debug, Microsoft-IIS-Configuration/Operational, and Microsoft-IIS-Logging/Logs. The second command run is "wevtutil.exe gl "Microsoft-IIS-Configuration/Operational". The results highlighted show that the selected log is not enabled, the logFileName is %SystemRoot%\System32\Winevt\Logs\Microsoft-IIS-Configuration%Operational.evtx, and the max size is 1052672 bytes.
Figure 5. Example showing wevtutil querying the IIS Configuration Operational event log

The log that we will be focusing on in this blog is the Microsoft IIS Configuration Operational log. When enabled, the default path for this log is `C:\Windows\System32\winevt\Logs\Microsoft-IIS-Configuration%4Operational.evtx’ (shown in the figure above).

The Microsoft IIS Configuration Operational log captures the additional and removal of IIS modules (Event ID 29).  IIS modules are not commonly added to a production IIS server, so alerting on this event ID should be enabled within your SIEM or security products.

A screenshot of events captured in the Microsoft IIS Configuration Operational log. Event ID 29 is highlighted to show the event logged when the IIS module ‘ProxyShell’ is added to the default website. The event text reads: Changes to ‘/system.webServer/modules/add[@name=”ProxyShell”]’ at ‘MACHINE/WEBROOT/APPHOST/Default Web Site’ have successfully been committed. The event details include the log name (Microsoft-IIS-Configuration/Operational), the source (IIS-Configuration), the level (Verbose), the User (omitted for this blog), the OpCode (Info), the logged timestamp (31/7/2022 11:40:16 AM), and the Computer (home).
Figure 6. Event ID 29 showing the IIS module ‘ProxyShell’ being added to the default website

Note: This IIS module has no correlation with the Exchange Vulnerability ProxyShell.

A screenshot of events captured in the Microsoft IIS Configuration Operational log. Event ID 29 is highlighted to show the event logged when the IIS module ‘ProxyShell’ is removed from the default website. The event text reads: Changes to ‘/system.webServer/modules/remove[@name=”ProxyShell”]’ at ‘MACHINE/WEBROOT/APPHOST/Default Web Site’ have successfully been committed. The event details include the log name (Microsoft-IIS-Configuration/Operational), the source (IIS-Configuration), the level (Verbose), the User (omitted for this blog), the OpCode (Info), the logged timestamp (31/7/2022 11:41:52 AM), and the Computer (home).
Figure 7. Event ID 29 showing the IIS module ‘ProxyShell’ being removed from the default website

IIS module listing

IIS modules can be installed at a global level or at a site level. In detecting malicious IIS modules, it is important to check both the global and site level for unauthorized modules. Regular monitoring of these locations for such modules and comparing against a known good list can help detect and identify malicious IIS modules. Appcmd (path: %windir%\system32\inetsrv\appcmd.exe), a command line tool for managing your IIS servers, can be used to that purpose. The command ‘appcmd list modules’ will list global IIS modules on your server. The command ‘appcmd list modules /app.name:<appName>/’ will let you search specific websites.

A screenshot of the Windows Terminal showing the results of running the command "appcmd.exe list modules /appname:"Default Web Site/". The result show a list of thirty modules, such as IsapiModule, IsapiFilterModule, HttpLoggingModule, and more. The last two modules on the list are “ProxyShell” with details ( type:System.Web.Security.ProxyShell.Shell, preCondition: ) and “Malicious IIS Module” with details ( type:System.Web.Security.ProxyShell.Shell, preCondition: ).
Figure 8. Appcmd listing the modules for Default Web Site and showing two malicious modules: “ProxyShell” and “Malicious IIS Module”

Modules listed through appcmd will be ordered based on the order of installation. In Figure 9, the two malicious IIS modules, ProxyShell and Malicious IIS Module, were the two most recent IIS modules installed and therefore the last two on the list. The type parameter also shows the class that is called when the module is loaded.

Web.config

The web.config file, which details the settings for a website, can include modules that the website loads and should therefore be monitored when detecting malicious IIS modules. Monitoring of web.config should primarily focus on tracking modifications to the file, and can be done through multiple tools and sources. For example, the Microsoft IIS Configuration Operational event log produces Event ID 50 when a modification is made to a website. Because the content of the modification is not captured, a backup of the web.config should be stored for easy comparison between the modified file and the original.

A screenshot of events captured in the Microsoft IIS Configuration Operational log. Event ID 50 is highlighted to show the event captured when a modification is made to the default website. The event text reads: Changes have been successfully committed to ‘MACHINE/WEBROOT/APPHOST/Default Web Site’.  The event details include the log name (Microsoft-IIS-Configuration/Operational), the source (IIS-Configuration), the level (Information), the User (omitted for this blog), the OpCode (Info), the logged timestamp (31/7/2022 11:41:52 AM), and the Computer (home).
Figure 9. Event ID 50 showing that a modification has been made to default website

Most EDRs capture file modification events as well. Enabling an alert for the modification of web.config, especially from the w3wp.exe process, will enable detection of unwarranted changes to the config.

Hunting for malicious IIS modules

IIS module loading

While loaded IIS modules are standardly loaded DLLs, not all tools list .NET modules that are loaded into w3wp.exe. One tool that does show IIS modules loaded into w3wp.exe is Process Hacker, which if used with administrative privileges, will show them under the Modules tab.

A screenshot of Process Hacker showing ProxyShell.DLL loaded into w3wp.exe under the Modules tab. The name of the window is w3wp.exe (12728) Properties.
Figure 10. Malicious ProxyShell IIS module loaded within the w3wp.exe process

In Microsoft Defender for Endpoint, an IIS module that is loaded into w3wp.exe will appear twice: First when loaded from the bin directory from which it resides, then immediately after from the temporary ASP.NET directory.

A screenshot of the Advanced Hunting query window in Microsoft Defender for Endpoint. The KQL query run is: DeviceImageLoadEvents | where FileName has “ProxyShell” | where InitiatingProcessFileName has “w3wp.exe” | project FolderPath. The results of the query are two folder paths: “C:\inetpub\wwwroot\bin\ProxyShell.dll” and “C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\e22c2559\92c7e946\assembly\dl3\db6147e5\e6334bff_63bfd801\ProxyShell.DLL”.
Figure 11. Malicious IIS module ProxyShell being listed in Defender for Endpoint

By default, IIS modules are loaded when the w3wp.exe process is created. If an IIS module is loaded while the w3wp.exe process is already executing and at a different time than the rest of the module, it can be an indicator for malicious IIS module loading. Monitoring for abnormal module loads may help detect malicious IIS modules. Using a query like the KQL one below can group together modules loaded into w3wp.exe at the same second. In Figure 12, we can see a large number of modules being loaded within a three second time period, followed by the malicious ProxyShell IIS module three hours later.

DeviceImageLoadEvents
| where InitiatingProcessFileName has "w3wp.exe"
| summarize loaded_modules=make_set(FileName) by format_datetime(Timestamp, 'yy-MM-dd HH:mm:ss')
| project Timestamp, loaded_modules, count=array_length(loaded_modules)
A screenshot of the Advanced Hunting query window in Microsoft Defender for Endpoint. The KQL query run is: DeviceImageLoadEvents | where InitiatingProcessFileName has "w3wp.exe" | summarize loaded_modules=make_set(FileName) by format_datetime(Timestamp, 'yy-MM-dd HH:mm:ss') | project Timestamp, loaded_modules, count=array_length(loaded_modules). The results are shown in a table with three columns: Timestamp, loaded_modules, and count. At 22-09-03 04:16:57, there are 10 loaded modules. At 22-09-03 04:16:58, there are 21 loaded modules. At 22-09-03 04:16:59, there are 2 loaded modules. At 2022-09-03 07:11:09, there are three loaded modules, with the names “ProxyShell.dll” and “ProxyShell.DLL” shown in the loaded modules column.
Figure 12. Anomalous module loading based on timeframe of other IIS modules

Assembly loading

While IIS modules have the capability to load .NET modules arbitrarily and reflectively within the context of w3wp.exe, the AppDomains are still registered within the hosting process. By listing AppDomain loaded within an assembly through a tool like Process Hacker, you’ll be able to find the loaded IIS module and any .NET modules that have been loaded.

A screenshot of Process Hacker in the .NET assemblies tab showing a hierarchical list of .NET assemblies loaded in w3wp.exe with the Structure, the ID, and flags. Of the 27 entries shown in the screenshot, five are highlighted: ProxyShell, SharpHound, SharpHoundCommonLib, SweetPotato, SweetPotato. All five have the ID 270243 and have an empty Flags field (most other entries have populated Flags fields).
Figure 13. Malicious ProxyShell IIS module, SharpHound and SweetPotato App Domains

In the figure above, the malicious IIS module ProxyShell can be seen alongside the loaded assemblies SharpHound and SweetPotato. Another thing to note is that reflectively loaded modules usually do not have Flags: in Figure 13, all the assemblies without Flags are either loaded through the malicious IIS module or through Visual Studio debugging.

The ETW provider Microsoft-Windows-DotNETRuntimeRundown provides a snapshot in time of the loaded .NET modules within active processes. Two events can help detect malicious assemblies loaded within IIS:

  • Event ID 151 lists loaded AppDomains.
  • Event ID 155 enumerates assemblies loaded at the time of the rundown.

The ModuleILPath field shows the path of the loaded assembly; however, if this assembly is loaded reflectively, rather than a path to the file, it will instead just list the name of the assembly. The figure below shows how SharpHound and SweetPotato, both with reflectively loaded assemblies, do not have paths while other events do.

A screenshot of a snippet of Microsoft-Windows-DotNETRuntimeRundown showing a snapshot of loaded .NET modules. The ModuleILPath fields are highlighted, three of them showing just the assembly name with no path (“SharpHound”, “SweetPotato”, “SweetPotato”) and one showing the assembly path (“C:\\Windows\\Microsoft.NET\\Framework64\\...”).
Figure 14. Example of reflectively loaded assemblies not having a file path within the ModuleILPath field

The Assembly Flags field may also be 0, similar to Figure 13 where Process Hacker shows empty Flags for the assemblies.

A screenshot of a snippet of Microsoft-Windows-DotNETRuntimeRundown showing a snapshot of loaded .NET modules. The AssemblyFlags field is highlighted, and all fields show a value of “0”.
Figure 15. Example of empty assembly flags for .NET rundown

IIS module installation

Processes which contain appcmd or gacutil within the command line and the parent process w3wp.exe should be investigated for potential installation of malicious IIS modules. The following Defender for Endpoint queries can help detect such malicious IIS module installation:

DeviceProcessEvents
| where ProcessCommandLine has "appcmd.exe add module"
| where InitiatingProcessParentFileName == "w3wp.exe"
DeviceProcessEvents
|where ProcessCommandLine has "\\gacutil.exe /I"
| where InitiatingProcessParentFileName == "w3wp.exe"

Process creation

Process creation events with the parent process of w3wp.exe should be monitored for abnormal child processes. For IIS servers that require child processes of w3wp.exe, ignore lists should be created for these child processes to prevent false flags.

DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ('w3wp.exe', 'httpd.exe')
| where FileName in~ ('cmd.exe', 'powershell.exe', 'cscript.exe', 'wscript.exe', 'net.exe', 'net1.exe', 'ping.exe', 'whoami.exe')
| summarize instances = count() by ProcessCommandLine, FolderPath, DeviceName, DeviceId | order by instances asc

Query source: Azure-Sentinel/Webserver Executing Suspicious Applications.yaml

If one of the Potato-sploits are being used to create processes, the AccountName field may also be “System” while the InitiatingProcessAccountName will be the Application Pool.

Conclusion

Threat actors use a variety of techniques to conceal their activity when using malicious IIS modules. Enabling additional logging in your environment is recommended to facilitate the detection of these harmful modules. Specifically, IIS servers should enable the optional event log Microsoft IIS Configuration Operational. This log can provide insight into IIS modules being added or removed from the IIS server and track any modifications made to web.config.

IIS Servers should have their web.config and IIS modules monitored for malicious modifications being made. For example, Gacutil.exe and appcmd.exe being executed from w3wp.exe should be monitored for potential installation of IIS modules. Additionally, the bin directories of websites and the default GAC path should be monitored and regularly scanned for malicious modules being created.

Hunting for malicious IIS modules can be performed through Microsoft Defender for Endpoint or your EDR of choice, and it should be conducted regularly to detect abnormal w3wp.exe interactions. This can include, but is not limited to, process creation, file creation and named pipe creation. Due to the wide flexibility around how IIS modules can execute malicious code, it’s important to look for irregularities in behavior.

Detecting web exploitation and malicious IIS modules should be a priority for all organizations, and Microsoft DART believes that following the recommendations provided in this blog and along with the monitoring and detection strategies will assist your organization in the detection and response of these threats.

READ MORE HERE