Skip to content

Add hunting queries: Entra privileged-identity utilization pack (3 queries) - #14813

Open
d4rk-pri0r wants to merge 2 commits into
Azure:masterfrom
d4rk-pri0r:community/hunting-privileged-identity-utilization
Open

Add hunting queries: Entra privileged-identity utilization pack (3 queries)#14813
d4rk-pri0r wants to merge 2 commits into
Azure:masterfrom
d4rk-pri0r:community/hunting-privileged-identity-utilization

Conversation

@d4rk-pri0r

Copy link
Copy Markdown
Contributor

Details

Three new SigninLogs hunting queries under the "licensed but minimally configured" theme, surfacing identities that hold directory or PIM roles yet show risky/absent usage patterns in Microsoft Entra ID:

  1. DormantPrivilegedIdentities — enabled identities with AssignedRoles or PrivilegedEntraPimRoles that have no successful sign-in in 90 days (blast radius ranked), a classic takeover target and unused-license signal.
  2. PrivilegedSigninsWithoutConditionalAccessSuccess — successful sign-ins by privileged users where ConditionalAccessStatus was not success, i.e. logons reaching the tenant that were not gated by an applied Conditional Access policy.
  3. PrivilegedAccountsUsingLegacyAuthentication — privileged users authenticating via legacy protocols (Exchange Web Services, IMAP, Autodiscover, etc.) that bypass modern CA and MFA controls.

All three join IdentityInfo (Microsoft 365 Defender) with SigninLogs and map Account and IP entities.

Testing

  • KQL validated against the repo Kusto schema via CI kql-validations (runs on this PR).
  • YAML parses and conforms to the community detection schema (id/name/description-detail/requiredDataConnectors/tactics/relevantTechniques/query/entityMappings/version/metadata).
  • Entity mappings use the new Account FullName/Name/UPNSuffix/AadUserId + IP Address structure; ASCII-only content.

Note to reviewers

Author metadata: d4rk-pri0r, Community support tier. If any column name is rejected by KQL validation, I'll patch the affected query.

@d4rk-pri0r
d4rk-pri0r requested review from a team as code owners August 3, 2026 14:41
New SigninLogs hunting queries that surface licensed-but-minimally-
configured identity gaps in Microsoft Entra ID:

- DormantPrivilegedIdentities: enabled identities with directory or PIM
  roles that have no successful sign-in in 90 days
- PrivilegedSigninsWithoutConditionalAccessSuccess: privileged users whose
  successful logons are not gated by an applied Conditional Access policy
- PrivilegedAccountsUsingLegacyAuthentication: privileged users
  authenticating via legacy protocols that bypass modern CA/MFA

All three join IdentityInfo (Microsoft 365 Defender) with SigninLogs and
map Account/IP entities.
@v-atulyadav v-atulyadav self-assigned this Aug 4, 2026
@v-atulyadav v-atulyadav added the Hunting Hunting specialty review needed label Aug 4, 2026
@v-atulyadav
v-atulyadav requested a lite review from Copilot August 4, 2026 04:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds three new Microsoft Entra ID SigninLogs hunting queries focused on identifying privileged identities showing risky/absent usage patterns in “licensed but minimally configured” tenants.

Changes:

  • Added a query to find privileged sign-ins where Conditional Access did not succeed.
  • Added a query to detect privileged accounts authenticating via legacy protocols.
  • Added a query to surface privileged identities with no recent successful sign-ins.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 11 comments.

File Description
Hunting Queries/SigninLogs/PrivilegedSigninsWithoutConditionalAccessSuccess.yaml New hunting query for privileged successful sign-ins lacking CA “success”.
Hunting Queries/SigninLogs/PrivilegedAccountsUsingLegacyAuthentication.yaml New hunting query for privileged successful sign-ins using legacy client protocols.
Hunting Queries/SigninLogs/DormantPrivilegedIdentities.yaml New hunting query for enabled privileged identities with no recent successful sign-ins.

