Tool Enumeration Detected via Defend for Containers
This rule detects the enumeration of tools by the "which" command inside a container. The "which" command is used to list what tools are installed on a system, and may be used by an adversary to gain information about the container and the services running inside it.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2026/01/21"
3integration = ["cloud_defend"]
4maturity = "production"
5min_stack_comments = "Defend for Containers integration was re-introduced in 9.3.0"
6min_stack_version = "9.3.0"
7updated_date = "2026/01/27"
8
9[rule]
10author = ["Elastic"]
11description = """
12This rule detects the enumeration of tools by the "which" command inside a container. The "which" command is used to list
13what tools are installed on a system, and may be used by an adversary to gain information about the container and the services
14running inside it.
15"""
16false_positives = [
17 """
18 There is a potential for false positives if the "which" command is used for legitimate purposes,
19 such as debugging or troubleshooting. It is important to investigate any alerts generated by this rule to determine
20 if they are indicative of malicious activity or part of legitimate container activity.
21 """,
22]
23from = "now-6m"
24index = ["logs-cloud_defend.process*"]
25interval = "5m"
26language = "eql"
27license = "Elastic License v2"
28name = "Tool Enumeration Detected via Defend for Containers"
29note = """ ## Triage and analysis
30
31> **Disclaimer**:
32> 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.
33
34### Investigating Tool Enumeration Detected via Defend for Containers
35
36Detects interactive use of which inside a Linux container to list installed networking, container-control, compiler, and scanning utilities. Adversaries do this to quickly assess built-in tools for living-off-the-land actions like payload download, cluster manipulation, or reconnaissance without dropping new binaries. Example: after compromising a Kubernetes pod, an operator runs which curl wget kubectl nmap python to decide how to transfer data, interact with the API, or probe the network.
37
38### Possible investigation steps
39
40- Correlate Kubernetes audit logs to determine whether the pod was accessed via kubectl exec, attach, or an ephemeral container and to identify the requesting user, source IP, and user agent.
41- Review the container’s process tree and TTY session around the alert time to see if the same session subsequently executed the enumerated utilities or performed network reconnaissance or data transfer.
42- Analyze outbound network connections and DNS queries from the pod around the event to unfamiliar destinations or cluster control-plane endpoints and compare them against expected egress policy.
43- Inspect pod and container metadata (namespace, service account, image, node) and evaluate RBAC bindings and mounted secrets to gauge potential impact and access scope.
44- Confirm with the service owner whether this interactive container access aligns with an approved maintenance or debugging task and gather the corresponding change ticket or runbook reference.
45
46### False positive analysis
47
48- An engineer opens an interactive shell in a container for approved troubleshooting and runs which on utilities like curl, wget, kubectl, and python to confirm tool availability before debugging.
49- During routine post-deployment checks, an operator follows a runbook that uses which to verify paths for expected binaries such as openssl and gcc inside the container, resulting in a benign alert.
50
51### Response and remediation
52
53- Immediately terminate any active TTY/shell in the affected pod (namespace/name) and isolate it by applying a temporary deny-all NetworkPolicy and removing exec/attach permissions from its service account.
54- Delete the pod and any attached ephemeral debug container, redeploy from a known-good image, and rotate mounted secrets, cloud credentials, and the service account token present in the container.
55- Restore service from clean deployments and verify the workload behaves as expected by running smoke tests and confirming the pod’s outbound connections are limited to approved destinations and ports.
56- Escalate to the incident response team if the same session executed kubectl or docker, ran scanning tools such as nmap/masscan, accessed /var/run/secrets or changed RBAC, or connected to unfamiliar external IPs or the Kubernetes API server, and preserve evidence (container filesystem snapshot, shell history, Kubernetes audit logs, and node syslogs).
57- Harden by enforcing admission controls to block interactive kubectl exec/attach to production pods and requiring runAsNonRoot, a read-only root filesystem, and dropped Linux capabilities on this workload.
58- Reduce living-off-the-land options by rebuilding images to distroless/minimal and omitting utilities enumerated by which (curl, wget, nc, python, kubectl), and restrict egress with NetworkPolicies and service account RBAC to prevent cluster manipulation from inside containers.
59"""
60risk_score = 21
61rule_id = "b84264aa-37a3-49f8-8bbc-60acbe9d4f86"
62severity = "low"
63tags = [
64 "Data Source: Elastic Defend for Containers",
65 "Domain: Container",
66 "OS: Linux",
67 "Use Case: Threat Detection",
68 "Tactic: Discovery",
69 "Resources: Investigation Guide",
70]
71timestamp_override = "event.ingested"
72type = "eql"
73query = '''
74process where host.os.type == "linux" and event.type == "start" and event.action == "exec" and (
75 process.name == "which" or
76 (
77 /* Account for tools that execute utilities as a subprocess, in this case the target utility name will appear as a process arg */
78 process.name in ("bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "busybox") and
79 process.args in ("which", "/bin/which", "/usr/bin/which", "/usr/local/bin/which") and
80 /* default exclusion list to not FP on default multi-process commands */
81 not process.args in (
82 "man", "/bin/man", "/usr/bin/man", "/usr/local/bin/man",
83 "chmod", "/bin/chmod", "/usr/bin/chmod", "/usr/local/bin/chmod",
84 "chown", "/bin/chown", "/usr/bin/chown", "/usr/local/bin/chown"
85 )
86 )
87) and
88process.args in (
89
90 /* TCP IP */
91 "curl", "wget", "socat", "nc", "netcat", "ncat", "busybox", "python3", "python", "perl", "node", "openssl", "ruby", "lua",
92
93 /* networking */
94 "getent", "dig", "nslookup", "host", "ip", "tcpdump", "tshark",
95
96 /* container management */
97 "kubectl", "docker", "kubelet", "kube-proxy", "containerd", "systemd", "crictl",
98
99 /* compilation */
100 "gcc", "g++", "clang", "clang++", "cc", "c++", "c99", "c89", "cc1*", "musl-gcc", "musl-clang", "tcc", "zig", "ccache", "distcc", "make",
101
102 /* scanning */
103 "nmap", "zenmap", "nuclei", "netdiscover", "legion", "masscan", "zmap", "zgrab", "ngrep", "telnet", "mitmproxy", "zmap",
104 "masscan", "zgrab"
105) and
106process.interactive == true and container.id like "*"
107'''
108
109[[rule.threat]]
110framework = "MITRE ATT&CK"
111
112[[rule.threat.technique]]
113id = "T1518"
114name = "Software Discovery"
115reference = "https://attack.mitre.org/techniques/T1518/"
116
117[[rule.threat.technique]]
118id = "T1613"
119name = "Container and Resource Discovery"
120reference = "https://attack.mitre.org/techniques/T1613/"
121
122[rule.threat.tactic]
123id = "TA0007"
124name = "Discovery"
125reference = "https://attack.mitre.org/tactics/TA0007/"
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 Tool Enumeration Detected via Defend for Containers
Detects interactive use of which inside a Linux container to list installed networking, container-control, compiler, and scanning utilities. Adversaries do this to quickly assess built-in tools for living-off-the-land actions like payload download, cluster manipulation, or reconnaissance without dropping new binaries. Example: after compromising a Kubernetes pod, an operator runs which curl wget kubectl nmap python to decide how to transfer data, interact with the API, or probe the network.
Possible investigation steps
- Correlate Kubernetes audit logs to determine whether the pod was accessed via kubectl exec, attach, or an ephemeral container and to identify the requesting user, source IP, and user agent.
- Review the container’s process tree and TTY session around the alert time to see if the same session subsequently executed the enumerated utilities or performed network reconnaissance or data transfer.
- Analyze outbound network connections and DNS queries from the pod around the event to unfamiliar destinations or cluster control-plane endpoints and compare them against expected egress policy.
- Inspect pod and container metadata (namespace, service account, image, node) and evaluate RBAC bindings and mounted secrets to gauge potential impact and access scope.
- Confirm with the service owner whether this interactive container access aligns with an approved maintenance or debugging task and gather the corresponding change ticket or runbook reference.
False positive analysis
- An engineer opens an interactive shell in a container for approved troubleshooting and runs which on utilities like curl, wget, kubectl, and python to confirm tool availability before debugging.
- During routine post-deployment checks, an operator follows a runbook that uses which to verify paths for expected binaries such as openssl and gcc inside the container, resulting in a benign alert.
Response and remediation
- Immediately terminate any active TTY/shell in the affected pod (namespace/name) and isolate it by applying a temporary deny-all NetworkPolicy and removing exec/attach permissions from its service account.
- Delete the pod and any attached ephemeral debug container, redeploy from a known-good image, and rotate mounted secrets, cloud credentials, and the service account token present in the container.
- Restore service from clean deployments and verify the workload behaves as expected by running smoke tests and confirming the pod’s outbound connections are limited to approved destinations and ports.
- Escalate to the incident response team if the same session executed kubectl or docker, ran scanning tools such as nmap/masscan, accessed /var/run/secrets or changed RBAC, or connected to unfamiliar external IPs or the Kubernetes API server, and preserve evidence (container filesystem snapshot, shell history, Kubernetes audit logs, and node syslogs).
- Harden by enforcing admission controls to block interactive kubectl exec/attach to production pods and requiring runAsNonRoot, a read-only root filesystem, and dropped Linux capabilities on this workload.
- Reduce living-off-the-land options by rebuilding images to distroless/minimal and omitting utilities enumerated by which (curl, wget, nc, python, kubectl), and restrict egress with NetworkPolicies and service account RBAC to prevent cluster manipulation from inside containers.
Related rules
- DNS Enumeration Detected via Defend for Containers
- Direct Interactive Kubernetes API Request Detected via Defend for Containers
- Direct Interactive Kubernetes API Request by Common Utilities
- Direct Interactive Kubernetes API Request by Unusual Utilities
- Environment Variable Enumeration Detected via Defend for Containers