Detection rules › Panther
Panther rules: ec2
| Rule | Severity |
|---|---|
| AWS EC2 Discovery Commands Executed | informational |
| AWS EC2 Discovery Commands Executed | |
| Query.EC2.CRUD.Activity.Role | |
| Query.EC2.CRUD.Activity.Useragent |
AWS EC2 Discovery Commands Executed
#Multiple different discovery commands were executed by the same EC2 instance. This could indicate a compromised instance.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Discovery |
Detection logic
from panther_aws_helpers import aws_rule_context
from panther_core import PantherEvent
def rule(_):
return True
def title(event: PantherEvent):
account = event.get("recipientAccountId")
instance_id = event.deep_get("userIdentity", "arn").split("/")[-1]
return f"{account}: Multiple Discovery Commands Executed on EC2 Instance '{instance_id}'"
def alert_context(event: PantherEvent):
return aws_rule_context(event)
Rule specification
AnalysisType: scheduled_rule
Filename: ec2_discovery_commands.py
RuleID: "AWS.EC2.DiscoveryCommandsExecuted"
DisplayName: "AWS EC2 Discovery Commands Executed"
Enabled: true
ScheduledQueries:
- AWS EC2 Discovery Commands Executed
Severity: Info
Reports:
MITRE ATT&CK:
- TA0007:T1526 # Discoery: Cloud Service Discovery
Description: Multiple different discovery commands were executed by the same EC2 instance.
This could indicate a compromised instance.
DedupPeriodMinutes: 90
Reference:
https://stratus-red-team.cloud/attack-techniques/AWS/aws.discovery.ec2-enumerate-from-instance/
Runbook: Investigate other activity from the instance. Revoke permissions from the
instance until the credentials have been rotated. Determine who was accessing the
instance and monitor the account for other activity.
Tags:
- AWS
- CloudTrail
- EC2
- Discovery
- Cloud Service Discovery
- Beta
Stages and Predicates
Rule logic
This rule alerts on rows returned by its scheduled query AWS EC2 Discovery Commands Executed; its Python module (Detection logic above) shapes the alert rather than filtering.
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field |
|---|
eventName |
eventSource |
awsRegion |
recipientAccountId |
sourceIPAddress |
userAgent |
userIdentity |
Response runbook
Investigate other activity from the instance. Revoke permissions from the instance until the credentials have been rotated. Determine who was accessing the instance and monitor the account for other activity.
AWS EC2 Discovery Commands Executed
#Multiple different discovery commands were executed by the same EC2 instance.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Discovery | No specific technique |
Rule specification
AnalysisType: scheduled_query
QueryName: "AWS EC2 Discovery Commands Executed"
Enabled: false
Description: Multiple different discovery commands were executed by the same EC2 instance.
Tags:
- AWS
- CloudTrail
- EC2
- Discovery
SnowflakeQuery: |
select
*,
count(distinct eventName) over (partition by userIdentity:arn) nActions
from panther_logs.public.aws_cloudtrail
where p_occurs_since(90m)
and SPLIT_PART(userIdentity:arn, '/', -1) like 'i-%'
and ARRAY_CONTAINS(eventName, [
'GetCallerIdentity',
'ListBuckets',
'GetAccountSummary',
'ListRoles',
'ListUsers',
'GetAccountAuthorizationDetails',
'DescribeSnapshots',
'DescribeTrails',
'ListDetectors'
])
qualify nActions > 2
DatabricksQuery: |
SELECT * FROM (
SELECT
*,
count(distinct eventName) over (partition by userIdentity:arn) AS nActions
FROM panther_logs.aws_cloudtrail
WHERE p_occurs_since(90m)
AND ELEMENT_AT(SPLIT(userIdentity:arn, '/'), -1) LIKE 'i-%'
AND eventName IN (
'GetCallerIdentity',
'ListBuckets',
'GetAccountSummary',
'ListRoles',
'ListUsers',
'GetAccountAuthorizationDetails',
'DescribeSnapshots',
'DescribeTrails',
'ListDetectors'
)
) WHERE nActions > 2
Schedule:
RateMinutes: 60
TimeoutMinutes: 1
Stages and Predicates
Stage 1: source
Stage 2: filter
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field |
|---|
* |
count ( DISTINCT eventName ) OVER ( PARTITION BY userIdentity:arn ) nActions |
Query.EC2.CRUD.Activity.Role
#This is a threat-hunting query, not an automated detection. It surfaces activity for an analyst to review rather than firing on a match. It is searchable for reference but is excluded from the detection-rule browse and the ATT&CK coverage matrix.
This query searches for CRUD activity in EC2 by role arn. Activities from a role outside typical deployment processes may warrant investigation.
Telemetry coverage
| Platform | Record / event type |
|---|---|
| AWS | CloudTrail event any: Catch-all entry for EC2 rules that match the service but not a specific eventName. |
Rules detecting the same action
These rules filter on the same operation.
Rule specification
AnalysisType: scheduled_query
QueryName: "Query.EC2.CRUD.Activity.Role"
Enabled: false
Description: >
This query searches for CRUD activity in EC2 by role arn. Activities from a role outside typical deployment processes may warrant investigation.
SnowflakeQuery: |
SELECT
count(*) as num_logs,
recipientAccountId,
userIdentity:arn as arn,
eventName,
eventSource
FROM panther_logs.public.aws_cloudtrail
WHERE
eventSource = 'ec2.amazonaws.com'
AND eventName LIKE '%Image%'
AND eventName NOT LIKE '%Describe%'
AND p_occurs_since('3 day')
GROUP BY recipientAccountId, userIdentity:arn, eventName, eventSource
ORDER BY recipientAccountId, count(*)
DatabricksQuery: |
SELECT
count(*) as num_logs,
recipientAccountId,
userIdentity:arn as arn,
eventName,
eventSource
FROM panther_logs.aws_cloudtrail
WHERE
eventSource = 'ec2.amazonaws.com'
AND eventName LIKE '%Image%'
AND eventName NOT LIKE '%Describe%'
AND p_occurs_since('3 day')
GROUP BY recipientAccountId, userIdentity:arn, eventName, eventSource
ORDER BY recipientAccountId, count(*)
Schedule:
RateMinutes: 9999
TimeoutMinutes: 5
Stages and Predicates
Stage 1: source
Stage 2: filter
eventSourceisec2.amazonaws.comeventNamematches the pattern*Image*eventNamedoes not match the pattern*Describe*
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
eventName | match | Describe | excludes:eventName field:"eventName" value:"Describe" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
eventName | wildcard |
| field:"aws::eventName" kind:wildcard value:"*Image*" |
eventSource | eq |
| field:"aws::eventSource" kind:eq value:"ec2.amazonaws.com" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
num_logs | count ( * ) |
recipientAccountId | |
arn | userIdentity:arn |
eventName | |
eventSource |
Query.EC2.CRUD.Activity.Useragent
#This is a threat-hunting query, not an automated detection. It surfaces activity for an analyst to review rather than firing on a match. It is searchable for reference but is excluded from the detection-rule browse and the ATT&CK coverage matrix.
This query searches for CRUD activity in EC2 by userAgent. A low count or previously unseen useragent may indicate that the action was not performed by an automated process.
Telemetry coverage
| Platform | Record / event type |
|---|---|
| AWS | CloudTrail event any: Catch-all entry for EC2 rules that match the service but not a specific eventName. |
Rules detecting the same action
These rules filter on the same operation.
- AWS Discovery API Calls via CLI from a Single Resource (Elastic)
- Query.EC2.CRUD.Activity.Role (Panther)
- Sensitive API Calls Via VPC Endpoint (Panther)
Rule specification
AnalysisType: scheduled_query
QueryName: "Query.EC2.CRUD.Activity.Useragent"
Enabled: false
Description: >
This query searches for CRUD activity in EC2 by userAgent. A low count or previously unseen useragent may indicate that the action was not performed by an automated process.
SnowflakeQuery: |
SELECT
count(*) as num_logs,
recipientAccountId,
userAgent,
eventName,
eventSource
FROM panther_logs.public.aws_cloudtrail
WHERE
eventSource = 'ec2.amazonaws.com'
AND eventName LIKE '%Image%'
AND eventName NOT LIKE '%Describe%'
AND p_occurs_since('3 day')
GROUP BY recipientAccountId, userAgent, eventName, eventSource
ORDER BY recipientAccountId, count(*), userAgent
DatabricksQuery: |
SELECT
count(*) as num_logs,
recipientAccountId,
userAgent,
eventName,
eventSource
FROM panther_logs.aws_cloudtrail
WHERE
eventSource = 'ec2.amazonaws.com'
AND eventName LIKE '%Image%'
AND eventName NOT LIKE '%Describe%'
AND p_occurs_since('3 day')
GROUP BY recipientAccountId, userAgent, eventName, eventSource
ORDER BY recipientAccountId, count(*), userAgent
Schedule:
RateMinutes: 1440
TimeoutMinutes: 20
Stages and Predicates
Stage 1: source
Stage 2: filter
eventSourceisec2.amazonaws.comeventNamematches the pattern*Image*eventNamedoes not match the pattern*Describe*
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
eventName | match | Describe | excludes:eventName field:"eventName" value:"Describe" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
eventName | wildcard |
| field:"aws::eventName" kind:wildcard value:"*Image*" |
eventSource | eq |
| field:"aws::eventSource" kind:eq value:"ec2.amazonaws.com" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
num_logs | count ( * ) |
recipientAccountId | |
userAgent | |
eventName | |
eventSource |