Back
Idb9be2aa6-911d-4131-8658-d2a537ed49f4
RulenameAWSCloudTrail - Privilege escalation via CRUD DynamoDB policy
DescriptionDetects creation of inline IAM policies that grant broad DynamoDB create, read, update, and delete permissions.

Attackers may use this access expansion to manipulate data stores and escalate influence across cloud workloads.
SeverityMedium
TacticsPrivilegeEscalation
TechniquesT1098.003
Required data connectorsAWS
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_PrivilegeEscalationviaCRUDDynamoDB.yaml
Version1.0.2
Arm templateb9be2aa6-911d-4131-8658-d2a537ed49f4.json
Deploy To Azure
AWSCloudTrail
| where EventName in ("PutUserPolicy","PutRolePolicy","PutGroupPolicy") and isempty(ErrorCode) and isempty(ErrorMessage)
| extend PolicyName = tostring(parse_json(RequestParameters).policyName)
| extend Statement = parse_json(tostring((parse_json(RequestParameters).policyDocument))).Statement
| mvexpand Statement
| extend Action = parse_json(Statement).Action , Effect = tostring(parse_json(Statement).Effect), Resource = tostring(parse_json(Statement).Resource), Condition = tostring(parse_json(Statement).Condition)
| extend Action = tostring(Action)
| where Effect =~ "Allow" and ((Action contains "dynamodb:Create" or Action contains "dynamodb:Put") and (Action contains "dynamodb:Describe" or Action contains "dynamodb:Get" or Action contains "dynamodb:Scan")  and Action contains "dynamodb:Update" and Action contains "dynamodb:Delete") and Resource == "*" and Condition == ""
| 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]), "")
| distinct TimeGenerated, EventName, PolicyName, SourceIpAddress, RecipientAccountId, AccountName, AccountUPNSuffix, UserIdentityArn, UserIdentityUserName
relevantTechniques:
- T1098.003
triggerThreshold: 0
id: b9be2aa6-911d-4131-8658-d2a537ed49f4
queryPeriod: 1d
triggerOperator: gt
alertDetailsOverride:
  alertDisplayNameFormat: AWS DynamoDB privilege escalation policy update by {{AccountName}}
  alertDescriptionFormat: Detected {{EventName}} Event, updating inline DynamoDB escalation policy {{PolicyName}} in account {{RecipientAccountId}}.
status: Available
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Amazon%20Web%20Services/Analytic%20Rules/AWS_PrivilegeEscalationviaCRUDDynamoDB.yaml
queryFrequency: 1d
requiredDataConnectors:
- dataTypes:
  - AWSCloudTrail
  connectorId: AWS
version: 1.0.2
tactics:
- PrivilegeEscalation
query: |
  AWSCloudTrail
  | where EventName in ("PutUserPolicy","PutRolePolicy","PutGroupPolicy") and isempty(ErrorCode) and isempty(ErrorMessage)
  | extend PolicyName = tostring(parse_json(RequestParameters).policyName)
  | extend Statement = parse_json(tostring((parse_json(RequestParameters).policyDocument))).Statement
  | mvexpand Statement
  | extend Action = parse_json(Statement).Action , Effect = tostring(parse_json(Statement).Effect), Resource = tostring(parse_json(Statement).Resource), Condition = tostring(parse_json(Statement).Condition)
  | extend Action = tostring(Action)
  | where Effect =~ "Allow" and ((Action contains "dynamodb:Create" or Action contains "dynamodb:Put") and (Action contains "dynamodb:Describe" or Action contains "dynamodb:Get" or Action contains "dynamodb:Scan")  and Action contains "dynamodb:Update" and Action contains "dynamodb:Delete") and Resource == "*" and Condition == ""
  | 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]), "")
  | distinct TimeGenerated, EventName, PolicyName, SourceIpAddress, RecipientAccountId, AccountName, AccountUPNSuffix, UserIdentityArn, UserIdentityUserName
name: AWSCloudTrail - Privilege escalation via CRUD DynamoDB policy
severity: Medium
entityMappings:
- entityType: Account
  fieldMappings:
  - identifier: Name
    columnName: AccountName
  - identifier: UPNSuffix
    columnName: AccountUPNSuffix
  - identifier: CloudAppAccountId
    columnName: RecipientAccountId
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: SourceIpAddress
customDetails:
  EventName: EventName
  RecipientAccountId: RecipientAccountId
  PolicyName: PolicyName
  UserIdentityArn: UserIdentityArn
description: |
  Detects creation of inline IAM policies that grant broad DynamoDB create, read, update, and delete permissions.
  Attackers may use this access expansion to manipulate data stores and escalate influence across cloud workloads.
kind: Scheduled
{
  "$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/b9be2aa6-911d-4131-8658-d2a537ed49f4')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/b9be2aa6-911d-4131-8658-d2a537ed49f4')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "Detected {{EventName}} Event, updating inline DynamoDB escalation policy {{PolicyName}} in account {{RecipientAccountId}}.",
          "alertDisplayNameFormat": "AWS DynamoDB privilege escalation policy update by {{AccountName}}"
        },
        "alertRuleTemplateName": "b9be2aa6-911d-4131-8658-d2a537ed49f4",
        "customDetails": {
          "EventName": "EventName",
          "PolicyName": "PolicyName",
          "RecipientAccountId": "RecipientAccountId",
          "UserIdentityArn": "UserIdentityArn"
        },
        "description": "Detects creation of inline IAM policies that grant broad DynamoDB create, read, update, and delete permissions.\nAttackers may use this access expansion to manipulate data stores and escalate influence across cloud workloads.\n",
        "displayName": "AWSCloudTrail - Privilege escalation via CRUD DynamoDB policy",
        "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_PrivilegeEscalationviaCRUDDynamoDB.yaml",
        "query": "AWSCloudTrail\n| where EventName in (\"PutUserPolicy\",\"PutRolePolicy\",\"PutGroupPolicy\") and isempty(ErrorCode) and isempty(ErrorMessage)\n| extend PolicyName = tostring(parse_json(RequestParameters).policyName)\n| extend Statement = parse_json(tostring((parse_json(RequestParameters).policyDocument))).Statement\n| mvexpand Statement\n| extend Action = parse_json(Statement).Action , Effect = tostring(parse_json(Statement).Effect), Resource = tostring(parse_json(Statement).Resource), Condition = tostring(parse_json(Statement).Condition)\n| extend Action = tostring(Action)\n| where Effect =~ \"Allow\" and ((Action contains \"dynamodb:Create\" or Action contains \"dynamodb:Put\") and (Action contains \"dynamodb:Describe\" or Action contains \"dynamodb:Get\" or Action contains \"dynamodb:Scan\")  and Action contains \"dynamodb:Update\" and Action contains \"dynamodb:Delete\") and Resource == \"*\" and Condition == \"\"\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| distinct TimeGenerated, EventName, PolicyName, SourceIpAddress, RecipientAccountId, AccountName, AccountUPNSuffix, UserIdentityArn, UserIdentityUserName\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P1D",
        "severity": "Medium",
        "status": "Available",
        "subTechniques": [
          "T1098.003"
        ],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "PrivilegeEscalation"
        ],
        "techniques": [
          "T1098"
        ],
        "templateVersion": "1.0.2",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}