Query Details

Azure Hound Reconnaissance Detected

Query

let AzureHoundGraphQueries = dynamic([
    "https:/graph.microsoft.com/version/servicePrincipals/<UUID>/owners",
    "https:/graph.microsoft.com/version/groups/<UUID>/members",
    "https:/graph.microsoft.com/version/groups/<UUID>/owners",
    "https:/graph.microsoft.com/version/servicePrincipals/<UUID>/appRoleAssignedTo",
    "https:/graph.microsoft.com/version/roleManagement/directory/roleAssignments",
    "https:/graph.microsoft.com/version/applications/<UUID>/owners",
    "https:/graph.microsoft.com/version/devices/<UUID>/registeredOwners",
    "https:/graph.microsoft.com/version/organization",
    "https:/graph.microsoft.com/version/groups",
    "https:/graph.microsoft.com/version/servicePrincipals",
    "https:/graph.microsoft.com/version/applications",
    "https:/graph.microsoft.com/version/roleManagement/directory/roleDefinitions",
    "https:/graph.microsoft.com/version/devices",
    "https:/graph.microsoft.com/version/users"
    ]);
let PotentialMaliciousGraphCalls = materialize (
    MicrosoftGraphActivityLogs
    | where ingestion_time() > ago(35m)
    | extend ObjectId = iff(isempty(UserId), ServicePrincipalId, UserId)
    | extend ObjectType = iff(isempty(UserId), "ServicePrincipalId", "UserId")
    | where RequestUri !has "microsoft.graph.delta"
    | extend NormalizedRequestUri = replace_regex(RequestUri, @'[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}', @'<UUID>')
    | extend NormalizedRequestUri = replace_regex(NormalizedRequestUri, @'\d+$', @'<UUID>')
    | extend NormalizedRequestUri = replace_regex(NormalizedRequestUri, @'\/+', @'/')
    | extend NormalizedRequestUri = replace_regex(NormalizedRequestUri, @'\/(v1\.0|beta)\/', @'/version/')
    | extend NormalizedRequestUri = replace_regex(NormalizedRequestUri, @'%23EXT%23', @'')
    | extend NormalizedRequestUri = replace_regex(NormalizedRequestUri, @'\/[a-zA-Z0-9+_.\-]+@[a-zA-Z0-9.]+\/', @'/<UUID>/')
    | extend NormalizedRequestUri = replace_regex(NormalizedRequestUri, @'^\/<UUID>', @'')
    | extend NormalizedRequestUri = replace_regex(NormalizedRequestUri, @'\?.*$', @'')
    | summarize
        GraphEndpointsCalled = make_set(NormalizedRequestUri, 1000),
        IPAddresses = make_set(IpAddress)
        by ObjectId, ObjectType
    | project
        ObjectId,
        ObjectType,
        IPAddresses,
        MatchingQueries=set_intersect(AzureHoundGraphQueries, GraphEndpointsCalled)
    | extend ConfidenceScore = round(todouble(array_length(MatchingQueries)) / todouble(array_length(AzureHoundGraphQueries)), 1)
    | where ConfidenceScore > 0.7);
let IPEntities = PotentialMaliciousGraphCalls
    | mv-expand IPAddresses
    | sort by ObjectId
    | extend CurrentRowNumber=row_number(2, prev(ObjectId) != ObjectId)
    | extend IPInformation = bag_pack(@"$id", CurrentRowNumber, "Address", IPAddresses, "Type", "ip")
    | project ObjectId, IPInformation
    | summarize IPInformation = make_set(IPInformation, 150) by ObjectId;
PotentialMaliciousGraphCalls
| join kind=leftouter IPEntities on ObjectId
| project-away IPAddresses, *1, *2

Explanation

The query is designed to detect potential malicious activity in your environment related to Microsoft Graph queries similar to AzureHound. It looks for specific URLs in the Microsoft Graph API and matches them with activity logs. It calculates a confidence score based on the number of matching queries and compares it to a threshold. If the score is above the threshold, it identifies the potential malicious calls and extracts IP addresses associated with them. The query also includes incident configuration settings and entity mappings for further analysis.