Suspicious Command Execution via Web Server
Identifies suspicious command executions via a web server, which may suggest a vulnerability and remote shell access. Attackers may exploit a vulnerability in a web application to execute commands via a web server, or place a backdoor file that can be abused to gain code execution as a mechanism for persistence.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2026/06/01"
3integration = ["endpoint"]
4maturity = "production"
5updated_date = "2026/06/04"
6
7[rule]
8author = ["Elastic"]
9description = """
10Identifies suspicious command executions via a web server, which may suggest a vulnerability and remote shell access.
11Attackers may exploit a vulnerability in a web application to execute commands via a web server, or place a backdoor
12file that can be abused to gain code execution as a mechanism for persistence.
13"""
14false_positives = [
15 """
16 Network monitoring or management products may have a web server component that runs shell commands as part of normal
17 behavior.
18 """,
19]
20from = "now-9m"
21index = ["logs-endpoint.events.process*"]
22language = "eql"
23license = "Elastic License v2"
24name = "Suspicious Command Execution via Web Server"
25note = """ ## Triage and analysis
26
27> **Disclaimer**:
28> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.
29
30### Investigating Suspicious Command Execution via Web Server
31
32This alert fires when a Linux web server launches a shell to run commands that look like exploitation activity, such as discovery, credential access, payload decoding, or reverse shell setup. That matters because web servers rarely need to spawn shell commands, so this behavior often signals command injection, a dropped web shell, or attacker persistence. A common pattern is an app exploit causing php-fpm or nginx to run `sh -c 'id; cat /etc/passwd; curl ... | bash'` from `/tmp`.
33
34### Possible investigation steps
35
36- Review the full process ancestry and execution context to determine what application component invoked the shell, which service account ran it, what working directory and environment it used, and whether the command aligns with any documented application behavior.
37- Correlate the execution time with web server access, error, and application logs to identify the triggering request, including source IP, requested URI, parameters, headers, authenticated user or session, and any indications of command injection or direct web shell access.
38- Inspect recently created or modified files in the web root and writable locations such as upload, cache, temp, and shared-memory directories for dropped scripts, encoded payloads, cron changes, SSH key additions, or other persistence artifacts tied to the command.
39- Scope for follow-on activity by pivoting on the source IP, command fragments, spawned children, outbound connections, and similar executions on other web servers to determine whether exploitation was successful, repeated, or part of a broader campaign.
40- If the activity is unauthorized or cannot be explained, isolate the host, preserve relevant volatile and disk evidence, rotate secrets accessible to the web service, and remediate the vulnerable application or remove any discovered web shell before restoring service.
41
42### False positive analysis
43
44- A legitimate web administration or diagnostics function may invoke `sh -c` to run commands such as `id`, `whoami`, `hostname`, or read OS metadata for status pages; verify the command matches documented application behavior and correlate it to an authorized request in web or application logs.
45- A normal application workflow may use the web server to unpack user uploads or stage temporary content under `/tmp`, `/var/tmp`, or `/dev/shm` during import, conversion, or update operations; verify the execution aligns with a known user action or scheduled maintenance window and that the created files are expected temporary artifacts owned by the service account.
46
47### Response and remediation
48
49- Isolate the affected web server from the network or remove it from the load balancer immediately, preserve a forensic snapshot if possible, and block the attacker-controlled IPs, domains, and downloaded payload locations observed in the command chain.
50- Hunt for and remove persistence by deleting web shells and dropped scripts in the document root, uploads, `/tmp`, `/var/tmp`, and `/dev/shm`, and by cleaning unauthorized cron entries, systemd services, startup scripts, SSH `authorized_keys`, and any attacker-created local accounts.
51- Reset trust on the host by rotating application secrets, database passwords, API tokens, cloud credentials, and SSH keys that were present or reachable from the web server, and invalidate active sessions tied to the compromised application.
52- Rebuild or reimage the server from a known-good source, patch the exploited web application or server component, restore only validated content and configurations, and verify no unauthorized binaries, modified packages, or backdoored application files remain before returning it to service.
53- Escalate to incident response immediately if the shell command opened a reverse shell, downloaded or piped a payload into an interpreter, accessed sensitive files such as `/etc/shadow`, `.ssh`, or cloud credential stores, or if similar activity is found on additional hosts.
54- Harden the environment by removing unnecessary shell execution from the application, disabling write and execute permissions in web-accessible upload and temp paths, enforcing least privilege for the web service account, enabling WAF or virtual patching for the exploited weakness, and increasing monitoring on web roots and startup locations.
55"""
56risk_score = 47
57rule_id = "6148b9f5-5b12-4704-9ef7-f4b4c5dd9bb5"
58setup = """## Setup
59
60This rule requires data coming in from Elastic Defend.
61
62### Elastic Defend Integration Setup
63Elastic Defend is integrated into the Elastic Agent using Fleet. Upon configuration, the integration allows the Elastic Agent to monitor events on your host and send data to the Elastic Security app.
64
65#### Prerequisite Requirements:
66- Fleet is required for Elastic Defend.
67- To configure Fleet Server refer to the [documentation](https://www.elastic.co/guide/en/fleet/current/fleet-server.html).
68
69#### The following steps should be executed in order to add the Elastic Defend integration on a Linux System:
70- Go to the Kibana home page and click "Add integrations".
71- In the query bar, search for "Elastic Defend" and select the integration to see more details about it.
72- Click "Add Elastic Defend".
73- Configure the integration name and optionally add a description.
74- Select the type of environment you want to protect, either "Traditional Endpoints" or "Cloud Workloads".
75- Select a configuration preset. Each preset comes with different default settings for Elastic Agent, you can further customize these later by configuring the Elastic Defend integration policy. [Helper guide](https://www.elastic.co/guide/en/security/current/configure-endpoint-integration-policy.html).
76- We suggest selecting "Complete EDR (Endpoint Detection and Response)" as a configuration setting, that provides "All events; all preventions"
77- Enter a name for the agent policy in "New agent policy name". If other agent policies already exist, you can click the "Existing hosts" tab and select an existing policy instead.
78For more details on Elastic Agent configuration settings, refer to the [helper guide](https://www.elastic.co/guide/en/fleet/8.10/agent-policy.html).
79- Click "Save and Continue".
80- To complete the integration, select "Add Elastic Agent to your hosts" and continue to the next section to install the Elastic Agent on your hosts.
81For more details on Elastic Defend refer to the [helper guide](https://www.elastic.co/guide/en/security/current/install-endpoint.html).
82"""
83severity = "medium"
84tags = [
85 "Domain: Endpoint",
86 "OS: Linux",
87 "Use Case: Threat Detection",
88 "Tactic: Persistence",
89 "Tactic: Initial Access",
90 "Use Case: Vulnerability",
91 "Data Source: Elastic Defend",
92 "Resources: Investigation Guide",
93]
94timestamp_override = "event.ingested"
95type = "eql"
96query = '''
97process where host.os.type == "linux" and event.type == "start" and event.action == "exec" and (
98 process.parent.name in (
99 "nginx", "apache2", "httpd", "caddy", "mongrel_rails", "uwsgi", "daphne", "httpd.worker", "flask",
100 "php-cgi", "php-fcgi", "php-cgi.cagefs", "lswsctrl", "varnishd", "uvicorn", "waitress-serve", "starman",
101 "frankenphp", "zabbix_server", "asterisk", "sw-engine-fpm"
102 ) or
103 process.parent.name like ("php-fpm*", "gunicorn*", "*.cgi", "*.fcgi") or
104 (
105 process.parent.name like "ruby*" and
106 process.parent.command_line like~ ("*puma*", "*rails*", "*passenger*")
107 ) or
108 (
109 process.parent.name like "python*" and
110 process.parent.command_line like~ (
111 "*hypercorn*", "*flask*", "*uvicorn*", "*django*", "*app.py*", "*server.py*", "*wsgi.py*", "*asgi.py*"
112 )
113 ) or
114 (process.parent.name like "perl*" and process.parent.command_line like~ "*plackup*") or
115 (
116 process.parent.name == "java" and (
117 process.parent.args like~ (
118 /* Tomcat */
119 "org.apache.catalina.startup.Bootstrap", "-Dcatalina.base=*",
120
121 /* Jetty */
122 "org.eclipse.jetty.start.Main", "-Djetty.home=*",
123
124 /* WildFly / JBoss */
125 "org.jboss.modules.Main", "-Djboss.home.dir=*",
126
127 /* WebLogic */
128 "weblogic.Server", "-Dweblogic.Name=*", "*weblogic-launcher.jar*",
129
130 /* WebSphere traditional + Liberty */
131 "com.ibm.ws.runtime.WsServer", "com.ibm.ws.kernel.boot.cmdline.Bootstrap",
132
133 /* GlassFish */
134 "com.sun.enterprise.glassfish.bootstrap.ASMain",
135
136 /* Resin */
137 "com.caucho.server.resin.Resin",
138
139 /* Spring Boot */
140 "org.springframework.boot.loader.*",
141
142 /* Quarkus */
143 "*quarkus-run.jar*", "io.quarkus.runner.GeneratedMain",
144
145 /* Micronaut */
146 "io.micronaut.runtime.Micronaut",
147
148 /* Dropwizard */
149 "io.dropwizard.cli.ServerCommand",
150
151 /* Play */
152 "play.core.server.ProdServerStart",
153
154 /* Helidon */
155 "io.helidon.microprofile.server.Main", "io.helidon.webserver*",
156
157 /* Vert.x */
158 "io.vertx.core.Launcher",
159
160 /* Keycloak */
161 "org.keycloak*",
162
163 /* Apereo CAS */
164 "org.apereo.cas*",
165
166 /* Elasticsearch */
167 "org.elasticsearch.bootstrap.Elasticsearch",
168
169 /* Atlassian / Gerrit */
170 "com.atlassian.jira.startup.Launcher", "*BitbucketServerLauncher*", "com.google.gerrit.pgm.Daemon",
171
172 /* Solr */
173 "*-Dsolr.solr.home=*",
174
175 /* Jenkins */
176 "*jenkins.war*"
177 ) or
178 ?process.working_directory like "/u0?/*"
179 )
180 )
181) and
182process.name in ("bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "mksh", "busybox") and
183process.args in ("-c", "-cl", "-lc") and (
184 process.command_line like~ (
185
186 /* Suspicious Paths */
187 "* /tmp/* ", "* /var/tmp/* ", "* /dev/shm/*", "* /run/*", "* /var/run/*",
188
189 /* Encoding, Decoding & Piping */
190 "*|sh", "*| sh *", "*| sh ", "*|bash*", "*| bash*", "*|zsh*", "*| zsh*", "*|dash*", "*| dash*",
191 "*|python*", "*| python*", "*|php*", "*| php*", "*|perl*", "*| perl*", "*|ruby*", "*| ruby*",
192 "*|node*", "*| node*", "*|lua*", "*| lua*", "*|busybox*", "*| busybox*", "*|*base64 -d*", "*|*base64 --decode*",
193 "*|*base64 --decode*", "*|*openssl base64 -d*", "*xxd *", "*| openssl*enc * -d *", "*b64decode -r*",
194
195 /* Interpreter Execution */
196 "*python -c*", "*python3 -c*", "*php -r*", "*perl -e*", "*ruby -e*", "*lua -e*", "*node -e *",
197
198 /* Reverse Shells */
199 "*netcat *", "* nc *", "*ncat *", "*/dev/tcp*", "*/dev/udp/*", "*socat *", "*openssl*s_client *", "*stty*raw*-echo*",
200 "*mkfifo /tmp/*",
201
202 /* File Access */
203 "*>*/etc/cron*", "*crontab*", "*/etc/ssh*", "*/home/*/.ssh/*", "*/root/.ssh*", "*~/.ssh/*", "*/etc/shadow*",
204 "*/etc/passwd*", "*/etc/master.passwd*",
205
206 /* Enumeration & Discovery */
207 "*/etc/hosts*", "*/etc/resolv.conf*", "*/etc/hostname*", "*/etc/issue*", "*/etc/os-release*", "*lsb_release*",
208 "*/proc/*/environ*", "*sudo -l*", "*/proc/*/cgroup*", "*dockerenv*", "*/proc/*/mountinfo*", "*printenv*",
209 "*cat*.env *", "*getcap*", "*capsh*", "*find / *", "*netstat *",
210
211 /* AWS Credentials */
212 "*aws_access_key_id*", "*aws_secret_access_key*", "*aws_session_token*", "*accesskeyid*", "*secretaccesskey*",
213 "*.aws/credentials*", "*/.aws/config*",
214
215 /* Azure Credentials */
216 "*AZURE_CLIENT_ID*", "*AZURE_TENANT_ID*", "*AZURE_CLIENT_SECRET*", "*AZURE_FEDERATED_TOKEN_FILE*",
217 "*IDENTITY_ENDPOINT*", "*IDENTITY_HEADER*", "*MSI_ENDPOINT*", "*MSI_SECRET*", "*/.azure/*",
218 "*/run/secrets/azure/*",
219
220 /* GCP Credentials */
221 "*/.config/gcloud/*", "*application_default_credentials.json*", "*type: service_account*",
222 "*client_email*", "*private_key_id*", "*/run/secrets/google/*", "*GOOGLE_APPLICATION_CREDENTIALS*",
223
224 /* Misc. Cloud */
225 "*/.docker/config.json*", "*/.npmrc*", "*/secrets/kubernetes.io/serviceaccount/*",
226
227 /* Helpers */
228 "*timeout *sh -c *", "*env *sh *-c*", "*exec -a*",
229
230 /* Miscellaneous */
231 "*chattr *", "*busybox *", "*#!*", "*chmod +x *", "*chmod 777*", "*chpasswd*",
232 "*<?php*?>*", "*kworker*",
233
234 /* Decompression */
235 "*gzip -*d *", "*bzip2 -*d *", "*xz -*d *", "*tar -*x*",
236
237 /* Path Traversal */
238 "*../../../*etc/*", "*/.../*", "*../../../*home/*/*", "*../../../*root/*",
239
240 /* File Upload/Download */
241 "*pastebin.com*", "*transfer.sh*", "*bashupload.com*",
242
243 /* Enumeration & Discovery */
244 "* id *", "* whoami *", "* hostname *"
245 ) or
246 /* Keep this to not miss FNs due to spacing */
247 process.args in ("id", "whoami", "hostname")
248) and
249not (
250 (
251 process.parent.name == "nginx" and
252 process.args like ("chmod 777 /etc/resty-*", "resty*")
253 ) or
254 (
255 process.parent.name == "apache2" and (
256 process.command_line in (
257 "sh -c /usr/local/bin/php -r 'echo phpversion();'", "sh -c -- /usr/local/bin/php -r 'echo phpversion();'",
258 "sh -c /usr/bin/php -r 'echo phpversion();'",
259 "sh -c /usr/bin/lsb_release -a 2>/dev/null"
260 ) or
261 process.args like (
262 """bash -c "( /home/*/apps/richdocumentscode/collabora/Collabora_Online.AppImage*""",
263 "chmod 777 /etc/cobra/uploads/mysql*", "stat*"
264 ) or
265 process.command_line like (
266 "*/usr/bin/crontab*phpupdatecrontab.txt", "*mysqldump*/var/www/html/*/writable/uploads/backup/mysql*",
267 "sh -c chmod 777 -R /opt/data/www/php_upload/*/temp"
268 )
269 )
270 ) or
271 (
272 process.parent.name like "php-fpm*" and (
273 process.command_line in (
274 "sh -c /usr/bin/php -r 'echo phpversion();'", "sh -c -- /usr/bin/php -r 'echo phpversion();'",
275 "sh -c php -r 'print_r(phpversion());'", "sh -c chattr -i -a /usr/local/virtualizor/license2.php",
276 "sh -c source /etc/os-release 2>/dev/null && echo $ID $ID_LIKE",
277 "sh -c php -r \"echo date('T');\"",
278 "sh -c php -r \"echo PHP_VERSION;\""
279 ) or
280 process.command_line like (
281 "*var_export*extension_loaded*", "*/tmp/tmp_resize*", "*/v1/objects/hosts/*_Infoterminal*", "*python -m json.tool*",
282 "sh -c timeout 3600 ssh -o ControlMaster=auto -o ControlPath=/var/www/html/storage/app/ssh/mux/*"
283 ) or
284 process.args like ("ps*|*grep*", "ffmpeg*")
285 )
286 ) or
287 (
288 process.parent.name == "php-cgi" and (
289 process.command_line like (
290 "sh -c nohup php /home/*/public_html/lockindex.php index.php >/dev/null 2>&1 &",
291 "sh -c nohup php /home/*/public_html/wp-content/* >> /dev/null 2>&1 &",
292 "sh -c nohup php /home/*/public_html/wp-includes/* >> /dev/null 2>&1 &",
293 "sh -c nohup php /home/*/public_html/*/wp-content/* >> /dev/null 2>&1 &",
294 "*-ef|grep*"
295 ) or
296 process.args like "ps*| grep*"
297 )
298 ) or
299 (
300 process.command_line == "/bin/sh -c echo | openssl s_client -connect localhost:61617 2>/dev/null | openssl x509 -noout -enddate" and
301 process.parent.name == "gunicorn"
302 ) or
303 (
304 process.parent.executable == "/usr/local/bin/gunicorn" and
305 process.command_line == "/bin/sh -c echo 'Q' | openssl s_client -connect localhost:61617 2>/dev/null | openssl x509 -noout -enddate"
306 ) or
307 (
308 process.parent.executable == "/opt/bitnami/apache/bin/httpd" and
309 process.command_line == "sh -c /opt/bitnami/php/bin/php -r 'echo phpversion();'"
310 ) or
311 (
312 process.parent.executable like "/var/lib/containers/storage/overlay/*/merged/usr/local/sbin/php-fpm" and
313 process.command_line == "sh -c /usr/local/bin/php -r 'echo phpversion();'"
314 ) or
315 (
316 process.parent.executable like "/var/lib/docker/overlay2/*/merged/usr/sbin/uwsgi" and
317 process.command_line == "/bin/sh -c { touch /run/uwsgi-logrotate }"
318 ) or
319 (process.parent.name like "python*" and process.parent.command_line like "*hive_server.py*") or
320 (process.parent.name == "sw-engine-fpm" and process.command_line like ("*/opt/psa/admin/bin/*", "*/usr/local/psa/admin/*")) or
321 (process.parent.name == "httpd" and process.command_line like ("*/datastore/htdocs/control-states/compass*", "*/dev/shm/netmon-log*")) or
322 (process.parent.name == "asterisk" and process.args like "/bin/chmod 777 */gravacoes/*.WAV") or
323 (process.parent.name == "nginx" and process.command_line like "sh -c gcc -print-multiarch 2>/dev/null > /tmp/lua_*") or
324 (process.parent.name == "varnishd" and process.args like "exec gcc*") or
325 (process.parent.name == "zabbix_server" and process.command_line like "*/usr/sbin/sendmail*") or
326 (process.parent.executable == "/opt/morpheus/embedded/java/jre/bin/java" and process.command_line like "*morpheus-local*") or
327 (
328 process.parent.name == "ruby" and
329 process.command_line in (
330 "sh -c echo \"^d\" | openssl s_client -connect 127.0.0.1:443 2>&1",
331 "sh -c cat /etc/hosts.allow 2>/dev/null"
332 )
333 ) or
334 (process.parent.name == "java" and process.args like "chmod 777 *.csv") or
335 process.command_line == "sh -c node -v || nodejs -v" or
336 process.working_directory == "/var/lib/puppet/rack/puppetmasterd"
337)
338'''
339
340[[rule.threat]]
341framework = "MITRE ATT&CK"
342
343[[rule.threat.technique]]
344id = "T1505"
345name = "Server Software Component"
346reference = "https://attack.mitre.org/techniques/T1505/"
347
348[[rule.threat.technique.subtechnique]]
349id = "T1505.003"
350name = "Web Shell"
351reference = "https://attack.mitre.org/techniques/T1505/003/"
352
353[rule.threat.tactic]
354id = "TA0003"
355name = "Persistence"
356reference = "https://attack.mitre.org/tactics/TA0003/"
357
358[[rule.threat]]
359framework = "MITRE ATT&CK"
360
361[[rule.threat.technique]]
362id = "T1190"
363name = "Exploit Public-Facing Application"
364reference = "https://attack.mitre.org/techniques/T1190/"
365
366[rule.threat.tactic]
367id = "TA0001"
368name = "Initial Access"
369reference = "https://attack.mitre.org/tactics/TA0001/"
370
371[[rule.threat]]
372framework = "MITRE ATT&CK"
373
374[[rule.threat.technique]]
375id = "T1059"
376name = "Command and Scripting Interpreter"
377reference = "https://attack.mitre.org/techniques/T1059/"
378
379[rule.threat.tactic]
380id = "TA0002"
381name = "Execution"
382reference = "https://attack.mitre.org/tactics/TA0002/"
Triage and analysis
Disclaimer: This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.
Investigating Suspicious Command Execution via Web Server
This alert fires when a Linux web server launches a shell to run commands that look like exploitation activity, such as discovery, credential access, payload decoding, or reverse shell setup. That matters because web servers rarely need to spawn shell commands, so this behavior often signals command injection, a dropped web shell, or attacker persistence. A common pattern is an app exploit causing php-fpm or nginx to run sh -c 'id; cat /etc/passwd; curl ... | bash' from /tmp.
Possible investigation steps
- Review the full process ancestry and execution context to determine what application component invoked the shell, which service account ran it, what working directory and environment it used, and whether the command aligns with any documented application behavior.
- Correlate the execution time with web server access, error, and application logs to identify the triggering request, including source IP, requested URI, parameters, headers, authenticated user or session, and any indications of command injection or direct web shell access.
- Inspect recently created or modified files in the web root and writable locations such as upload, cache, temp, and shared-memory directories for dropped scripts, encoded payloads, cron changes, SSH key additions, or other persistence artifacts tied to the command.
- Scope for follow-on activity by pivoting on the source IP, command fragments, spawned children, outbound connections, and similar executions on other web servers to determine whether exploitation was successful, repeated, or part of a broader campaign.
- If the activity is unauthorized or cannot be explained, isolate the host, preserve relevant volatile and disk evidence, rotate secrets accessible to the web service, and remediate the vulnerable application or remove any discovered web shell before restoring service.
False positive analysis
- A legitimate web administration or diagnostics function may invoke
sh -cto run commands such asid,whoami,hostname, or read OS metadata for status pages; verify the command matches documented application behavior and correlate it to an authorized request in web or application logs. - A normal application workflow may use the web server to unpack user uploads or stage temporary content under
/tmp,/var/tmp, or/dev/shmduring import, conversion, or update operations; verify the execution aligns with a known user action or scheduled maintenance window and that the created files are expected temporary artifacts owned by the service account.
Response and remediation
- Isolate the affected web server from the network or remove it from the load balancer immediately, preserve a forensic snapshot if possible, and block the attacker-controlled IPs, domains, and downloaded payload locations observed in the command chain.
- Hunt for and remove persistence by deleting web shells and dropped scripts in the document root, uploads,
/tmp,/var/tmp, and/dev/shm, and by cleaning unauthorized cron entries, systemd services, startup scripts, SSHauthorized_keys, and any attacker-created local accounts. - Reset trust on the host by rotating application secrets, database passwords, API tokens, cloud credentials, and SSH keys that were present or reachable from the web server, and invalidate active sessions tied to the compromised application.
- Rebuild or reimage the server from a known-good source, patch the exploited web application or server component, restore only validated content and configurations, and verify no unauthorized binaries, modified packages, or backdoored application files remain before returning it to service.
- Escalate to incident response immediately if the shell command opened a reverse shell, downloaded or piped a payload into an interpreter, accessed sensitive files such as
/etc/shadow,.ssh, or cloud credential stores, or if similar activity is found on additional hosts. - Harden the environment by removing unnecessary shell execution from the application, disabling write and execute permissions in web-accessible upload and temp paths, enforcing least privilege for the web service account, enabling WAF or virtual patching for the exploited weakness, and increasing monitoring on web roots and startup locations.
Related rules
- Suspicious Child Execution via Web Server
- Potential Webshell Deployed via Apache Struts CVE-2023-50164 Exploitation
- Initial Access via File Upload Followed by GET Request
- Potential Telnet Authentication Bypass (CVE-2026-24061)
- Unusual Child Execution via Web Server