Query Details
id: f2a3b4c5-d6e7-4f8a-9b0c-1d2e3f4a5b6c
name: "SigninLogs — Fresh IP Authenticating Multiple Accounts (Compromised Proxy)"
version: 1.0.0
kind: Scheduled
description: |
Detects an IP not seen in the prior 14 days that successfully authenticates 5 or more distinct user accounts within 2 hours. Indicates a newly-provisioned attack proxy or relay used with a purchased credential list. Complements the spray rule (failures) by catching pre-validated or successful spray runs. MITRE ATT&CK: T1110.003 (Password Spraying), T1078 (Valid Accounts).
severity: High
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- SigninLogs
queryFrequency: PT2H
queryPeriod: P14D
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
- InitialAccess
relevantTechniques:
- T1110
- T1078
query: |
// ---- Network Allowlist (exclude trusted IPs / CIDR / ranges) --------------
let _allow = materialize(union isfuzzy=true (print R="" | take 0), (_GetWatchlist('NetworkAllowlist') | project R = tostring(IPOrRange)) | where isnotempty(R));
let _allowCIDR = toscalar(_allow | where not(R matches regex @'^\d+\.\d+\.\d+\.\d+-\d+\.\d+\.\d+\.\d+$') | extend R = iff(R has '/', R, strcat(R, '/32')) | summarize make_list(R));
let _allowRange = toscalar(_allow | where R matches regex @'^\d+\.\d+\.\d+\.\d+-\d+\.\d+\.\d+\.\d+$' | summarize make_list(R));
let _ExcludeAllowlistedIPs = (T:(IPAddress:string)) {
T
| extend IPAddress = tostring(IPAddress)
| where array_length(_allowCIDR) == 0 or isnull(ipv4_is_in_any_range(IPAddress, _allowCIDR)) or not(ipv4_is_in_any_range(IPAddress, _allowCIDR))
| mv-apply _r = _allowRange to typeof(string) on (
extend _lo = tostring(split(_r,'-')[0]), _hi = tostring(split(_r,'-')[1])
| extend _inRange = ipv4_compare(IPAddress, _lo) >= 0 and ipv4_compare(IPAddress, _hi) <= 0
| summarize _anyInRange = max(toint(_inRange)))
| where isnull(_anyInRange) or _anyInRange == 0
| project-away _anyInRange
};
// ---------------------------------------------------------------------------
let lookback = 2h;
let baselineDays = 14d;
let minUsers = 5;
let KnownIPs =
SigninLogs
| invoke _ExcludeAllowlistedIPs()
| where TimeGenerated between (ago(baselineDays) .. ago(lookback))
| where ResultType == "0"
| distinct IPAddress;
SigninLogs
| invoke _ExcludeAllowlistedIPs()
| where TimeGenerated > ago(lookback)
| where ResultType == "0"
| where isnotempty(IPAddress)
| join kind=leftanti KnownIPs on IPAddress
| summarize
UniqueUsers = dcount(UserPrincipalName),
AuthenticatedUsers = make_set(UserPrincipalName, 30),
TotalLogins = count(),
Apps = make_set(AppDisplayName, 5),
Locations = make_set(Location, 3),
ClientTypes = make_set(ClientAppUsed, 5),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by IPAddress
| where UniqueUsers >= minUsers
| project
TimeGenerated = FirstSeen,
IPAddress, UniqueUsers, TotalLogins,
AuthenticatedUsers, Apps,
Locations, ClientTypes, LastSeen
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPAddress
customDetails:
UniqueUsers: UniqueUsers
TotalLogins: TotalLogins
alertDetailsOverride:
alertDisplayNameFormat: "Fresh IP Mass Auth — {{IPAddress}} authenticated {{UniqueUsers}} accounts (not seen in 14d)"
alertDescriptionFormat: "IP {{IPAddress}} (first seen in a 2h window — not in 14d baseline) successfully authenticated {{UniqueUsers}} distinct accounts — strong indicator of a newly-deployed attack proxy."
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: PT2H
matchingMethod: AllEntities
groupByEntities:
- IP
This query is designed to detect suspicious activity in sign-in logs, specifically focusing on identifying potential attack proxies or relays. Here's a simplified breakdown of what it does:
Purpose: The query aims to find IP addresses that have not been seen in the last 14 days but have successfully authenticated five or more distinct user accounts within a two-hour window. This behavior suggests the use of a newly-provisioned attack proxy or relay, potentially using a list of purchased credentials.
Exclusions: It excludes IP addresses that are on a predefined allowlist (trusted IPs or ranges) to avoid false positives from known safe sources.
Data Source: It uses data from Azure Active Directory's SigninLogs.
Detection Logic:
Output: For each suspicious IP address, it provides details such as:
Alerting: If such an IP address is detected, an alert is generated with a high severity level, indicating a potential security threat. The alert includes details about the IP address and the number of accounts it authenticated.
Incident Management: The query is set to create incidents for detected cases, with configurations for grouping related alerts and managing incident states.
Overall, this query helps in identifying and alerting on potential credential-based attacks using new IP addresses, enhancing security monitoring and response capabilities.

David Alonso
Released: April 20, 2026
Tables
Keywords
Operators