Skip to content

[Rule Tuning] Potential Reverse Shell Activity via Terminal (a1a0375f-22c2-48c0-81a4-7c2d11cc6856) #5798

@tradebot-elastic

Description

@tradebot-elastic

Rule Tuning Analysis

Rule ID: a1a0375f-22c2-48c0-81a4-7c2d11cc6856
Rule Name: Potential Reverse Shell Activity via Terminal
Rule Type: eql


Classification

Metric Value
Category NOISY_PERFORMANT
Priority MEDIUM
Tuning Score 60.83
Version Status ✅ Established (37 release cycles)

Alert Telemetry

Metric Value
Total Alerts (3d) 25,074
Unique Clusters 5
Cluster Coverage 0.2%
Daily Average 8358
Days Active 3
Coefficient of Variation 0.49 (MODERATE)

Analysis Flags

  • 🔴 Noisy on Latest Version: ✅ Yes
  • 🔴 Widespread False Positive: ❌ No
  • ⚠️ Version Regression: ❌ No
  • ⚠️ Stale and Noisy: ❌ No
  • ⚠️ Low Version / High Volume: ❌ No
  • ℹ️ Low Activity: ❌ No

Recommendation

Action: Add args-based loopback exclusions and a narrow timeout + echo > /dev/tcp health-check exclusion to reduce recurring benign alerts while keeping reverse-shell redirect patterns detectable.

Rationale: The rule is firing at very high volume in a small set of clusters, largely driven by benign service/port-check patterns that use bash’s /dev/tcp feature (e.g., timeout ... bash -c echo > /dev/tcp/<host>/<port>) and by loopback (/127.0.0.1) usage that is not consistently excluded when process.command_line is missing (common in some system module events). The best tuning is to (1) add args-based loopback exclusions and (2) narrowly exclude the common timeout + echo > /dev/tcp health-check pattern, while preserving true reverse-shell-style redirects like exec >&/dev/tcp/... seen in the samples.

Query Modifications

Loopback exclusions do not apply when process.command_line is missing, causing recurring false positives for /dev/tcp/127.0.0.1/... events. (Impact: accuracy)

Current:

not process.command_line : (
  "*/dev/tcp/127.*", "*/dev/udp/127.*", "*/dev/tcp/localhost/*", ...
)

Modify →

/* cover datasets where command_line is absent */
and not process.args : (
  "/dev/tcp/127.*", "/dev/udp/127.*", "/dev/tcp/localhost/*"
) and
not process.command_line : (
  "*/dev/tcp/127.*", "*/dev/udp/127.*", "*/dev/tcp/localhost/*", ...
)

Sample Events 3–4 demonstrate /dev/tcp/127.0.0.1/4444 triggering without a populated process.command_line. Adding args-based exclusions eliminates those benign/local-test hits without weakening detection for non-loopback reverse shell patterns.

High-volume benign health checks using timeout ... bash -c echo > /dev/tcp/... are not excluded and can dominate alert volume. (Impact: accuracy)

Current:

not (process.parent.name : "timeout" and process.executable : "/var/lib/docker/overlay*")

Modify →

/* keep existing docker-overlay suppression */
not (process.parent.name : "timeout" and process.executable : "/var/lib/docker/overlay*") and
/* add narrow timeout+echo>/dev/tcp suppression */
not (
  process.parent.name == "timeout" and
  (
    process.command_line : ("*echo > /dev/tcp/*/*", "*echo >/dev/tcp/*/*") or
    process.parent.command_line : ("*echo > /dev/tcp/*/*", "*echo >/dev/tcp/*/*")
  )
)

Sample Event 5 is consistent with benign service checks (Consul port 8301). The suggested pattern is narrow (requires timeout plus echo redirection into /dev/tcp) and preserves detection for reverse-shell-style redirects like exec >&/dev/tcp/... seen in Sample Events 1–2.

Exception Recommendations

Add exception: process.args wildcard "/dev/tcp/127.*" (Confidence: HIGH)

Evidence: Sample Event 3 executes bash with args including /dev/tcp/127.0.0.1/4444 and lacks process.command_line, so the rule’s current not process.command_line : "*/dev/tcp/127.*" does not apply. Add an args-based exclusion to cover these events. Copy/paste-ready EQL addition:
and not process.args : ("/dev/tcp/127.*", "/dev/udp/127.*")

Modify →

and process.args wildcard "/dev/tcp/127.*"

Add exception: process.args wildcard "/dev/tcp/localhost/*" (Confidence: MEDIUM)

Evidence: The rule already excludes */dev/tcp/localhost/* via process.command_line, but events that only have process.args will bypass that exclusion similarly to the loopback sample (Events 3–4). Add localhost to the same args-based exclusion set. Copy/paste-ready EQL addition:
and not process.args : ("/dev/tcp/localhost/*")

Modify →

and process.args wildcard "/dev/tcp/localhost/*"

Add exception: process.parent.name is "timeout" (Confidence: MEDIUM)

Evidence: Sample Event 5 is a classic health/port check: parent is timeout and child runs bash -c echo > /dev/tcp/nbg1-c1-infra-consul-31.sun-one.org/8301. Excluding all timeout parents would be risky, so implement as a compound exception with an echo > /dev/tcp condition (see next recommendation). Compound, copy/paste-ready EQL block:
and not (process.parent.name == "timeout" and (process.command_line : ("*echo > /dev/tcp/*/*", "*echo >/dev/tcp/*/*") or process.parent.command_line : ("*echo > /dev/tcp/*/*", "*echo >/dev/tcp/*/*")))

Modify →

and process.parent.name is "timeout"

Add exception: process.command_line wildcard "*echo > /dev/tcp/*/*" (Confidence: MEDIUM)

Evidence: Sample Event 5 uses bash -c echo > /dev/tcp/<host>/<port>, which is typical of benign connectivity checks and very frequently scheduled. This should be used ONLY together with the process.parent.name == "timeout" condition to avoid suppressing other contexts. Include both spacing variants (echo > and echo > without space before redirection). Copy/paste-ready EQL (paired with timeout):
and not (process.parent.name == "timeout" and process.command_line : ("*echo > /dev/tcp/*/*", "*echo >/dev/tcp/*/*"))

Modify →

and process.command_line wildcard "*echo > /dev/tcp/*/*"

Field-Level Recommendations

Field Value Alert % Cluster % Confidence Type
process.args /dev/tcp/127.* 0.0% 40.0% HIGH EXCEPTION
process.args /dev/tcp/localhost/* 0.0% 20.0% MEDIUM EXCEPTION
process.parent.name timeout 0.0% 60.0% MEDIUM EXCEPTION
process.command_line *echo > /dev/tcp/*/* 0.0% 60.0% MEDIUM EXCEPTION

This issue was generated by the GenAI Tradecraft Rule Tuning Advisor.
Analysis timestamp: 2026-02-28T06:11:26.377746

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions