| name | user-account-guessing |
| description | Investigate whether a source machine attempted authentication using an unusually large number of distinct accounts against one or more systems, consistent with username enumeration or password spraying. Use when given authentication logs and asked to check for account/username guessing, password spraying, or enumeration from a single source. |
User Account Guessing
MITRE ATT&CK: T1110.003 (Password Spraying) and/or T1087 (Account
Discovery), depending on whether attempts show real passwords being tried
across many accounts (spraying) or are simply probing which usernames exist.
1. Which question am I trying to answer?
Did source machine X make authentication requests using Y number of
distinct accounts, against one or more machines, within a given time period —
consistent with an attacker enumerating or spraying against valid usernames
rather than a single compromised account being brute forced?
2. Which direct evidence do I need?
Per authentication event, scoped to a single source: Time, Source,
Destination, User, Success/Failure, Logon Type. The signal here is
distinct-user fan-out from one source — the mirror image of the
indiscriminate-lateral-movement analytic, which looks at distinct-
destination fan-out instead.
3. Where do I get that data?
- Windows Security.evtx: Event ID
4625 (failure) and 4624 (success)
— for password spraying, the volume of distinct users attempted matters
more than the failure/success split, since spraying is often tuned to stay
under per-account lockout thresholds.
- Entra ID / Okta sign-in logs — password spraying against cloud
identity is now at least as common as against on-prem AD; these logs
often already flag "unfamiliar sign-in properties."
- SSH bastion / VPN concentrator logs for the equivalent Linux-side
pattern (many distinct usernames from one source IP).
- NPS/RADIUS logs if authentication is brokered through network access
policy servers rather than directly against endpoints.
4. How do I analyze that data to answer the question?
Normalize into the shared schema (timestamp, user, source, destination, success, logon_type), then run:
python3 scripts/analyze.py --input auth_events.csv \
--window-minutes 30 --min-distinct-users 10
Logic: group events by source, slide a --window-minutes window, and
count distinct user values attempted inside it (successes and failures
both count — the point is breadth of accounts tried, not outcome). Windows
at or above --min-distinct-users are flagged along with the usernames and
destinations touched.
Tuning: password spraying is deliberately slow to evade per-account
lockout policies, so consider running this a second time with a wider window
(e.g. --window-minutes 1440 for a 24-hour view) in addition to the tight
default, since a spray campaign may not cluster tightly enough to trip a
30-minute window.
5. What answer does the analysis provide?
A list of (source, window, distinct_user_count, usernames, destinations)
findings. Interpretation:
- Sequential/alphabetical or common-username patterns (e.g.
admin,
administrator, svc-*, a dictionary-like sequence) in the username list
is a strong tell of automated guessing versus coincidental legitimate
traffic.
- Shared infrastructure as the source (a proxy, NAT gateway, VPN
concentrator, or shared workstation) can legitimately produce many
distinct users from one apparent "source" — check whether
source here
is a true endpoint IP or a shared egress point before treating high
fan-out as suspicious.
- All failures, zero successes across a large username set is
consistent with pure enumeration/spraying that hasn't yet succeeded — this
is still worth escalating pre-emptively, since it indicates the
environment is an active target.
- At least one success amid many distinct usernames tried is high
priority — cross-reference the successful account with
brute-force-logon
and impossible-travel for that same account to determine whether the
spray succeeded.
This analytic is most useful as an early-warning signal — by the time a
spray succeeds, you want to already know the source was probing broadly.