Detection rules › Panther

Panther rules: ec2

AWS EC2 Discovery Commands Executed

#
Severity
informational
Tags
AWS, CloudTrail, EC2, Discovery, Cloud Service Discovery, Beta
Reference
stratus-red-team.cloud
Source
github.com/panther-labs/panther-analysis

Multiple different discovery commands were executed by the same EC2 instance. This could indicate a compromised instance.

MITRE ATT&CK coverage

TacticTechniques
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.

Alert deduplication
repeat matches within 90m group into one alert

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

#
Tags
AWS, CloudTrail, EC2, Discovery
Source
github.com/panther-labs/panther-analysis

Multiple different discovery commands were executed by the same EC2 instance.

MITRE ATT&CK coverage

TacticTechniques
DiscoveryNo 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

Table
panther_logs.public.aws_cloudtrail

Stage 2: filter

Window
90m

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.

Source
github.com/panther-labs/panther-analysis

This query searches for CRUD activity in EC2 by role arn. Activities from a role outside typical deployment processes may warrant investigation.

Telemetry coverage

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

Table
panther_logs.public.aws_cloudtrail

Stage 2: filter

  • eventSource is ec2.amazonaws.com
  • eventName matches the pattern *Image*
  • eventName does not match the pattern *Describe*
Grouped by
recipientAccountId, userIdentity:arn, eventName, eventSource
Window
3d

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
eventNamematchDescribeexcludes:eventName field:"eventName" value:"Describe"

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
num_logscount ( * )
recipientAccountId
arnuserIdentity: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.

Source
github.com/panther-labs/panther-analysis

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

Rules detecting the same action

These rules filter on the same operation.

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

Table
panther_logs.public.aws_cloudtrail

Stage 2: filter

  • eventSource is ec2.amazonaws.com
  • eventName matches the pattern *Image*
  • eventName does not match the pattern *Describe*
Grouped by
recipientAccountId, userAgent, eventName, eventSource
Window
3d

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
eventNamematchDescribeexcludes:eventName field:"eventName" value:"Describe"

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
num_logscount ( * )
recipientAccountId
userAgent
eventName
eventSource