Skip to content

Web Shell Evolution and Discovery in IIS Modules

Web Shell Detection and Prevention (Web Shells Part 5) | Acunetix

Web exploitation and web shells are common ways that attackers gain access to corporate networks. Web servers provide an external access point into the network, and are often the first point of entry for attackers. It is important for all networks to monitor for signs of exploitation and web shells, and to take steps to prevent them. While some techniques for detecting these threats are specific to IIS modules, many can be applied more broadly to protect against web shells in general.

History of malicious IIS modules

The concept of malicious IIS modules has been around since at least 2013. Historical analysis of malware has shown that crimeware groups have used IIS modules to intercept client logins and payment information by using the BeginRequest triggers to read user-provided parameters before the web server processes them.

One of the earliest examples of sophisticated IIS modules was discovered in late 2021. The vendor’s ICEAPPLE report describes an IIS module that was used by an attacker to load additional .NET modules, which in turn allowed the attacker to load additional capabilities. This allowed the attacker to minimize the number of malicious indicators in the base IIS module, and only load additional capabilities as needed.

Malicious IIS modules techniques

Event handlers

A key part of IIS module functionality is the ability to handle events. Event triggers are used to call code when specific actions occur. IIS modules have access to 27 default event triggers, including:

  • Begin Request: When a request is received by the web server.
  • 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 are called when their associated event triggers are fired, can be used by attackers to set up a proxy on the IIS server. By setting up event handlers on the BeginRequest, EndRequest, and Error event triggers, an attacker can intercept all requests before the web service can process them and before the response is sent to the client. This allows the attacker to control the communication between the client and the server, and potentially steal sensitive information.

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 access to read and write requests, which allows malicious IIS modules to hide web shell communications within any part of the web request. This can include hiding web shell communications in the parameters, body, headers, or HTTP methods of the request. This makes it difficult for defenders to detect the presence of web shells since they can be hidden in a wide range of different parts of the request. Additionally, because web shell communications can be hidden on pages that do or do not exist, it can be challenging to identify which pages are being used for malicious purposes.

The ability of malicious IIS modules to hide web shell communications in various parts of web requests makes them difficult to detect using standard IIS logs. Traditional web shell detection strategies, such as looking for high-frequency page requests or specific URI patterns, are not effective against malicious IIS modules. Instead, new detection techniques and the use of advanced IIS logging are required to detect these threats.

Request and response tampering

Another challenge with malicious IIS modules is that they can manipulate any part of the request and response. This can 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 to the client, which provides an opportunity for attackers to serve malicious payloads in the response from the website. This can potentially infect viewers of the website with malware.

Process creation

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

Monitoring for the creation of common shell tools with the w3wp.exe process should not be considered a strong detection method for IIS modules. Because IIS modules have full integration with C# and the .NET framework, a wide range of functionality can be integrated to execute directly within the IIS process without the need to create child processes.

.NET assembly loading

A common tactic used by attackers is to load .NET modules directly into memory using the reflective loading of assemblies. This allows common tools, such as SharpHound or the Potato PrivEsc family, to be loaded without being written to disk. This is seen as a stealthier alternative to process creation because the tools are loaded within the context of the w3wp.exe process, rather than as a separate 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 a previous vendor paper, assemblies can be provided arbitrarily to deliver additional functionality to IIS modules. This can be done by providing the assembly through the web request, or by downloading it from an attacker-controlled command and control (C2) server. The figure below illustrates this process:

  1. SharpHound is downloaded from an external C2 and loaded through the Reflection Assembly Load method.
  2. Two methods are invoked within the binary and the output directory is 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

Because IIS modules have access to .NET, attackers can use it to add additional layers of evasion to prevent the detection of their IIS modules. This can include techniques such as encoding or encryption. The figure below illustrates this process:

  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 modules Logs

IIS logs are a good starting point for hunting for web shells, but it is recommended to use advanced IIS logging 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 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 will be discussed 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’ (as shown in the figure above).

