Process-tree detection: w3wp, httpd or java spawning shells
Detect web shell activity from process telemetry: suspicious children of IIS, Apache, nginx/PHP-FPM and Java servers, with Sysmon, Event 4688, auditd, KQL and Sigma examples.
A web shell's file can be obfuscated, renamed and timestomped. Its traffic can be encrypted. But when the operator wants to do something — list users, dump credentials, compress data — the web server process has to start a child process. That parent-child relationship is one of the most robust, family-agnostic web shell detections available.
The pattern
Web server worker processes should run application code, not command interpreters. When they spawn shells and reconnaissance utilities, something is executing commands through the web tier.
| Platform | Worker (parent) process | Suspicious children |
|---|---|---|
| IIS / ASP.NET | w3wp.exe | cmd.exe, powershell.exe, pwsh.exe, whoami.exe, net.exe, net1.exe, nltest.exe, ipconfig.exe, systeminfo.exe, certutil.exe, bitsadmin.exe, rundll32.exe, reg.exe, tasklist.exe, quser.exe, wmic.exe |
| Exchange | w3wp.exe (MSExchange* app pools), UMWorkerProcess.exe | Same as above; plus unexpected writes to webroots |
| Apache (prefork / mod_php) | httpd, apache2 | sh, bash, dash, id, uname, whoami, curl, wget, nc, python*, perl |
| nginx + PHP-FPM | php-fpm* (nginx itself does not execute PHP) | Same as above |
| Tomcat / Java | java (Tomcat, JBoss/WildFly, WebLogic, WebSphere) | sh, bash, cmd.exe, powershell.exe |
| Node.js | node | sh, bash, cmd.exe |
| Python (gunicorn/uwsgi) | gunicorn, uwsgi, python* | sh, bash |
Reconnaissance commands are the highest-signal children: an operator's first actions on a new shell are nearly always identity and environment discovery (whoami, hostname, ipconfig /all, net group "domain admins" /domain).
Getting the telemetry
Windows
- Sysmon Event ID 1 (ProcessCreate) records
Image,CommandLine,ParentImage,ParentCommandLine, user, hashes and a process GUID linking parent and child. - Security Event 4688 (Audit Process Creation) plus the policy Include command line in process creation events provides the same core data without Sysmon.
- EDR products record full process trees and usually ship built-in web shell analytics.
The IIS app pool name appears in the worker's command line (w3wp.exe -ap "DefaultAppPool" ...), which tells you which site spawned the child.
Linux
- auditd with an
execverule for the web server's UID captures every program it launches:
# /etc/audit/rules.d/60-web-exec.rules — replace 33 with your web server UID (id -u www-data)
-a always,exit -F arch=b64 -S execve -F uid=33 -k web_exec
-a always,exit -F arch=b32 -S execve -F uid=33 -k web_exec
Review with ausearch -k web_exec -i. Any execve by the web user that is not part of a known allow-list is a lead.
- eBPF-based sensors (Falco, Tetragon, EDR agents) provide richer, lower-overhead process lineage and are well suited to containers.
Detection queries
Microsoft Defender XDR / Sentinel (KQL)
let webParents = dynamic(["w3wp.exe","httpd.exe","tomcat.exe","tomcat9.exe","java.exe","php-cgi.exe","UMWorkerProcess.exe","node.exe"]);
let suspicious = dynamic(["cmd.exe","powershell.exe","pwsh.exe","whoami.exe","net.exe","net1.exe","nltest.exe",
"ipconfig.exe","systeminfo.exe","certutil.exe","bitsadmin.exe","reg.exe","wmic.exe",
"tasklist.exe","quser.exe","rundll32.exe","mshta.exe"]);
DeviceProcessEvents
| where Timestamp > ago(14d)
| where InitiatingProcessFileName in~ (webParents)
| where FileName in~ (suspicious)
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName,
InitiatingProcessCommandLine, FileName, ProcessCommandLine
| order by Timestamp desc
Splunk (Sysmon)
index=sysmon EventCode=1
(ParentImage="*\\w3wp.exe" OR ParentImage="*\\httpd.exe" OR ParentImage="*\\java.exe" OR ParentImage="*\\php-cgi.exe")
(Image="*\\cmd.exe" OR Image="*\\powershell.exe" OR Image="*\\whoami.exe" OR Image="*\\net.exe" OR Image="*\\nltest.exe")
| table _time host User ParentImage ParentCommandLine Image CommandLine
Sigma (portable)
Sigma rules compile to most SIEM query languages. A compact rule for the Windows case:
title: Web Server Worker Spawning Shell or Recon Utility
id: 5b8f2a61-3c1e-4d7a-9b2e-6f0c1a9d4e21
status: experimental
description: Detects IIS, Tomcat, PHP-CGI or Exchange UM worker processes spawning command interpreters or discovery tools, a common web shell behaviour.
references:
- https://attack.mitre.org/techniques/T1505/003/
author: WebShells
date: 2026-09-24
tags:
- attack.persistence
- attack.t1505.003
logsource:
category: process_creation
product: windows
detection:
parent:
ParentImage|endswith:
- '\w3wp.exe'
- '\httpd.exe'
- '\tomcat.exe'
- '\java.exe'
- '\php-cgi.exe'
- '\UMWorkerProcess.exe'
child:
Image|endswith:
- '\cmd.exe'
- '\powershell.exe'
- '\pwsh.exe'
- '\whoami.exe'
- '\net.exe'
- '\net1.exe'
- '\nltest.exe'
- '\ipconfig.exe'
- '\systeminfo.exe'
- '\certutil.exe'
- '\wmic.exe'
condition: parent and child
falsepositives:
- Applications that legitimately invoke system utilities (document converters, backup or reporting jobs)
level: high
The Linux equivalent uses logsource: {category: process_creation, product: linux} with ParentImage|endswith values such as /httpd, /apache2, /php-fpm, /java and Image|endswith values such as /sh, /bash, /id, /whoami, /uname. The public SigmaHQ repository contains maintained rules for both platforms; start there and tune.
Reading the command lines
Children tell you what the operator did. Typical sequences, which map neatly onto ATT&CK:
| Phase | Typical command lines | ATT&CK |
|---|---|---|
| Discovery | whoami /all, hostname, ipconfig /all, systeminfo, net user, net group ... /domain, nltest /dclist: | T1033, T1082, T1016, T1087 |
| Credential access | Dumping LSASS via rundll32 with comsvcs.dll, reg save HKLM\SAM, reading config files for connection strings | T1003 |
| Staging / transfer | certutil -urlcache, bitsadmin /transfer, curl, wget, PowerShell download cradles | T1105 |
| Collection | Archivers (7z, rar, tar) creating files in web-accessible folders | T1560, T1074 |
| Persistence | New local accounts, scheduled tasks, additional web shell files | T1136, T1053, T1505.003 |
When a command writes an archive into the webroot and the next log entry is a GET for that archive, you have evidence of exfiltration through the web server — correlate with log analysis.
Tuning without blinding yourself
- Baseline per application pool / service. Record which child processes and command lines each app legitimately uses (for example a PDF renderer). Allow-list by full command line pattern and parent app pool, not by image name alone.
- Never allow-list
cmd.exeorshwholesale. Allow the specific invocation. - Weight recon utilities higher than generic interpreters —
whoamifromw3wpis rarely benign. - Correlate with file events. A child process shortly after a new executable file appears in the webroot is a near-certain true positive.
Beyond parent-child: other process signals
- Unusual modules loaded by the worker — unsigned DLLs in
w3wp.exe, native IIS modules registered recently (appcmd list modules), unfamiliar Java agents or filters. - Network connections from the worker to internal hosts on SMB, RDP, WinRM, LDAP or database ports it does not normally use — a sign of tunnelling through the shell.
- Worker process identity changes — application pools switched to
LocalSystemor new service accounts. - Prevention as detection — application control (WDAC/AppLocker on Windows, SELinux/AppArmor confinement on Linux) can block worker processes from launching interpreters; the resulting block events are high-fidelity alerts. See eradication and hardening.