Skip to content

Commit cea2f43

Browse files
terrancedejesusAegrahimays11SamirbousMikaayenson
authored
[New Rule] AWS EC2 LOLBin Execution via SSM (#5354)
* [New Rule] AWS EC2 LOLBin Execution via SSM Fixes #5353 * updated from command * removed high order tag * adjusted query logic * updated reference * add ESQL_priv. to keep * Update rules/cross-platform/execution_aws_ec2_lolbin_via_ssm.toml Co-authored-by: Ruben Groenewoud <[email protected]> * Update rules/cross-platform/execution_aws_ec2_lolbin_via_ssm.toml * cleaned up comments * updating query logic to use coalesce * Update rules/cross-platform/execution_aws_ec2_lolbin_via_ssm.toml Co-authored-by: Isai <[email protected]> * Update rules/cross-platform/execution_aws_ec2_lolbin_via_ssm.toml Co-authored-by: Samirbous <[email protected]> * Update rules/cross-platform/execution_aws_ec2_lolbin_via_ssm.toml * Update rules/cross-platform/execution_aws_ec2_lolbin_via_ssm.toml Co-authored-by: Mika Ayenson, PhD <[email protected]> * added SSM tag --------- Co-authored-by: Ruben Groenewoud <[email protected]> Co-authored-by: Isai <[email protected]> Co-authored-by: Samirbous <[email protected]> Co-authored-by: Mika Ayenson, PhD <[email protected]>
1 parent f40a383 commit cea2f43

File tree

1 file changed

+250
-0
lines changed

1 file changed

+250
-0
lines changed
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
[metadata]
2+
creation_date = "2025/11/23"
3+
integration = ["aws", "endpoint"]
4+
maturity = "production"
5+
updated_date = "2025/11/23"
6+
7+
[rule]
8+
author = ["Elastic"]
9+
description = """
10+
Identifies the execution of Living Off the Land Binaries (LOLBins) or GTFOBins on EC2 instances via AWS Systems Manager
11+
(SSM) `SendCommand` API. This detection correlates AWS CloudTrail `SendCommand` events with endpoint process execution
12+
by matching SSM command IDs. While AWS redacts command parameters in CloudTrail logs, this correlation technique reveals
13+
the actual commands executed on EC2 instances. Adversaries may abuse SSM to execute malicious commands remotely without
14+
requiring SSH or RDP access, using legitimate system utilities for data exfiltration, establishing reverse shells, or
15+
lateral movement.
16+
"""
17+
false_positives = [
18+
"""
19+
Legitimate administrative tasks using SSM to run system utilities may trigger this rule. Review the command context,
20+
user identity, and timing to determine if the activity is authorized.
21+
""",
22+
"""
23+
Automated configuration management or monitoring scripts that use LOLBins via SSM for legitimate purposes. Consider
24+
excluding known automation accounts or specific command patterns.
25+
""",
26+
]
27+
from = "now-9m"
28+
interval = "8m"
29+
language = "esql"
30+
license = "Elastic License v2"
31+
name = "AWS EC2 LOLBin Execution via SSM SendCommand"
32+
note = """## Triage and analysis
33+
34+
### Investigating AWS EC2 LOLBin Execution via SSM SendCommand
35+
36+
AWS Systems Manager (SSM) enables remote command execution on EC2 instances without SSH/RDP access. While legitimate for administration, adversaries exploit this by running LOLBins—system utilities abused for malicious purposes like data theft or backdoors. This detection correlates CloudTrail API logs with endpoint telemetry using SSM command IDs, bypassing AWS's parameter redaction to reveal actual executed commands and identify suspicious activity.
37+
38+
This is an ESQL aggregation-based rule, thus all original event fields and detail may not be present in the alert. It is recommended to pivot into the raw events from both data sources for full context during investigation.
39+
40+
### Possible investigation steps
41+
42+
- Review the SSM command ID in the alert to track the full lifecycle of the command from initiation to execution across both CloudTrail and endpoint data
43+
- Examine the CloudTrail user identity, including the ARN and access key ID, to determine who initiated the SSM command and verify if the activity is authorized
44+
- Analyze the command lines of the executed LOLBins to understand what commands were run and assess their intent, looking for indicators of data exfiltration, reverse shells, or reconnaissance
45+
- Check the source IP address and user agent from the CloudTrail event to identify if the request came from an expected location or tool
46+
- Investigate the affected EC2 instances for other suspicious activities or signs of compromise during the same timeframe, including network connections and file modifications
47+
- Review the SSM shell process details to see the full context of what the SSM agent executed and identify the parent-child process relationships
48+
- Correlate the timing between the CloudTrail event and endpoint execution to ensure they occurred within the detection window and represent the same activity
49+
- Check if the same user identity or source IP has executed similar SSM commands on other EC2 instances in your environment
50+
51+
### False positive analysis
52+
53+
- Routine administrative scripts that use utilities like curl, wget, or python for legitimate configuration management should be documented and excluded by user identity or source IP
54+
- Automated monitoring tools that execute commands via SSM for health checks or data collection can be filtered by identifying their consistent patterns and access key IDs
55+
- DevOps CI/CD pipelines that deploy or test applications using SSM may trigger alerts; create exceptions based on known automation roles or specific command patterns
56+
- Security scanning tools that legitimately use SSM for vulnerability assessments should be allowlisted by their known IAM roles or source IPs
57+
- Scheduled maintenance tasks using LOLBins for backup, log rotation, or data synchronization can be excluded by command pattern matching or execution timing
58+
59+
### Response and remediation
60+
61+
- Immediately isolate the affected EC2 instance from the network to prevent further unauthorized command execution or lateral movement
62+
- Review AWS CloudTrail logs to identify the IAM user, role, or access key associated with the suspicious SSM command and revoke or rotate compromised credentials
63+
- Terminate any unauthorized processes identified on the endpoint that match the LOLBin execution patterns detected in the alert
64+
- Conduct a forensic analysis of the affected EC2 instance to identify any persistence mechanisms, backdoors, or data exfiltration indicators
65+
- Implement stricter IAM policies to limit SSM `SendCommand` permissions to only trusted users and roles, following the principle of least privilege
66+
- Enable multi-factor authentication (MFA) for IAM users with SSM execution privileges to reduce the risk of credential compromise
67+
- Review and update VPC security groups and network ACLs to restrict outbound traffic from EC2 instances to only necessary destinations, preventing data exfiltration
68+
- Escalate the incident to the security operations center (SOC) for further investigation and to determine if additional AWS resources or accounts have been compromised
69+
"""
70+
references = [
71+
"https://www.mitiga.io/blog/abusing-the-amazon-web-services-ssm-agent-as-a-remote-access-trojan",
72+
"https://www.kali.org/tools/pacu/",
73+
"https://www.100daysofredteam.com/p/ghost-in-the-cloud-abusing-aws-ssm",
74+
"https://hackingthe.cloud/aws/post_exploitation/run_shell_commands_on_ec2/",
75+
"https://gtfobins.github.io/",
76+
]
77+
risk_score = 47
78+
rule_id = "a8b3e2f0-8c7d-11ef-b4c6-f661ea17fbcd"
79+
severity = "medium"
80+
tags = [
81+
"Domain: Cloud",
82+
"Domain: Endpoint",
83+
"OS: Linux",
84+
"Use Case: Threat Detection",
85+
"Tactic: Execution",
86+
"Tactic: Command and Control",
87+
"Data Source: AWS",
88+
"Data Source: Amazon Web Services",
89+
"Data Source: AWS CloudTrail",
90+
"Data Source: AWS EC2",
91+
"Data Source: AWS SSM",
92+
"Data Source: AWS Systems Manager",
93+
"Data Source: Elastic Defend",
94+
"Resources: Investigation Guide",
95+
]
96+
timestamp_override = "event.ingested"
97+
type = "esql"
98+
99+
query = '''
100+
FROM logs-aws.cloudtrail*, logs-endpoint.events.process-* METADATA _id, _version, _index
101+
| WHERE
102+
// CloudTrail SSM SendCommand with AWS-RunShellScript
103+
(
104+
event.dataset == "aws.cloudtrail"
105+
AND event.action == "SendCommand"
106+
AND aws.cloudtrail.request_parameters LIKE "*documentName=AWS-RunShellScript*"
107+
)
108+
// Linux endpoint process events, prefiltered to SSM shell runner OR LOLBins/GTFOBins
109+
OR
110+
(
111+
event.dataset == "endpoint.events.process"
112+
AND host.os.type == "linux"
113+
AND (
114+
// SSM shell (_script.sh) runner
115+
process.command_line LIKE "%/document/orchestration/%/awsrunShellScript/%/_script.sh"
116+
// LOLBins / GTFOBins
117+
OR process.name IN (
118+
"base64",
119+
"curl",
120+
"wget",
121+
"openssl",
122+
"nc", "ncat", "netcat",
123+
"socat",
124+
"python", "python3",
125+
"perl",
126+
"php",
127+
"ruby",
128+
"ssh",
129+
"scp",
130+
"sftp",
131+
"rsync"
132+
)
133+
)
134+
)
135+
136+
// Endpoint leg: extract SSM command ID from parent command line
137+
| DISSECT process.parent.command_line
138+
"%{}/document/orchestration/%{Esql.process_parent_command_line_ssm_command_id}/%{}"
139+
140+
// CloudTrail leg: extract SSM command ID from response_elements
141+
| DISSECT aws.cloudtrail.response_elements
142+
"%{}commandId=%{Esql.aws_cloudtrail_response_elements_ssm_command_id},%{}"
143+
144+
// Coalesce SSM command ID from both data sources
145+
| EVAL Esql.aws_ssm_command_id = COALESCE(
146+
Esql.aws_cloudtrail_response_elements_ssm_command_id,
147+
Esql.process_parent_command_line_ssm_command_id
148+
)
149+
| WHERE Esql.aws_ssm_command_id IS NOT NULL
150+
151+
// Role flags
152+
| EVAL Esql.is_cloud_event = event.dataset == "aws.cloudtrail"
153+
| EVAL Esql.is_endpoint_event = event.dataset == "endpoint.events.process"
154+
155+
// Identify the SSM shell processes (the _script.sh runners)
156+
| EVAL Esql.is_ssm_shell_process =
157+
Esql.is_endpoint_event
158+
AND process.command_line LIKE "%/document/orchestration/%/awsrunShellScript/%/_script.sh"
159+
160+
// LOLBins / GTFOBins on Linux
161+
| EVAL Esql.is_lolbin_process =
162+
Esql.is_endpoint_event AND NOT Esql.is_ssm_shell_process
163+
164+
// Aggregate per SSM command ID
165+
| STATS
166+
// Core correlation counts & timing
167+
Esql.aws_cloudtrail_event_count = SUM(CASE(Esql.is_cloud_event, 1, 0)),
168+
Esql.endpoint_events_process_lolbin_count = SUM(CASE(Esql.is_lolbin_process, 1, 0)),
169+
Esql.endpoint_events_process_ssm_shell_count = SUM(CASE(Esql.is_ssm_shell_process, 1, 0)),
170+
Esql.aws_cloudtrail_first_event_ts = MIN(CASE(Esql.is_cloud_event, @timestamp, null)),
171+
Esql.endpoint_events_process_first_lolbin_ts = MIN(CASE(Esql.is_lolbin_process, @timestamp, null)),
172+
173+
// AWS / CloudTrail identity & request context
174+
Esql_priv.aws_cloudtrail_user_identity_arn_values =
175+
VALUES(CASE(Esql.is_cloud_event, aws.cloudtrail.user_identity.arn, null)),
176+
Esql_priv.aws_cloudtrail_user_identity_access_key_id_values =
177+
VALUES(CASE(Esql.is_cloud_event, aws.cloudtrail.user_identity.access_key_id, null)),
178+
Esql_priv.user_name_values =
179+
VALUES(CASE(Esql.is_cloud_event, user.name, null)),
180+
181+
// AWS environment / request metadata
182+
Esql.cloud_region_values = VALUES(CASE(Esql.is_cloud_event, cloud.region, null)),
183+
Esql.source_ip_values = VALUES(CASE(Esql.is_cloud_event, source.ip, null)),
184+
Esql.user_agent_original_values =
185+
VALUES(CASE(Esql.is_cloud_event, user_agent.original, null)),
186+
187+
// Endpoint host & user context
188+
Esql.host_name_values = VALUES(CASE(Esql.is_endpoint_event, host.name, null)),
189+
Esql_priv.endpoint_user_name_values =
190+
VALUES(CASE(Esql.is_endpoint_event, user.name, null)),
191+
192+
// SSM shell processes on endpoint
193+
Esql.process_command_line_ssm_shell_values =
194+
VALUES(CASE(Esql.is_ssm_shell_process, process.command_line, null)),
195+
Esql.process_pid_ssm_shell_values =
196+
VALUES(CASE(Esql.is_ssm_shell_process, process.pid, null)),
197+
198+
// LOLBin processes on endpoint
199+
Esql.process_name_lolbin_values =
200+
VALUES(CASE(Esql.is_lolbin_process, process.name, null)),
201+
Esql.process_executable_lolbin_values =
202+
VALUES(CASE(Esql.is_lolbin_process, process.executable, null)),
203+
Esql.process_command_line_lolbin_values =
204+
VALUES(CASE(Esql.is_lolbin_process, process.command_line, null)),
205+
Esql.process_pid_lolbin_values =
206+
VALUES(CASE(Esql.is_lolbin_process, process.pid, null)),
207+
Esql.process_parent_command_line_lolbin_values =
208+
VALUES(CASE(Esql.is_lolbin_process, process.parent.command_line, null)),
209+
210+
Esql.data_stream_namespace_values = VALUES(data_stream.namespace)
211+
BY Esql.aws_ssm_command_id
212+
213+
// Detection condition: SSM SendCommand + AWS-RunShellScript + LOLBin on endpoint
214+
| WHERE Esql.aws_cloudtrail_event_count > 0
215+
AND Esql.endpoint_events_process_lolbin_count > 0
216+
AND DATE_DIFF(
217+
"minutes",
218+
Esql.endpoint_events_process_first_lolbin_ts,
219+
Esql.aws_cloudtrail_first_event_ts
220+
) <= 5
221+
| SORT Esql.aws_cloudtrail_first_event_ts ASC
222+
| KEEP Esql.*, Esql_priv.*
223+
'''
224+
225+
226+
[[rule.threat]]
227+
framework = "MITRE ATT&CK"
228+
[[rule.threat.technique]]
229+
id = "T1651"
230+
name = "Cloud Administration Command"
231+
reference = "https://attack.mitre.org/techniques/T1651/"
232+
233+
234+
[rule.threat.tactic]
235+
id = "TA0002"
236+
name = "Execution"
237+
reference = "https://attack.mitre.org/tactics/TA0002/"
238+
[[rule.threat]]
239+
framework = "MITRE ATT&CK"
240+
[[rule.threat.technique]]
241+
id = "T1105"
242+
name = "Ingress Tool Transfer"
243+
reference = "https://attack.mitre.org/techniques/T1105/"
244+
245+
246+
[rule.threat.tactic]
247+
id = "TA0011"
248+
name = "Command and Control"
249+
reference = "https://attack.mitre.org/tactics/TA0011/"
250+

0 commit comments

Comments
 (0)