Internet Information Services (IIS) is a commonly used web server produced by Microsoft to assist organizations of all sizes to host content publicly or internally, including on premise SharePoint or Exchange. IIS modules are like building blocks, modules may be added to the server in order to provide the desired functionality for applications. Installation is done by using one of three methods on Windows - The IIS interface, AppCmd.exe and PowerShell New-WebGlobalModule.
Microsoft published two blogs in 2022 (July and December) detailing how adversaries will persist with IIS modules and how to detect them. In parallel, CrowdStrike has been tracking a campaign since 2021, dubbed IceApple, that has evolved over the years by installing multiple modules to perform different post-exploitation functions.
Defenders need to understand how to monitor for IIS modules, identify suspicious command execution, track suspicious DLLs on disk and quickly respond. This blog showcases how to enable and ingest IIS operational logs, utilize PowerShell scripted inputs to ingest installed modules and simulate AppCmd and PowerShell adding new IIS modules and disable HTTP logging using Atomic Red Team. We also share analytics created by the Splunk Threat Research Team (STRT) to identify suspicious IIS component activity.
There are two types of IIS modules, which we break down here to better understand how IIS operates with each.
The first type of IIS modules is a native module. A native module is typically going to be a DLL deployed to the server and loaded up via IIS Administration Tool, PowerShell or AppCmd. Per Microsoft, all three of these installation methods result in the module entry being added to the <globalModules> IIS configuration section, which can be set only at the server level. To examine the contents of this section, open the root configuration file located in %windir%\system32\inetsrv\config\applicationhost.config, and search for the string "<globalModules>".
The second type of IIS modules is managed modules. Per Microsoft, a managed module does not require installation and can be enabled directly for each application. This allows applications to include their managed modules directly within the application by registering them in the application's web.config file, and providing the implementation in /BIN or /App_Code directories.
All three of these options add the module entry to the <modules> IIS configuration section, which can be set at both the server level and application level. Examine the contents of this section by opening the root configuration file located in %windir%\system32\inetsrv\config\applicationhost.config, and search for the string "<modules>".
Microsoft provides three methods to manage modules:
The IIS Manager application allows for easy adding and removing of both managed and native modules.
AppCmd by default is found in %windir%\system32\inetsrv\. AppCmd.exe provides all sorts of functionality to manage IIS, but for this blog we focus on listing, adding and removing modules.
To list modules:
%windir%\system32\inetsrv\appcmd.exe list modules
Add a module:
%windir%\system32\inetsrv\appcmd.exe install module /name:DefaultDocumentModule_round2 /image:%windir%\system32\inetsrv\defdoc.dll
Uninstall a module:
%windir%\system32\inetsrv\appcmd.exe uninstall module DefaultDocumentModule
Similar to AppCmd, PowerShell has cmdlets that can be used to do similar functions.
To list modules:
Get-WebGlobalModule
Add new module:
New-WebGlobalModule -Name DefaultDocumentModule_Atomic2 -Image %windir%\system32\inetsrv\defdoc.dll
Uninstall module:
Remove-WebGlobalModule -Name DefaultDocumentModule_Atomic2
Next, we focus on getting additional IIS logs and collecting modules.
In their latest blog, Microsoft recommends enabling advanced IIS logging to hunt for web shells. The Microsoft-IIS-Configuration/Operational log provides details on new modules being added by site/app pool.
Once enabled, we will need to add the following to an inputs.conf to be collected:
[WinEventLog://Microsoft-IIS-Configuration/Operational] index=win sourcetype=IIS:Configuration:Operational disabled = false
The collected data in Splunk may look like the following:
Splunk 2023, figure 1
The advanced IIS logging is a great source, however, another method we can use with Splunk Universal Forwarders is PowerShell scripted inputs. In this instance, we want to gather all installed modules on our IIS server fleet. As outlined here, we can pass a script or command via inputs.conf and the output will be ingested into Splunk. Deploy the new inputs.conf matching your environment to ingest modules. Modify the scheduled time to meet your needs.
[powershell://IISModules] script = Get-WebGlobalModule schedule = */1 * * * * #schedule = 0 0 * * * sourcetype = Pwsh:InstalledIISModules index=iis
In Splunk we see:
Splunk 2023, figure 2
Note the last 3 modules in a non-standard path.
Now that we have configured IIS logging and inventoried modules in Splunk, we will dive into how to simulate adversary techniques using Atomic Red Team.
The following three Atomic tests assist defenders in simulating and identifying 3 suspect behaviors related to adding new modules and disabling HTTP logging.
T1505.004 -testnumbers 1
This Atomic test simulates adding a IIS module using AppCmd.exe.
T1505.004 -testnumbers 2
This Atomic test simulates adding a new module using PowerShell New-WebGlobalModule cmdlet.
Now we switch gears to disabling HTTP logging.
T1562.002 -testnumber 1
This Atomic test utilizes AppCmd.exe to disable HTTP logging on IIS.
T1562.002 -testnumber 2
This Atomic test utilizes PowerShell cmdlet set-WebConfigurationProperty to disable HTTP logging.
Now that we have simulated adversary tradecraft using AppCmd and PowerShell cmdlets for adding IIS modules or disabling HTTP logging, we can showcase some additional hunts and the security content that assists defenders in identifying this Atomic testing.
When a new module is added to IIS, it will load into w3wp.exe (IIS process). We may utilize an EDR product or Sysmon to look at all modules being loaded by w3wp.exe.
All modules loaded
`sysmon` EventCode=7 parent_process_name=w3wp.exe | stats values(ImageLoaded)
Splunk 2023, figure 3
There is a pattern to normal modules being loaded. It is possible to filter out the most common paths to limit the amount of volume. Note that collecting module loads is intensive and sometimes does not provide high value.
`sysmon` EventCode=7 parent_process_name=w3wp.exe NOT (process_path IN ("*\\inetsrv\\*", "*\\windows\\system32\\*")) | stats values(ImageLoaded)
Splunk 2023, figure 4
While testing out different ways to load a module, we received an error when the module wasn’t correctly formatted or made to load properly into IIS. This generated event code 2282, which occurs when a module fails to load into the IIS worker process.
The following analytics were produced to assist defenders in utilizing multiple log sources to identify suspicious and malicious behavior on IIS web servers.
Data sources:
Windows Disable Windows Event Logging Disable HTTP Logging
Identifies the use of AppCmd.exe to disable HTTP logging.
| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time) as lastTime from datamodel=Endpoint.Processes where NOT (Processes.parent_process_name IN ("msiexec.exe", "iissetup.exe")) Processes.process_name=appcmd.exe Processes.process IN ("*set config*", "*httplogging*","*dontlog:true*") by Processes.dest Processes.user Processes.parent_process_name Processes.process_name Processes.original_file_name Processes.process Processes.process_id Processes.parent_process_id | `drop_dm_object_name(Processes)` | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
Splunk 2023, figure 5
Windows IIS Components Add New Module
Identifies AppCmd.exe adding a new module.
| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time) as lastTime from datamodel=Endpoint.Processes where NOT (Processes.parent_process_name IN ("msiexec.exe", "iissetup.exe")) Processes.process_name=appcmd.exe Processes.process IN ("*install *", "*module *") AND Processes.process="*image*" by Processes.dest Processes.user Processes.parent_process_name Processes.process_name Processes.original_file_name Processes.process Processes.process_id Processes.parent_process_id | `drop_dm_object_name(Processes)` | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
Splunk 2023, figure 6
Windows IIS Components Get-WebGlobalModule Module Query
Using PowerShell scripted inputs, gathers all installed IIS modules and outputs to Splunk.
`iis_get_webglobalmodule` | stats count min(_time) as firstTime max(_time) as lastTime by host name image | rename host as dest | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
Splunk 2023, figure 7
Windows IIS Components Module Failed to Load
When a module fails to load, it generates Event ID 2282.
`wineventlog_application` EventCode=2282 | stats count min(_time) as firstTime max(_time) as lastTime by EventCode dest Name ModuleDll | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
Splunk 2023, figure 8
Windows IIS Components New Module Added
Utilizing EventCode 29 from the IIS Operational logs, identifies new modules installed.
`iis_operational_logs` EventCode=29 | stats count min(_time) as firstTime max(_time) as lastTime by OpCode EventCode ComputerName Message | rename ComputerName AS dest | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
Splunk 2023, figure 9
Windows PowerShell Disable HTTP Logging
Utilizing PowerShell Script Block Logging, identifies when HTTP logging is disabled.
`powershell` EventCode=4104 ScriptBlockText IN("*get-WebConfigurationProperty*","*Set-ItemProperty*") AND ScriptBlockText IN ("*httpLogging*","*Logfile.enabled*") AND ScriptBlockText IN ("*dontLog*", "*false*") | stats count min(_time) as firstTime max(_time) as lastTime by EventCode ScriptBlockText Computer user_id | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
Splunk 2023, figure 10
Windows PowerShell IIS Components WebGlobalModule Usage
Utilizing PowerShell Script Block Logging, identifies the use of a new module being added, enabled or modified.
`powershell` EventCode=4104 ScriptBlockText IN("*New-WebGlobalModule*","*Enable-WebGlobalModule*","*Set-WebGlobalModule*") | stats count min(_time) as firstTime max(_time) as lastTime by EventCode ScriptBlockText Computer user_id | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
Splunk 2023, figure 11
In closing, we covered adversaries using IIS modules to persist and perform post-exploitation, we focused on capturing new log sources from IIS and using PowerShell to gather IIS modules and we showcased Atomic testing to assist defenders in simulating these attacks. Last, the Splunk Threat Research Team developed 7 new analytics spanning 5 different data sources to help organizations of all sizes identify suspicious activity. The content may be obtained from ESCU or SSE.
You can find the latest content and security analytic stories on GitHub and in Splunkbase. Splunk Security Essentials also has all these detections available via push update. For a full list of security content, check out the release notes on Splunk Docs.
Any feedback or requests? Feel free to put in an issue on GitHub and we’ll follow up. Alternatively, join us on the Slack channel #security-research. Follow these instructions if you need an invitation to our Splunk user groups on Slack.
The Splunk platform removes the barriers between data and action, empowering observability, IT and security teams to ensure their organizations are secure, resilient and innovative.
Founded in 2003, Splunk is a global company — with over 7,500 employees, Splunkers have received over 1,020 patents to date and availability in 21 regions around the world — and offers an open, extensible data platform that supports shared data across any environment so that all teams in an organization can get end-to-end visibility, with context, for every interaction and business process. Build a strong data foundation with Splunk.