---¶
User Enumeration via Kerberos¶
Kerberos user enumeration exploits the different error codes the KDC returns for valid and invalid principal names. An attacker with nothing more than network access to the domain controller on port 88 can determine which usernames exist in the domain -- no credentials, no LDAP bind, no domain membership required.
How It Works¶
When the KDC receives an AS-REQ, it must look up the requested client principal (cname) in the Active Directory database before it can process the request. The KDC's response varies depending on whether the account exists and how it is configured:
| AS-REQ Scenario | KDC Response | Error Code |
|---|---|---|
| Principal does not exist | KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN |
6 |
| Principal exists, pre-auth required | KRB5KDC_ERR_PREAUTH_REQUIRED |
25 |
| Principal exists, pre-auth not required | Full AS-REP (TGT returned) | N/A |
| Principal exists, account disabled, locked, or expired | KDC_ERR_CLIENT_REVOKED |
18 |
The attacker sends AS-REQs without any pre-authentication data. For a non-existent principal, the KDC returns error 6 immediately. For an existing principal that requires pre-authentication (the default), the KDC returns error 25 -- telling the client to come back with pre-auth data. The difference between error 6 and error 25 reveals whether the username is valid.
sequenceDiagram
participant Attacker
participant KDC
Attacker->>KDC: AS-REQ (cname=administrator, no PA-DATA)
KDC->>Attacker: KRB5KDC_ERR_PREAUTH_REQUIRED (exists!)
Attacker->>KDC: AS-REQ (cname=nonexistent_user, no PA-DATA)
KDC->>Attacker: KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN (doesn't exist)
Attacker->>KDC: AS-REQ (cname=vuln_user, no PA-DATA)
KDC->>Attacker: AS-REP (exists + DONT_REQUIRE_PREAUTH!)
Bonus: AS-REP Roasting Discovery¶
When the KDC returns a full AS-REP (no error), the account exists and has DONT_REQUIRE_PREAUTH set. This simultaneously discovers the username and produces a crackable hash -- effectively combining user enumeration with AS-REP Roasting in a single request.
Use TCP transport for reliable results
Kerberos user enumeration over UDP may return KRB_ERR_RESPONSE_TOO_BIG for accounts without pre-authentication, because the full AS-REP exceeds the UDP datagram limit (~1470 bytes). Use TCP transport (--transport tcp) for reliable results.
Speed and Stealth¶
Kerberos enumeration is significantly faster and quieter than alternatives:
| Method | Auth Required | Port | Typical Speed | Logs Generated |
|---|---|---|---|---|
| Kerberos AS-REQ | No | 88 | Thousands/sec | 4768 per attempt |
| LDAP bind | Yes (anonymous or authed) | 389 | Hundreds/sec | Directory access logs |
| SMB session | No (null session, if allowed) | 445 | Slow | 4625 per attempt |
| RPC/SAMR | Yes | 135+ | Moderate | Object access logs |
Kerberos enumeration generates Event ID 4768 entries, but in environments with thousands of legitimate TGT requests per minute, the enumeration traffic blends in more easily than SMB logon failures.
Defend¶
This Cannot Be Fully Prevented¶
User enumeration through Kerberos error codes is fundamental protocol behavior. The KDC must distinguish between "principal not found" and "pre-auth required" to function correctly. There is no configuration that makes the KDC return the same error for both cases.
This is a known limitation acknowledged in [RFC 4120 §7.5.1]: the KDC error messages inherently reveal information about the principal database. The RFC recommends rate limiting as a mitigation.
Network-Level Rate Limiting¶
Since the protocol cannot be changed, the primary defense is limiting the rate at which an attacker can send AS-REQs:
- Firewall rate limiting: restrict the number of new connections to port 88 per source IP per time window
- Network segmentation: ensure that only authorized network segments can reach DCs on port 88
- IDS/IPS signatures: detect rapid-fire AS-REQ patterns from a single source
Monitor for Enumeration Patterns¶
Even if enumeration cannot be prevented, it can be detected (see the Detect section below). Early detection allows incident response before the attacker uses the validated usernames for further attacks like password spraying.
Reduce Information Leakage¶
While the core enumeration cannot be prevented, you can reduce its value:
- Use unpredictable username formats:
first.lastis easily guessed from public information; formats likeflast+ department code or employee ID are harder to enumerate - Avoid publishing employee directories: limit exposure of full name lists that can be converted to username patterns
Detect¶
Event ID 4768 with Failure Code 6¶
The most direct signal is a burst of Event ID 4768 entries with failure status 0x6 (principal unknown) from a single source IP. Legitimate clients almost never trigger this error because they know their own username.
index=security EventCode=4768 Status=0x6
| bin span=5m _time
| stats count, dc(TargetUserName) as unique_names by IpAddress, _time
| where unique_names > 50
Mixed Success/Failure Pattern¶
During enumeration, the attacker hits both valid and invalid usernames. Look for a single source producing a mix of:
- Status
0x6(principal unknown) -- invalid usernames - Status
0x19(preauth required, logged as failure in some configurations) -- valid usernames - Successful 4768 events (for no-preauth accounts) -- valid usernames
index=security EventCode=4768
| bin span=5m _time
| stats dc(TargetUserName) as unique_users,
sum(eval(if(Status="0x6",1,0))) as not_found,
sum(eval(if(Status="0x0" OR Status="0x19",1,0))) as found
by IpAddress, _time
| where unique_users > 30 AND not_found > 10
SIEM Correlation Rule¶
A practical detection rule: alert when more than 50 unique usernames are attempted from a single source IP within 5 minutes, with at least some returning error code 6.
Honeypot Usernames¶
If you know common username patterns that attackers generate from wordlists (e.g., admin, test, backup, scanner), create disabled accounts with these names. Any 4768 event for these accounts indicates enumeration activity. Since the accounts are disabled, the KDC returns KDC_ERR_CLIENT_REVOKED (error 18) rather than error 25, but the attempt is still logged.
Exploit¶
1. Generate a Username Wordlist¶
Build a list of potential usernames based on the target organization's naming convention. Common patterns:
| Format | Example | Source |
|---|---|---|
first.last |
john.smith |
LinkedIn, company website |
flast |
jsmith |
Common corporate format |
firstl |
johns |
Less common but used |
first_last |
john_smith |
Some organizations |
| Standard accounts | administrator, krbtgt, guest |
Always present |
Tools for generating username lists from names:
# Simple first.last generation from a names file
awk '{print tolower($1"."$2)}' names.txt > usernames.txt
2. Send AS-REQ for Each Username¶
For each username in the list, send an AS-REQ with:
cnameset to the target usernamesnameset tokrbtgt/<REALM>- No
PA-DATA(no pre-authentication data) - The
etypefield can contain any supported types; it does not affect enumeration
The AS-REQ is small and the KDC's error response is immediate, so this can be performed at high speed.
3. Classify Responses¶
| Error Code | Classification | Next Steps |
|---|---|---|
6 (C_PRINCIPAL_UNKNOWN) |
Does not exist | Discard |
25 (PREAUTH_REQUIRED) |
Exists (normal account) | Add to validated list |
18 (CLIENT_REVOKED) |
Exists (disabled, locked, or expired) | Note status, may still be useful |
| No error (AS-REP) | Exists + no pre-auth | Add to validated list and extract AS-REP hash |
4. Use the Validated List¶
The validated username list feeds directly into subsequent attacks:
- Password Spraying: spray common passwords against confirmed accounts
- AS-REP Roasting: any accounts that returned a full AS-REP are immediately roastable
- Targeted phishing: knowing exact usernames improves spear-phishing success rates
- OSINT correlation: map validated usernames back to real employees for social engineering
Tools¶
kerbwolf¶
kerbwolf does not include a dedicated user enumeration tool. The kw-asrep command performs AS-REQ requests and will implicitly enumerate users (accounts that require pre-auth are "silently skipped"), but it does not report the error code distinction between "exists with pre-auth" and "does not exist."
Dedicated Enumeration Tools¶
CredWolf (Python)¶
CredWolf is a dual-protocol (Kerberos + NTLM) credential validation tool with a dedicated userenum subcommand. It automatically classifies KDC responses into specific account statuses (valid, disabled, expired, locked, non-existent) and flags ASREProastable accounts during enumeration.
# Enumerate from a user list
credwolf -d CORP.LOCAL userenum --kdc-ip 10.0.0.1 -U users.txt
# Single user check
credwolf -d CORP.LOCAL userenum --kdc-ip 10.0.0.1 -u administrator
# Write valid usernames to a file
credwolf -d CORP.LOCAL -o valid_users.txt userenum --kdc-ip 10.0.0.1 -U users.txt
# Use TCP transport instead of UDP (default)
credwolf -d CORP.LOCAL userenum --kdc-ip 10.0.0.1 -U users.txt --transport tcp
# Rate-limit requests to avoid IDS detection
credwolf -d CORP.LOCAL userenum --kdc-ip 10.0.0.1 -U users.txt --delay 2 --jitter 0.5
Key features for enumeration:
- Automatic ASREProastable detection: accounts with
DONT_REQUIRE_PREAUTHare flagged asno_preauth (ASREProastable)during the enumeration pass -- no separate AS-REP roasting step needed - Full account status detection: distinguishes between disabled, expired, locked, and non-existent accounts based on KDC error codes, rather than just "exists" vs "doesn't exist"
- UDP and TCP transport: UDP by default for speed, TCP with
--transport tcpwhen needed - Rate limiting:
--delay(seconds between requests) and--jitter(random additional delay) to control request rate - Output to file:
-owrites valid usernames to a file for piping into subsequent attacks
kerbrute (Go)¶
The most widely used Kerberos enumeration tool. Fast, cross-platform, and handles the error code classification automatically.
# Enumerate users from a wordlist
kerbrute userenum -d CORP.LOCAL --dc 10.0.0.1 usernames.txt
# Output shows which users exist and which returned AS-REPs
# [+] VALID USERNAME: administrator@CORP.LOCAL
# [+] VALID USERNAME: jsmith@CORP.LOCAL
# [+] jsmith@CORP.LOCAL has no pre auth required. Dumping hash...
nmap krb5-enum-users¶
The krb5-enum-users NSE script performs Kerberos enumeration during an nmap scan:
nmap -p 88 --script krb5-enum-users --script-args krb5-enum-users.realm='CORP.LOCAL',userdb=users.txt 10.0.0.1
Rubeus brute¶
Rubeus can enumerate users as part of its brute-force mode by observing KDC error codes:
Tool Comparison¶
| Tool | Platform | Protocols | Speed | ASREProastable Detection | Account Status Detection | AES Support | Output Format |
|---|---|---|---|---|---|---|---|
| CredWolf | Cross-platform (Python) | Kerberos + NTLM | Fast | Yes (automatic) | Yes (disabled/expired/locked/non-existent) | Yes | Text, file (-o) |
| kerbrute | Cross-platform (Go) | Kerberos | Very fast (concurrent) | Yes | Partial (exists vs not found) | No | Text, JSON |
| nmap NSE | Cross-platform | Kerberos | Moderate | No | No | No | nmap XML/text |
| Rubeus | Windows (.NET) | Kerberos | Fast | Yes (with /hashfile) |
Partial | No | Console/file |