Detection: AWS EC2 Startup Script Modified on Stopped Instance

Description

A successful EC2 StopInstances request was followed within one hour by a successful ModifyInstanceAttribute request targeting userData on the same instance, by the same IAM principal. This may indicate an attempt to change instance startup behavior or establish persistence. These CloudTrail events do not confirm that the modified user-data script executed.

 1`cloudtrail`
 2eventSource="ec2.amazonaws.com"
 3eventName IN ("StopInstances", "ModifyInstanceAttribute")
 4
 5
 6| eval user_arn='userIdentity.arn'
 7
 8
 9| eval instance_id=case(
10    eventName="StopInstances", 'requestParameters.instancesSet.items{}.instanceId',
11    eventName="ModifyInstanceAttribute", 'requestParameters.instanceId'
12  )
13
14
15| mvexpand instance_id
16
17
18| where isnotnull(eventID) AND isnotnull(instance_id) AND isnotnull(user_arn)
19    AND (isnull(errorCode) OR errorCode="" OR lower(errorCode)="success")
20
21
22| where eventName="StopInstances"
23    OR (eventName="ModifyInstanceAttribute" AND 'requestParameters.attribute'="userData")
24
25
26| dedup eventID instance_id
27
28
29| eval event_epoch=coalesce(strptime(eventTime, "%Y-%m-%dT%H:%M:%SZ"), _time)
30
31
32| sort 0 user_arn instance_id awsRegion event_epoch
33
34
35| streamstats current=f
36    last(eval(if(eventName="StopInstances", event_epoch, null()))) AS stop_epoch
37    last(eval(if(eventName="StopInstances", eventID, null()))) AS stop_event_id
38    BY user_arn instance_id awsRegion
39
40
41| where eventName="ModifyInstanceAttribute" AND isnotnull(stop_epoch)
42
43
44| eval elapsed_seconds=event_epoch-stop_epoch
45
46
47| where elapsed_seconds>0 AND elapsed_seconds<=3600
48
49
50| eval stop_time_utc=strftime(stop_epoch, "%Y-%m-%dT%H:%M:%SZ")
51
52
53| eval modification_time_utc=strftime(event_epoch, "%Y-%m-%dT%H:%M:%SZ")
54
55
56| rename eventID AS modification_event_id
57
58
59| table user_arn instance_id awsRegion stop_time_utc modification_time_utc
60        elapsed_seconds stop_event_id modification_event_id
61
62
63| `aws_ec2_startup_script_modified_on_stopped_instance_filter`

Data Source

Name Platform Sourcetype Source
AWS CloudTrail AWS icon AWS 'aws:cloudtrail' 'aws_cloudtrail'

Macros Used

Name Value
cloudtrail sourcetype=aws:cloudtrail
aws_ec2_startup_script_modified_on_stopped_instance_filter search *
aws_ec2_startup_script_modified_on_stopped_instance_filter is an empty macro by default. It allows the user to filter out any results (false positives) without editing the SPL.

Annotations

- MITRE ATT&CK
+ Kill Chain Phases
+ NIST
+ CIS
- Threat Actors
ID Technique Tactic
T1578.005 Modify Cloud Compute Configurations Defense Impairment
Exploitation
DE.CM
CIS 10

Default Configuration

This detection is configured by default in Splunk Enterprise Security to run with the following settings:

Setting Value
Disabled true
Cron Schedule 0 * * * *
Earliest Time -70m@m
Latest Time -10m@m
Schedule Window auto
Creates Finding (Notable) Yes
Rule Title %name%
Rule Description %description%
Notable Event Fields user, dest
Creates Intermediate Finding (Risk Event) No
TTP detections generate a Finding (Notable) and may generate Intermediate Findings (Risk Events) for associated entities.

Implementation

You must install Splunk AWS Add on and enable CloudTrail logs in your AWS Environment.

Known False Positives

Authorized administrators and infrastructure automation may stop instances and update their user data. Review the IAM principal, instance, change window, and approved automation before escalating.

Associated Analytic Story

Finding

Title Entity Field Entity Type Risk Score
The IAM principal [$user_arn$] modified user data on stopped EC2 instance [$instance_id$] user_arn user 50

References

Detection Testing

Test Type Status Dataset Source Sourcetype
Validation ✅ Passing N/A N/A N/A
Unit ✅ Passing Dataset aws_cloudtrail aws:cloudtrail
Integration ✅ Passing Dataset aws_cloudtrail aws:cloudtrail

Replay any dataset to Splunk Enterprise by using our replay.py tool or the UI. Alternatively you can replay a dataset into a Splunk Attack Range


Source: GitHub |

Version: 1