Query Details

Exposed Tokens Overview Of Token Artifcats

Query

// Overview of detected token artifacts by Exposure Management
// Hunting query to get list of PRT, Session Cookies and CLI authentication artifacts
// with details of endpoint security posture.

let PrimaryRefresh = ExposureGraphEdges
    | where EdgeLabel == @"has credentials of"
    | join kind = inner (
        ExposureGraphNodes
        | project NodeId, RawData = parse_json(NodeProperties)["rawData"], EntityIds
    ) on $left.SourceNodeId == $right.NodeId
    | where parse_json(EdgeProperties)["rawData"]["primaryRefreshToken"]["primaryRefreshToken"] == 'true'
    | extend TokenType = tostring(parse_json(EdgeProperties)["rawData"]["primaryRefreshToken"]["type"])
    | project EdgeId, SourceNodeId, SourceNodeName, SourceNodeLabel, EdgeLabel, TargetNodeId, TargetNodeName, TokenType, DeviceRawData = RawData, EntityIds;
let SessionCookie = ExposureGraphEdges
    | where EdgeLabel == @"contains" and TargetNodeLabel == "entra-userCookie"
    | join kind = inner (
        ExposureGraphNodes
        | project NodeId, RawData = parse_json(NodeProperties)["rawData"], EntityIds
    ) on $left.SourceNodeId == $right.NodeId
    | join kind = inner (
        ExposureGraphNodes
        | project NodeId, RawData = parse_json(NodeProperties)["rawData"], EntityIds
    ) on $left.TargetNodeId == $right.NodeId
    | join kind = inner (
        ExposureGraphEdges
        | where EdgeLabel == @"can authenticate as" and SourceNodeLabel == @"entra-userCookie"
    ) on $left.TargetNodeId == $right.SourceNodeId
    | extend TargetNodeId
    | extend TokenType = "UserCookie"
    | project EdgeId, SourceNodeId, SourceNodeName, SourceNodeLabel, EdgeLabel, TargetNodeId = TargetNodeId1, TargetNodeName = TargetNodeName1, TokenType, DeviceRawData = RawData, EntityIds;
let AzureCliToken = ExposureGraphNodes
    // RT and AT in Azure CLI e.g., privileged account not primary user but will be used on this device
    | where NodeLabel == "user-azure-cli-secret"
    | extend AccountSid = tostring(parse_json(NodeProperties)["rawData"]["userAzureCliSecretData"]["userSid"])
    | join kind=inner ( ExposureGraphNodes
        | extend AccountSid = tostring(parse_json(NodeProperties)["rawData"]["aadSid"])
        | project UserNodeId = NodeId, UserNodeName = NodeName, AccountSid
    ) on AccountSid
    | join kind=inner ( 
        ExposureGraphEdges
        ) on $left.NodeId == $right.TargetNodeId
    | extend TokenType = tostring(parse_json(NodeProperties)["rawData"]["userAzureCliSecretData"]["type"])
    | project EdgeId, SourceNodeId, SourceNodeName, SourceNodeLabel, EdgeLabel, TargetNodeId = UserNodeId, TargetNodeName = UserNodeName, TokenType, TokenNodeId = TargetNodeId, TokenNodeName = TargetNodeName, DeviceRawData = parse_json(NodeProperties)["rawData"];
union PrimaryRefresh, SessionCookie, AzureCliToken
// Enrichment to MDE insights
| mv-apply EntityIds = parse_json(EntityIds) on (
    where EntityIds.type =~ "DeviceInventoryId"
    | extend DeviceId = tostring(EntityIds.id)
)
| extend HighRiskVulnerability = iff(parse_json(DeviceRawData)["highRiskVulnerabilityInsights"]["hasHighOrCritical"] == 'true', true, false)
| extend CredentialGuard = iff(parse_json(DeviceRawData)["hasGuardMisconfigurations"] has 'Credential Guard', false, true)
| summarize TokenArtifacts = make_list(TokenType) by
        User = TargetNodeName,
        Device = SourceNodeName,
        DeviceId,
        PublicIP = tostring(parse_json(DeviceRawData)["publicIP"]),
        ExposureScore = tostring(parse_json(DeviceRawData)["exposureScore"]),
        RiskScore = tostring(parse_json(DeviceRawData)["riskScore"]),
        HighRiskOrCriticalVulnerability = tostring(HighRiskVulnerability),
        MaxCvssScore = tostring(parse_json(DeviceRawData)["highRiskVulnerabilityInsights"]["maxCvssScore"]),
        AllowedRDP = tostring(parse_json(DeviceRawData)["rdpStatus"]["allowConnections"]),
        CredentialGuard = tostring(CredentialGuard),
        TpmActivated = tostring(parse_json(DeviceRawData)["tpmData"]["activated"])
| join kind = leftouter ( AlertEvidence
    | where isnotempty(DeviceId)
    | summarize Alerts = make_set(Title), AlertCategories = make_set(Categories) by DeviceId
) on DeviceId
| project-away DeviceId1

Explanation

This KQL query is designed to provide an overview of detected token artifacts related to authentication, such as Primary Refresh Tokens (PRT), Session Cookies, and Azure CLI tokens, along with details about the security posture of the endpoints where these tokens are found. Here's a simplified breakdown of what the query does:

  1. Primary Refresh Tokens (PRT):

    • It identifies edges in a graph database where a node has credentials of another node, specifically looking for primary refresh tokens.
    • It extracts relevant details such as token type and device raw data.
  2. Session Cookies:

    • It identifies edges where a node contains a session cookie, specifically targeting "entra-userCookie" nodes.
    • It extracts details about the session cookies and their associated devices.
  3. Azure CLI Tokens:

    • It identifies nodes labeled as "user-azure-cli-secret" to find Azure CLI tokens.
    • It joins these with user nodes and extracts token types and device raw data.
  4. Combining Results:

    • The results from the above three sections are combined into a single dataset.
  5. Enrichment with Device Insights:

    • The query enriches the data with additional insights from Microsoft Defender for Endpoint (MDE), such as high-risk vulnerabilities, credential guard status, and other security posture details.
    • It also checks for alerts related to the devices and includes alert titles and categories.
  6. Summarization:

    • The query summarizes the data by user and device, listing the types of token artifacts found and various security metrics like exposure score, risk score, and vulnerability details.
  7. Output:

    • The final output includes a list of users and devices, along with the token artifacts detected, security posture details, and any associated alerts.

In essence, this query is used for security hunting to identify and assess the risk associated with different types of authentication tokens on devices, providing a comprehensive view of potential security exposures.

Details

Thomas Naunheim profile picture

Thomas Naunheim

Released: April 7, 2025

Tables

ExposureGraphEdgesExposureGraphNodesAlertEvidence

Keywords

ExposureManagementTokenArtifactsEndpointSecurityDeviceUserAzureCLIVulnerabilityInsightsPublicIPRiskScoreCredentialGuardTPMAlertEvidence

Operators

letwherejoinonprojectparse_jsonextendtostringunionmv-applyiffhassummarizemake_listbymake_setleftouterisnotemptyproject-away

Actions

GitHub