JSP shells ride on the servlet container: a file dropped under webapps is compiled on first request and executed with the container’s privileges. File and process telemetry cover the classic case. Modern Java exploitation also installs filters, servlets or listeners directly in memory, which leaves no JSP file at all, so the detection plan needs both layers.
Signals at a Glance
| Signal | Where | ATT&CK |
|---|---|---|
| java or catalina process spawning sh, bash, cmd.exe or powershell.exe | auditd, Sysmon, EDR | T1059.004 |
| New .jsp or .jspx file under webapps or a work directory | FIM, auditd, Sysmon 11 | T1505.003 |
| Runtime.getRuntime().exec, ProcessBuilder or defineClass in uploaded JSPs | File scan, YARA | T1505.003 |
| New filter, servlet or valve registered at runtime with no matching file | JVM telemetry, EDR | T1620 |
| Compiled JSP classes in the work directory without a matching source JSP | File inspection | T1070.004 |
JVM Process Lineage
A servlet container launching a command interpreter is rare in a well-run application. Start with this Sigma rule, then record the legitimate exceptions, which tend to be backup, reporting or conversion scripts:
title: Java Servlet Container Spawning Shell
logsource:
category: process_creation
product: linux
detection:
parent:
ParentImage|endswith: '/java'
ParentCommandLine|contains:
- 'catalina'
- 'tomcat'
- 'jetty'
child:
Image|endswith:
- '/sh'
- '/bash'
- '/curl'
- '/wget'
- '/whoami'
- '/id'
condition: parent and child
level: high
# Tune/validate: Windows variant uses cmd.exe/powershell.exe with a java.exe parent.
Pair that with a periodic sweep for recently created JSP files and for compiled classes that have no source counterpart. This shell script is a starting point for the file layer:
#!/bin/sh
# List JSP files changed in the last 30 days under common Tomcat locations
for root in /opt/tomcat/webapps /var/lib/tomcat*/webapps /usr/share/tomcat*/webapps; do
[ -d "$root" ] && find "$root" -type f \( -name '*.jsp' -o -name '*.jspx' \) -mtime -30 \
-printf '%TY-%Tm-%Td %TH:%TM %u %p\n'
done
# Tune/validate: adjust paths to your installation; compare to your release manifest.
Memory-Resident Shells
- Inventory registered filters, servlets and listeners from the container’s management interface on a schedule, and alert on additions that are not in your deployment.
- Scan JVM heap or class histograms from suspect hosts for unfamiliar class names loaded by the web application class loader.
- Correlate access logs: requests to a URL that returns a 200 but does not correspond to any file or mapped servlet are a classic sign of a memory shell.
- Limit the container user’s privileges and egress, and log every execve by that user. It turns a successful shell into a visible one.
- Treat unauthenticated access to management consoles as an incident precursor and review it with the same urgency as a new JSP file.
Use the SigmaHQ Java server child-process rules, Elastic and Splunk ESCU analytics for Java spawning shells, CISA advisories on Java application exploitation, and the Neo23x0 signature-base JSP YARA rules. Baseline your own environment — reporting and batch features in Java applications sometimes shell out, and that is the main source of false positives.
Build Detections That Fire
Mjolnir Security helps blue teams turn threat intelligence into high-fidelity detections across endpoint, network, identity and cloud telemetry.
- Detection Engineering We build and tune detections mapped to ATT&CK from your own telemetry.
- Threat Hunting as a Service Hypothesis-driven hunts for the behaviours on this page.
- 24/7 Incident Response Containment when a detection fires. Call +1 833 403 5875.
Stay ahead of emerging threats. Get notified when we publish new intelligence reports and advisories.
Subscribe to Alerts