Query Details

Multiple Unexpected AD FS Authentication Flow

Query

let query_frequency = 5m;
let query_period = 2d;
let query_wait = 30m;
let _ExpectedADFSIPAddress = toscalar(
    _GetWatchlist("Activity-ExpectedSignificantActivity")
    | where Activity == "ADFSAuthenticationAddress"
    | summarize make_list(SourceAddress)
);
let _TrustedNamedLocations = toscalar(
    _GetWatchlist("Activity-ExpectedSignificantActivity")
    | where Activity == "TrustedNamedLocation"
    | summarize make_list(SourceResource)
);
ADFSSignInLogs
| where TimeGenerated between (ago(query_frequency + query_wait) .. ago(query_wait))
| where ResultType == 0 and isnotempty(IPAddress)
| mv-apply AuthenticationProcessingDetail = todynamic(AuthenticationProcessingDetails) on (
    where AuthenticationProcessingDetail has "IP Addresses Involved in Auth Flow"
    | extend IPAddressesInvolved = split(tostring(AuthenticationProcessingDetail["value"]), ",")
    )
| project-away AuthenticationProcessingDetail
| where not(array_length(IPAddressesInvolved) == 1) and not(IPAddress in (_ExpectedADFSIPAddress))
| summarize Auxiliar = arg_max(array_length(IPAddressesInvolved), IPAddressesInvolved) by UserId, CorrelationId
| project-away Auxiliar
| join kind = inner (
    union SigninLogs, AADNonInteractiveUserSignInLogs
    | where TimeGenerated > ago(query_period + query_wait)
    | where isnotempty(CorrelationId) and isnotempty(SessionId)
    ) on UserId, CorrelationId
| project-away *1
| summarize arg_min(CreatedDateTime, *) by UserId, HomeTenantId, ResourceTenantId, IPAddress, CorrelationId
| mv-apply NetworkLocationDetail = todynamic(NetworkLocationDetails) on (
    summarize
        //NetworkTypes = make_set(tostring(NetworkLocationDetail["networkType"])),
        NetworkNames = make_set(tostring(NetworkLocationDetail["networkNames"][0]))
    )
| where not(NetworkNames has_any (_TrustedNamedLocations))
| project IPAddressesInvolved, UserId, CorrelationId, SessionId
| join kind = inner (
    union SigninLogs, AADNonInteractiveUserSignInLogs
    | where TimeGenerated > ago(query_period + query_wait)
    | where isnotempty(SessionId)
    ) on UserId, SessionId
| project-away *1
| summarize
    arg_min(CreatedDateTime, *),
    AccesedApps = array_sort_asc(make_set_if(AppDisplayName, ResultType == 0, 50)),
    AccessedResources = array_sort_asc(make_set_if(ResourceDisplayName, ResultType == 0, 50)),
    SessionIds = make_set(SessionId),
    CorrelationIds = make_set(CorrelationId)
    by UserId, IPAddress, HomeTenantId, ResourceTenantId
| project
    TimeGenerated,
    CreatedDateTime,
    UserPrincipalName,
    UserDisplayName,
    SessionIds,
    IPAddressesInvolved,
    IPAddress,
    Location,
    NetworkLocationDetails,
    AutonomousSystemNumber,
    AuthenticationDetails,
    ClientAppUsed,
    DeviceDetail = coalesce(tostring(DeviceDetail_dynamic), DeviceDetail_string),
    UserAgent,
    Category,
    AccesedApps,
    AccessedResources,
    HomeTenantId,
    ResourceTenantId,
    CorrelationIds,
    UserId

Explanation

This KQL (Kusto Query Language) query is designed to analyze authentication logs, specifically focusing on ADFS (Active Directory Federation Services) sign-ins and related activities. Here's a simplified breakdown of what the query does:

  1. Define Parameters:

    • query_frequency, query_period, and query_wait are set to specify time intervals for the analysis.
    • _ExpectedADFSIPAddress and _TrustedNamedLocations are lists of expected IP addresses and trusted locations, respectively, retrieved from a watchlist.
  2. Filter ADFS Sign-In Logs:

    • The query examines ADFS sign-in logs within a specific time window.
    • It filters for successful logins (ResultType == 0) with non-empty IP addresses.
    • It extracts and processes details about IP addresses involved in the authentication flow.
  3. Identify Anomalies:

    • It identifies cases where multiple IP addresses are involved in a single authentication flow and checks if these IPs are not in the expected list.
    • It summarizes these cases by user and correlation ID.
  4. Join with Other Sign-In Logs:

    • The query joins the filtered ADFS logs with other sign-in logs (both interactive and non-interactive) based on user ID and correlation ID.
    • It further filters and summarizes these logs by various attributes like user ID, IP address, and tenant IDs.
  5. Network Location Analysis:

    • It analyzes network location details to identify if the network names are not in the list of trusted locations.
  6. Final Output:

    • The query compiles a detailed summary of the authentication events, including accessed applications and resources, session and correlation IDs, and other relevant user and network details.
    • It projects a final set of columns for output, providing a comprehensive view of the authentication activities and potential anomalies.

Overall, this query is used to detect unusual or potentially suspicious authentication activities by analyzing ADFS sign-in logs and correlating them with other sign-in data, while considering expected IP addresses and trusted locations.