Skip to content

Add hunting queries: break-glass account hunting pack (3 queries) - #14948

Open
Descambiado (descambiado) wants to merge 7 commits into
Azure:masterfrom
descambiado:add-breakglass-account-hunting-pack
Open

Add hunting queries: break-glass account hunting pack (3 queries)#14948
Descambiado (descambiado) wants to merge 7 commits into
Azure:masterfrom
descambiado:add-breakglass-account-hunting-pack

Conversation

@descambiado

Copy link
Copy Markdown
Contributor

Summary

Three hunting queries for monitoring designated emergency break-glass accounts, which should show no sign-in, credential, or membership activity outside a documented recovery test.

BreakGlassAccountSignIn (SigninLogs)

Identifies any sign-in from a designated break-glass account. These accounts are deliberately excluded from Conditional Access and day-to-day MFA, so a successful sign-in bypasses the same controls protecting every other identity in the tenant.

MITRE: T1078.004, InitialAccess, Persistence

BreakGlassAccountCredentialsModified (AuditLogs)

Identifies password resets, security-info registrations, and MFA changes on a break-glass account. Matches official Microsoft phrasing for password-reset detection (noun+verb match) rather than an exact-string list, since operation names vary across tenants and service versions.

MITRE: T1098, T1556.006, Persistence, DefenseEvasion

BreakGlassAccountRoleOrGroupMembershipChanged (AuditLogs)

Identifies direct role assignment and group-mediated privilege changes on a break-glass account. Covers both paths since a group-mediated addition to a role-assignable group grants the inherited role without ever generating a direct role-assignment event.

MITRE: T1098.003, PrivilegeEscalation, Persistence

Validation

  • All three descriptions under 255 characters (204, 245, 214)
  • Names sentence case, under the 100-char hard limit
  • No non-ASCII characters
  • GUIDs unique (verified against existing queries in the repo)
  • All three share and document the BreakGlassAccounts watchlist dependency
  • MITRE tactics/techniques verified against ATT&CK v16

- Sign-in to a designated emergency access account (T1078.004)
- Credential or MFA modification on a designated emergency access account (T1098, T1556.006)

Both queries key off a BreakGlassAccounts watchlist (AccountUPN column) since
break-glass accounts cannot be reliably inferred from log data alone.
Adds the third query to the break-glass account pack, closing the last gap
in the account's lifecycle: privilege changes made through direct role
assignment or group membership, alongside the sign-in and credential
queries already covering usage and secrets.

- Break-glass account role or group membership changed (T1098.003)
The sign-in and credentials queries still pointed to a single companion
query from before the pack had its third member. Updated both to point
readers to the role/group membership query as well.
Two real gaps found on a second pass, cross-checked against this repo's
own already-merged content rather than assumption:

Credentials/MFA query: password reset and change operation names are not
consistent across tenants and Entra ID service versions, this repo alone
has three different exact-string lists for the same event in other
hunting queries (BulkPasswordResetByActor, PasswordResetThenPrivileged
Operation, and this one as originally written). Switched to the same
has_any word-pair match the official "Multiple Password Reset by user"
analytic rule uses instead of a fourth incomplete exact list. Also
stopped assuming the target account sits at TargetResources[0]; the two
existing password-reset queries in this repo both read it via mv-apply
across all TargetResources entries instead, for good reason.

Role/group membership query: the Role.DisplayName and Group.DisplayName
lookups used mv-expand followed by a where clause, which silently drops
the whole row if that property isn't present in the exact shape
expected. Since the watchlist match against a break-glass account is
already the real detection signal and the property lookup is only
enrichment, a lookup miss should not cost the detection. Split each
branch into a base query and a leftouter-joined enrichment query so a
row always survives with a placeholder label if the name can't be read.
Both are referenced twice (once to build the name lookup, once as the
left side of the join back to it). Without materialize(), Kusto
re-evaluates a let expression at each reference instead of caching it,
so the new_guid() call inside each would run independently per
reference. The RowId used for the join would never match itself, and
the leftouter join added in the previous commit to avoid dropping rows
would have quietly enriched nothing, every row would have shown
"(role name unavailable)" or "(group name unavailable)" instead of the
real value, even on a clean match.

