Query Details

AWS Cloud Trail Aws Iam Assume Role Policy Brute Force

Query

let query_frequency = 1h;
let query_period = 2h;
let threshold = 5;
let _ExpectedErrorCodes = dynamic(["AccessDenied", "MalformedPolicyDocumentException", "NoSuchEntityException"]);
let _ExpectedRoleIdentityRegex = toscalar(
    _GetWatchlist("Activity-ExpectedSignificantActivity")
    | where Activity == "AWSAssumedRoleIdentityEventName_Regex" and Auxiliar has_any (_ExpectedErrorCodes)
    | summarize RegEx = make_set(strcat(SourceResource, ActorPrincipalName))
    | extend RegEx = strcat(@"^(", strcat_array(RegEx, "|"), @")$")
);
let _ExpectedUsers = toscalar(
    _GetWatchlist("Activity-ExpectedSignificantActivity")
    | where Activity == "AWSIAMUser" and Auxiliar has_any (_ExpectedErrorCodes)
    | summarize make_list(ActorPrincipalName)
);
AWSCloudTrail
| where TimeGenerated > ago(query_period)
| where ErrorCode has_any ("MalformedPolicyDocumentException", "NoSuchEntityException") or ErrorMessage matches regex @"not authorized to perform:.*AssumeRole.* on resource"
| where not(ErrorCode == "NoSuchEntityException" and not(ErrorMessage has "role with"))
| where not(UserIdentityInvokedBy has ".amazonaws.com" and SourceIpAddress has ".amazonaws.com" and UserAgent has ".amazonaws.com")
| where not(UserIdentityArn in (_ExpectedUsers))
| extend UserIdentityUserName = tostring(split(UserIdentityPrincipalid, ":")[1])
| where not(ErrorCode in (_ExpectedErrorCodes) and strcat(SessionIssuerUserName, UserIdentityUserName) matches regex _ExpectedRoleIdentityRegex)
| summarize arg_min(TimeGenerated, *) by UserIdentityArn, EventName, ErrorCode, ErrorMessage
| extend AuxiliarKey = ""
| as _Events
| join kind=leftsemi (
    _Events
    // query_period should be 2 * query_frequency
    | evaluate activity_counts_metrics(Type, TimeGenerated, ago(query_period), now(), query_frequency)
    | summarize
        arg_min(PreviousTimeGenerated = TimeGenerated, PreviousCount = ["count"]),
        arg_max(CurrentTimeGenerated = TimeGenerated, CurrentCount = ["count"])
    | where CurrentTimeGenerated > ago(query_period)
    | extend PreviousCount = iff(PreviousTimeGenerated == CurrentTimeGenerated, 0, PreviousCount)
    | where (not(PreviousCount > threshold) and CurrentCount > threshold)
        or ((CurrentCount - PreviousCount) > threshold)
    | extend AuxiliarKey = ""
    ) on AuxiliarKey
| invoke AWSIdentityRole()
| project
    TimeGenerated,
    UserIdentityType,
    Identity,
    ActorRole,
    UserIdentityAccountId,
    UserIdentityAccountName,
    RecipientAccountId,
    RecipientAccountName,
    AWSRegion,
    SessionCreationDate,
    UserIdentityPrincipalid,
    UserIdentityArn,
    SourceIpAddress,
    EventSource,
    EventTypeName,
    EventName,
    ManagementEvent,
    ReadOnly,
    ErrorCode,
    ErrorMessage,
    RequestParameters,
    ResponseElements,
    Resources,
    SessionMfaAuthenticated,
    UserAgent,
    AwsEventId

Explanation

This KQL (Kusto Query Language) query is designed to analyze AWS CloudTrail logs to identify unusual or potentially unauthorized activities related to AWS IAM roles and users. Here's a simplified breakdown of what the query does:

  1. Setup Variables:

    • Defines time intervals (query_frequency and query_period) and a threshold for detecting significant activity changes.
    • Specifies a list of expected error codes (_ExpectedErrorCodes) and retrieves expected role identities and users from a watchlist.
  2. Filter CloudTrail Logs:

    • Looks at logs from the past 2 hours (query_period).
    • Filters for specific error codes or error messages indicating unauthorized actions, particularly around the AssumeRole operation.
    • Excludes certain benign cases, such as those involving AWS internal services or expected users/roles.
  3. Identify Unusual Activity:

    • Summarizes the filtered events to find the earliest occurrence of each unique combination of user identity, event name, error code, and error message.
    • Joins these events with a subquery that calculates activity metrics over time.
    • The subquery checks if there is a significant increase in activity count (exceeding the threshold) compared to the previous period.
  4. Enrich and Present Results:

    • Enriches the results with additional identity and role information using the AWSIdentityRole() function.
    • Projects a set of relevant fields for further analysis or alerting, such as user identity details, event information, and error messages.

In essence, this query is designed to detect and highlight unusual or unauthorized AWS IAM activities by comparing current activity levels against historical data and expected patterns.

Details

Jose Sebastián Canós profile picture

Jose Sebastián Canós

Released: March 11, 2024

Tables

_GetWatchlistAWSCloudTrail

Keywords

AWSCloudTrailUserIdentityErrorCodeMessageEventNameSourceTypeSessionCreationDatePrincipalIdArnIpAddressAgentResourcesMfaAuthenticatedManagementReadOnlyRequestParametersResponseElements

Operators

lettoscalarwherehas_anysummarizemake_setstrcatextendinsplitmatchesregexarg_minbyasjoinkindleftsemievaluateactivity_counts_metricsagonowiffinvokeproject

Actions

GitHub