Microsoft Sentinel Analytic Rules
cloudbrothers.infoAzure Sentinel RepoToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

Monitor AWS Credential abuse or hijacking

Back
Id32555639-b639-4c2b-afda-c0ae0abefa55
RulenameMonitor AWS Credential abuse or hijacking
DescriptionLooking for GetCallerIdentity Events where the UserID Type is AssumedRole

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
TechniquesT1087
Required data connectorsAWS
AWSS3
KindScheduled
Query frequency1d
Query period1d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Amazon Web Services/Analytic Rules/AWS_CredentialHijack.yaml
Version1.0.3
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
kind: Scheduled
relevantTechniques:
- T1087
description: |
  'Looking for GetCallerIdentity Events where the UserID Type is AssumedRole
  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 '  
queryPeriod: 1d
queryFrequency: 1d
tactics:
- Discovery
name: Monitor AWS Credential abuse or hijacking
requiredDataConnectors:
- connectorId: AWS
  dataTypes:
  - AWSCloudTrail
- connectorId: AWSS3
  dataTypes:
  - AWSCloudTrail
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
version: 1.0.3
id: 32555639-b639-4c2b-afda-c0ae0abefa55
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  
status: Available
triggerOperator: gt
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Amazon Web Services/Analytic Rules/AWS_CredentialHijack.yaml
severity: Low
{
  "$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": {
        "alertRuleTemplateName": "32555639-b639-4c2b-afda-c0ae0abefa55",
        "customDetails": null,
        "description": "'Looking for GetCallerIdentity Events where the UserID Type is AssumedRole\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": "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 Web Services/Analytic Rules/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,\nUserAgent, 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": [
          "T1087"
        ],
        "templateVersion": "1.0.3",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}