Comment on lines +33 to +43
let lookback = 90d;
let noSigninSince = 1d;
IdentityInfo
| where IsAccountEnabled == true
| where isnotempty(AssignedRoles) or isnotempty(PrivilegedEntraPimRoles)
| join kind=leftanti (
SigninLogs
| where TimeGenerated > ago(noSigninSince)
| where ResultType == "0"
| project AccountObjectId = UserId
) on AccountObjectId
Comment on lines +52 to +60
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountUpn
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
Comment on lines +42 to +43
| where isnotempty(ConditionalAccessStatus)
| where ConditionalAccessStatus !~ "success"
Comment on lines +36 to +38
let PrivilegedUsers = IdentityInfo
| where isnotempty(AssignedRoles) or isnotempty(PrivilegedEntraPimRoles)
| project AccountObjectId, AccountUpn;
| where ResultType == "0"
| where isnotempty(ConditionalAccessStatus)
| where ConditionalAccessStatus !~ "success"
| join kind=inner PrivilegedUsers on $left.UserId == $right.AccountObjectId
Comment on lines +38 to +41
let LegacyProtocols = dynamic([
"IMAP", "POP", "SMTP", "ActiveSync", "ExchangeWebServices",
"Autodiscover", "OWA"
]);
SigninLogs
| where TimeGenerated > ago(timeframe)
| where ResultType == "0"
| where ClientAppUsed has_any (LegacyProtocols)
Comment on lines +42 to +44
let PrivilegedUsers = IdentityInfo
| where isnotempty(AssignedRoles) or isnotempty(PrivilegedEntraPimRoles)
| project AccountObjectId, AccountUpn;
| where TimeGenerated > ago(timeframe)
| where ResultType == "0"
| where ClientAppUsed has_any (LegacyProtocols)
| join kind=inner PrivilegedUsers on $left.UserId == $right.AccountObjectId
Comment on lines +59 to +61
IPAddresses = make_set(IPAddress)
by UserPrincipalName, AccountName, AccountUPNSuffix, UserId, AccountUpn, AppDisplayName
| extend FirstIP = tostring(IPAddresses[0])
@v-atulyadav

Copy link
Copy Markdown
Collaborator

Hi @d4rk-pri0r,

Please review the suggestions above and make the necessary changes accordingly. Also, please confirm that all queries are working correctly in your environment. If possible, share screenshots of the queries running successfully for verification. Thanks

@d4rk-pri0r

Copy link
Copy Markdown
Contributor Author

Addressed the Copilot review feedback across all three queries (v1.0.1):

DormantPrivilegedIdentities

  • Fixed lookback logic: anti-join now uses the 90d lookback (removed unused noSigninSince = 1d)
  • Softened description to “successful sign-in” (no interactive claim without a filter)
  • Deduped IdentityInfo via arg_max(TimeGenerated, *) by AccountObjectId
  • Projected AccountObjectId and mapped AadUserId

PrivilegedSigninsWithoutConditionalAccessSuccess

  • Removed isnotempty(ConditionalAccessStatus); coalesce null/empty to notEvaluated so unprotected sign-ins are included
  • Deduped privileged users before join
  • Replaced non-deterministic IPAddresses[0] with LastIP = arg_max(TimeGenerated, IPAddress)

PrivilegedAccountsUsingLegacyAuthentication

  • Aligned ClientAppUsed list with existing repo pattern (PrivilegedAccountLegacyAuthSignIn.yaml): Exchange ActiveSync, IMAP4, MAPI over HTTP, POP3, SMTP Auth, Authenticated SMTP, Other clients; switched to in~
  • Same privileged-user dedupe and deterministic LastIP

CI was green on the prior revision; this is description/KQL hardening only. I do not have a live tenant screenshot handy for this environment — happy to add one if you still need visual confirmation after CI re-runs.

Fix dormant lookback (use 90d), dedupe IdentityInfo, add AadUserId,
include null CA status, align legacy ClientAppUsed values with repo
patterns, and pick LastIP via arg_max for stable entity mapping.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Hunting Hunting specialty review needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants