Back
Id32555639-b639-4c2b-afda-c0ae0abefa55
RulenameAWSCloudTrail - Monitor AWS Credential abuse or hijacking
DescriptionIdentifies AWS STS `GetCallerIdentity` calls made by assumed-role sessions.

An attacker who has assumed the role of a legitimate account can call the GetCallerIdentity function to determine what account they are using.

A legitimate user using legitimate credentials would not need to call GetCallerIdentity since they should already know what account they are using.

More Information: https://duo.com/decipher/trailblazer-hunts-compromised-credentials-in-aws

AWS STS GetCallerIdentity API: https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html
SeverityLow
TacticsDiscovery
TechniquesT1580
Required data connectorsAWS
AWSS3
KindScheduled
Query frequency1d
Query period1d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Amazon%20Web%20Services/Analytic%20Rules/AWS_CredentialHijack.yaml
Version1.0.4
Arm template32555639-b639-4c2b-afda-c0ae0abefa55.json
Deploy To Azure
AWSCloudTrail
| where EventName =~ "GetCallerIdentity" and UserIdentityType =~ "AssumedRole"
| extend UserIdentityArn = iif(isempty(UserIdentityArn), tostring(parse_json(Resources)[0].ARN), UserIdentityArn)
| extend UserName = tostring(split(UserIdentityArn, '/')[-1])
| extend AccountName = case(UserIdentityPrincipalid == "Anonymous", "Anonymous", isempty(UserIdentityUserName), UserName, UserIdentityUserName)
| extend AccountName = iif(AccountName contains "@", tostring(split(AccountName, '@', 0)[0]), AccountName),
  AccountUPNSuffix = iif(AccountName contains "@", tostring(split(AccountName, '@', 1)[0]), "")
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by SourceIpAddress, EventName, EventTypeName, UserIdentityType, RecipientAccountId, AccountName, AccountUPNSuffix, UserIdentityAccountId, UserIdentityPrincipalid,
  UserAgent, UserIdentityUserName, SessionMfaAuthenticated, AWSRegion, EventSource, AdditionalEventData, ResponseElements
| extend timestamp = StartTime
| sort by EndTime desc nulls last
status: Available
queryPeriod: 1d
version: 1.0.4
severity: Low
customDetails:
  EventSource: EventSource
  EventName: EventName
  EventType: EventTypeName
  AWSRegion: AWSRegion
relevantTechniques:
- T1580
alertDetailsOverride:
  alertDisplayNameFormat: AWS credential hijack indicator from {{AccountName}}
  alertDescriptionFormat: GetCallerIdentity invoked by {{AccountName}} from {{SourceIpAddress}} in {{AWSRegion}}.
queryFrequency: 1d
id: 32555639-b639-4c2b-afda-c0ae0abefa55
description: |
  Identifies AWS STS `GetCallerIdentity` calls made by assumed-role sessions.
  An attacker who has assumed the role of a legitimate account can call the GetCallerIdentity function to determine what account they are using.
  A legitimate user using legitimate credentials would not need to call GetCallerIdentity since they should already know what account they are using.
  More Information: https://duo.com/decipher/trailblazer-hunts-compromised-credentials-in-aws 
  AWS STS GetCallerIdentity API: https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html
query: |
  AWSCloudTrail
  | where EventName =~ "GetCallerIdentity" and UserIdentityType =~ "AssumedRole"
  | extend UserIdentityArn = iif(isempty(UserIdentityArn), tostring(parse_json(Resources)[0].ARN), UserIdentityArn)
  | extend UserName = tostring(split(UserIdentityArn, '/')[-1])
  | extend AccountName = case(UserIdentityPrincipalid == "Anonymous", "Anonymous", isempty(UserIdentityUserName), UserName, UserIdentityUserName)
  | extend AccountName = iif(AccountName contains "@", tostring(split(AccountName, '@', 0)[0]), AccountName),
    AccountUPNSuffix = iif(AccountName contains "@", tostring(split(AccountName, '@', 1)[0]), "")
  | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by SourceIpAddress, EventName, EventTypeName, UserIdentityType, RecipientAccountId, AccountName, AccountUPNSuffix, UserIdentityAccountId, UserIdentityPrincipalid,
    UserAgent, UserIdentityUserName, SessionMfaAuthenticated, AWSRegion, EventSource, AdditionalEventData, ResponseElements
  | extend timestamp = StartTime
  | sort by EndTime desc nulls last