The Microsoft IIS Configuration Operational log captures information about the addition and removal of IIS modules (Event ID 29). IIS modules are not commonly added to production IIS servers, so it is recommended to enable alerts for this event ID 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 shows 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 modules listing

IIS modules can be installed at the global level or at the site level. In order to detect malicious IIS modules, it is important to check both levels for unauthorized modules. Regular monitoring of these locations, and comparison against a known-good list of modules, can help to detect and identify malicious IIS modules. The Appcmd tool (located at %windir%\system32\inetsrv\appcmd.exe), which is a command-line tool for managing IIS servers, can be used for this purpose. The command appcmd list modules will list global IIS modules on your server, while the command appcmd list modules /app.name:<appName>/ will let you search for specific websites. Using these commands can help you to identify unauthorized IIS modules, and take steps to remove them.

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 lists the modules for Default Web Site and shows two malicious modules: “ProxyShell” and “Malicious IIS Module”

Modules listed through Appcmd will be ordered based on the order in which they were installed. In the figure below, the two malicious IIS modules, ProxyShell and Malicious IIS Module are the two most recent IIS modules installed, and therefore appear at the end of the list. The type parameter also shows the class that is called when the module is loaded.

Web.config

The web.config file, which contains the settings for a website, can include information about the modules that the website loads. This means that monitoring the web.config file can be useful for detecting malicious IIS modules. When monitoring web.config files, it is important to focus on tracking modifications to the file. This can be done using various tools and sources, such as the Microsoft IIS Configuration Operational event log, which produces Event ID 50 when a modification is made to a website. Because the content of the modification is not captured in the event log, it is recommended to keep a backup of the web.config file for easy comparison with the modified version.

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 a default website

Many endpoint detection and response (EDR) systems capture file modification events as well. Enabling an alert for the modification of web.config, especially from the w3wp.exe process, can help to detect unauthorized changes to the config file.

Hunting for malicious IIS modules

IIS modules loading

While IIS modules are typically loaded as DLLs, not all tools can detect .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 display 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 it is loaded from the bin directory where it resides, and then immediately afterward 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 modules, it can be an indicator of malicious IIS module loading. Monitoring for abnormal module loads can help to detect malicious IIS modules. A query like the one below, which groups together modules loaded into w3wp.exe at the same second, can be useful for this purpose:

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

Although IIS modules have the ability to load .NET modules arbitrarily and reflectively within the context of w3wp.exe, the AppDomains are still registered within the hosting process. By using a tool like Process Hacker to list the AppDomains loaded within an assembly, you can identify 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 the Flags property. In the figure, 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 that can help to detect malicious assemblies loaded within IIS are:

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

The ModuleILPath field in the Microsoft-Windows-DotNETRuntimeRundown events shows the path of the loaded assembly. However, if an assembly is loaded reflectively, rather than from a file, the ModuleILPath field will just show 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 in the Microsoft-Windows-DotNETRuntimeRundown events may also be 0, similar to how the Flags field appears empty for the assemblies in Figure 13 when using Process Hacker.

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 that contain appcmd or gacutil within the command line and have the parent process w3wp.exe should be investigated for potential installation of malicious IIS modules. The following Defender for Endpoint queries can help to detect such installations:

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

It is important to monitor process creation events with the parent process w3wp.exe 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

Conclusion

To protect against malicious IIS modules, it is recommended to enable additional logging in your IIS environment, monitor web.config and IIS modules for suspicious activity, and regularly hunt for abnormalities in w3wp.exe behavior. This can be done using tools such as Microsoft Defender for Endpoint or a preferred EDR solution. It is important to look for irregularities in behavior, as IIS modules can execute malicious code in various ways. Detecting and responding to these threats should be a priority for all organizations, and following these recommendations can assist in this effort.


Here at CourseMonster, we know how hard it may be to find the right time and funds for training. We provide effective training programs that enable you to select the training option that best meets the demands of your company.

For more information, please get in touch with one of our course advisers today or contact us at training@coursemonster.com