This repo's own hunting query instructions call out materialize() for
exactly this situation (let statements referenced more than once), and
three other files in this repo already use it for similar reasons.
@v-atulyadav v-atulyadav self-assigned this Aug 20, 2026
@v-atulyadav v-atulyadav added the Hunting Hunting specialty review needed label Aug 20, 2026
@v-atulyadav
v-atulyadav requested a lite review from Copilot August 20, 2026 03:09

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 a small “break-glass account” hunting pack to detect sign-in, credential/MFA modifications, and privilege path changes involving designated emergency access accounts via a shared BreakGlassAccounts watchlist.

Changes:

  • Adds a SigninLogs hunting query to flag any break-glass account sign-in activity.
  • Adds an AuditLogs hunting query to flag break-glass account credential and security-info changes (password/MFA).
  • Adds an AuditLogs hunting query to flag direct role assignment events and group-mediated membership changes for break-glass accounts.

Reviewed changes

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

File Description
Hunting Queries/SigninLogs/BreakGlassAccountSignIn.yaml New SigninLogs query to alert on any break-glass account sign-in within the time window.
Hunting Queries/AuditLogs/BreakGlassAccountCredentialsModified.yaml New AuditLogs query to detect password/credential and security-info (MFA) changes affecting break-glass accounts.
Hunting Queries/AuditLogs/BreakGlassAccountRoleOrGroupMembershipChanged.yaml New AuditLogs query combining role-management and group-management changes affecting break-glass accounts, including group-mediated privilege paths.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread Hunting Queries/AuditLogs/BreakGlassAccountRoleOrGroupMembershipChanged.yaml Outdated
Comment thread Hunting Queries/AuditLogs/BreakGlassAccountRoleOrGroupMembershipChanged.yaml Outdated
Comment thread Hunting Queries/AuditLogs/BreakGlassAccountCredentialsModified.yaml Outdated
Comment thread Hunting Queries/AuditLogs/BreakGlassAccountRoleOrGroupMembershipChanged.yaml Outdated
The three queries projected AccountUPN directly out of
_GetWatchlist('BreakGlassAccounts'), which fails validation with KS142
because a user-defined watchlist column cannot be resolved against a
known schema.

SearchKey is the standard indexed lookup column on a Sentinel watchlist
and is the column this lookup should use anyway. Documentation in all
three files updated to match.
@v-atulyadav

Copy link
Copy Markdown
Collaborator

Hi Descambiado (@descambiado),
Please review the suggestions and make the necessary changes accordingly. Once you have completed the requested changes, please click the Resolve conversation button.

Role changes now read the target user and the role name from whichever
TargetResources entry describes the user, matching what the group path
already did. The previous fixed index could miss detections when the
user object was not first, which the comments already acknowledged for
groups but not for roles.

Group name lookup uses coalesce(newValue, oldValue) so removals, which
carry the prior value in oldValue, keep the group display name instead
of falling back to the unavailable placeholder.

Added the dotted "Remove member from role." variant so both add and
remove are normalised the same way.

Credential matching includes the singular "credential" alongside
"credentials", since has_any is term-based and would otherwise miss
singular operation-name variants.

Description updated so it describes the extraction that both paths now
use rather than only the group path.
@descambiado

Copy link
Copy Markdown
Contributor Author

Thanks for the review. All four points addressed in ee49fbf:

Role target extraction. Fair catch, and the inconsistency was mine: the group path already read the user from whichever TargetResources entry describes it, while the role path still used a fixed index, and my own comment explained why a fixed index is unsafe. Both paths now use the same mv-apply on type =~ "User", taking the UPN and that entry's modifiedProperties together. Description updated so it reflects both paths rather than only the group one.

Group name on removals. Right, newValue is empty on removals and the name sits in oldValue. GroupNames now uses coalesce(newValue, oldValue), matching what RoleNames was already doing.

Singular credential term. Added "credential" alongside "credentials" in PasswordWords, since has_any is term-based and would otherwise miss singular variants.

Dotted remove variant. Added "Remove member from role." so add and remove are normalised the same way. I kept the explicit list rather than moving to a pattern match, since the surrounding queries in this folder use explicit OperationName lists, but happy to switch if you would rather see the pattern form.

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