triggerOperator: gt
entityMappings:
- entityType: Account
  fieldMappings:
  - identifier: Name
    columnName: AccountName
  - identifier: UPNSuffix
    columnName: AccountUPNSuffix
  - identifier: CloudAppAccountId
    columnName: RecipientAccountId
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: SourceIpAddress
triggerThreshold: 0
tactics:
- Discovery
kind: Scheduled
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Amazon%20Web%20Services/Analytic%20Rules/AWS_CredentialHijack.yaml
requiredDataConnectors:
- dataTypes:
  - AWSCloudTrail
  connectorId: AWS
- dataTypes:
  - AWSCloudTrail
  connectorId: AWSS3
name: AWSCloudTrail - Monitor AWS Credential abuse or hijacking
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2024-01-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/32555639-b639-4c2b-afda-c0ae0abefa55')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/32555639-b639-4c2b-afda-c0ae0abefa55')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "GetCallerIdentity invoked by {{AccountName}} from {{SourceIpAddress}} in {{AWSRegion}}.",
          "alertDisplayNameFormat": "AWS credential hijack indicator from {{AccountName}}"
        },
        "alertRuleTemplateName": "32555639-b639-4c2b-afda-c0ae0abefa55",
        "customDetails": {
          "AWSRegion": "AWSRegion",
          "EventName": "EventName",
          "EventSource": "EventSource",
          "EventType": "EventTypeName"
        },
        "description": "Identifies AWS STS `GetCallerIdentity` calls made by assumed-role sessions.\nAn attacker who has assumed the role of a legitimate account can call the GetCallerIdentity function to determine what account they are using.\nA legitimate user using legitimate credentials would not need to call GetCallerIdentity since they should already know what account they are using.\nMore Information: https://duo.com/decipher/trailblazer-hunts-compromised-credentials-in-aws \nAWS STS GetCallerIdentity API: https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html\n",
        "displayName": "AWSCloudTrail - Monitor AWS Credential abuse or hijacking",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "AccountName",
                "identifier": "Name"
              },
              {
                "columnName": "AccountUPNSuffix",
                "identifier": "UPNSuffix"
              },
              {
                "columnName": "RecipientAccountId",
                "identifier": "CloudAppAccountId"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "SourceIpAddress",
                "identifier": "Address"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Amazon%20Web%20Services/Analytic%20Rules/AWS_CredentialHijack.yaml",
        "query": "AWSCloudTrail\n| where EventName =~ \"GetCallerIdentity\" and UserIdentityType =~ \"AssumedRole\"\n| extend UserIdentityArn = iif(isempty(UserIdentityArn), tostring(parse_json(Resources)[0].ARN), UserIdentityArn)\n| extend UserName = tostring(split(UserIdentityArn, '/')[-1])\n| extend AccountName = case(UserIdentityPrincipalid == \"Anonymous\", \"Anonymous\", isempty(UserIdentityUserName), UserName, UserIdentityUserName)\n| extend AccountName = iif(AccountName contains \"@\", tostring(split(AccountName, '@', 0)[0]), AccountName),\n  AccountUPNSuffix = iif(AccountName contains \"@\", tostring(split(AccountName, '@', 1)[0]), \"\")\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by SourceIpAddress, EventName, EventTypeName, UserIdentityType, RecipientAccountId, AccountName, AccountUPNSuffix, UserIdentityAccountId, UserIdentityPrincipalid,\n  UserAgent, UserIdentityUserName, SessionMfaAuthenticated, AWSRegion, EventSource, AdditionalEventData, ResponseElements\n| extend timestamp = StartTime\n| sort by EndTime desc nulls last\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P1D",
        "severity": "Low",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "Discovery"
        ],
        "techniques": [
          "T1580"
        ],
        "templateVersion": "1.0.4",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}