Kerberos in PCAP
Kerberos is Windows Active Directory's authentication protocol — it runs on UDP/TCP port 88 and is visible in PCAP. Understanding Kerberos traffic lets you detect Kerberoasting (service ticket requests for offline hash cracking), AS-REP Roasting (requests for accounts without pre-authentication), Golden/Silver Ticket attacks, and pass-the-ticket lateral movement. The Kerberos exchange is relatively simple and highly diagnostic when you know what to look for.
During a purple team exercise, you need to detect Kerberoasting in PCAP. The attacker ran Invoke-Kerberoast from a compromised workstation, requesting TGS tickets for all service accounts. In the PCAP you see: one TGT (AS-REQ/AS-REP) from the compromised account, followed immediately by 47 TGS-REQ/TGS-REP exchanges requesting service tickets for 47 different SPNs — all within 3 seconds. No human user requests tickets for 47 services in 3 seconds. That's the detection.
Kerberos Protocol Flow
Kerberos Authentication Flow — Forensic Map
═══════════════════════════════════════════════════════════════════
Phase 1: Authentication (Getting the TGT)
Client → KDC: AS-REQ (Authentication Service Request)
├── msg-type: 10 (AS-REQ)
├── kerberos.CNameString: username requesting authentication
├── kerberos.realm: domain (e.g., CORP.LOCAL)
├── kerberos.till: requested ticket expiry time
└── kerberos.padata-type:
PA-ENC-TIMESTAMP (2): client sent encrypted timestamp (pre-auth)
[no padata]: no pre-auth (AS-REP Roasting target)
KDC → Client: AS-REP (Authentication Service Reply)
├── msg-type: 11 (AS-REP)
├── Contains TGT (Ticket Granting Ticket), encrypted with KDC key
└── krbtgt encrypted portion: targets of AS-REP Roasting
Phase 2: Service Ticket Request
Client → KDC: TGS-REQ (Ticket Granting Service Request)
├── msg-type: 12 (TGS-REQ)
├── kerberos.SNameString: requested service SPN
│ e.g., MSSQLSvc/sql01.corp.local:1433
│ HTTP/sharepoint.corp.local
│ CIFS/fileserver.corp.local
└── Includes TGT (presented as proof of identity)
KDC → Client: TGS-REP (TGS Reply)
├── msg-type: 13 (TGS-REP)
├── Service ticket encrypted with SERVICE ACCOUNT's password hash
└── KERBEROASTING TARGET: this encrypted blob can be cracked offline
Phase 3: Service Authentication
Client → Service: AP-REQ
├── msg-type: 14 (AP-REQ)
└── Presents service ticket to actual service (not KDC)
Service → Client: AP-REP (success) or KRB-ERROR (failure)
KRB-ERROR codes:
18: KDC_ERR_CLIENT_REVOKED (disabled account)
23: KDC_ERR_KEY_EXPIRED (password expired)
37: KDC_ERR_BAD_INTEGRITY (wrong password — bad hash)
Kerberoasting Detection in PCAP
#!/bin/bash
PCAP="$1"
echo "=== Kerberos TGT Requests (AS-REQ) ==="
tshark -r "$PCAP" -n -Y "kerberos.msg_type==10" -T fields \
-E separator="\t" \
-e frame.time_epoch \
-e ip.src \
-e ip.dst \
-e kerberos.CNameString \
-e kerberos.realm \
| head -30
echo ""
echo "=== TGS Requests (potential Kerberoasting) ==="
tshark -r "$PCAP" -n -Y "kerberos.msg_type==12" -T fields \
-E separator="\t" \
-e frame.time_epoch \
-e ip.src \
-e kerberos.CNameString \
-e kerberos.SNameString \
| head -100
echo ""
echo "=== TGS Request count per source (bulk = Kerberoasting) ==="
tshark -r "$PCAP" -n -Y "kerberos.msg_type==12" -T fields \
-e ip.src \
| sort | uniq -c | sort -rn | head -20
echo ""
echo "=== Unique SPNs requested per source (>5 = suspicious) ==="
tshark -r "$PCAP" -n -Y "kerberos.msg_type==12" -T fields \
-E separator="\t" \
-e ip.src -e kerberos.SNameString \
| sort -u | awk -F'\t' '{print $1}' | sort | uniq -c | sort -rn | head -20
echo ""
echo "=== AS-REP Roasting (AS-REQ without padata pre-auth) ==="
# msg_type==10 with no PA-ENC-TIMESTAMP padata
tshark -r "$PCAP" -n \
-Y "kerberos.msg_type==10 and not kerberos.padata_type==2" \
-T fields \
-E separator="\t" \
-e frame.time_epoch -e ip.src -e kerberos.CNameString \
| head -20
echo ""
echo "=== Kerberos errors (brute force, bad credentials) ==="
tshark -r "$PCAP" -n -Y "kerberos.msg_type==30" -T fields \
-E separator="\t" \
-e frame.time_epoch -e ip.src -e kerberos.error_code \
| sort | uniq -c | sort -rn | head -20
echo ""
echo "=== Golden Ticket indicators (unusually long TGT lifetime) ==="
tshark -r "$PCAP" -n -Y "kerberos.msg_type==11" -T fields \
-E separator="\t" \
-e frame.time_epoch -e ip.dst -e kerberos.till \
| head -20
Kerberos Attack Signatures in PCAP
| Attack | PCAP Signature | Display Filter |
|---|---|---|
| Kerberoasting | One source requests TGS for 5+ different SPNs within seconds | kerberos.msg_type==12 |
| AS-REP Roasting | AS-REQ without PA-ENC-TIMESTAMP padata for multiple accounts | kerberos.msg_type==10 |
| Golden Ticket | TGS-REQ with no prior AS-REQ from same source; unusually long lifetime | kerberos.msg_type==12 and not kerberos.msg_type==10 |
| Silver Ticket | AP-REQ directly to service with no TGS-REQ to KDC | kerberos.msg_type==14 without preceding type 12 |
| Pass-the-Ticket | TGT or service ticket reused from different source IP | Same session ID (kerberos.cname) from multiple IPs |
| Brute Force | Many AS-REQ with error code 23 (bad password) or 18 (disabled) | kerberos.error_code==23 |
| Overpass-the-Hash | Kerberos request from host that hasn't previously used Kerberos | Correlate with SMB NTLM auth from same source |
Normal Kerberos traffic is boring: a user logs in (one AS-REQ/AS-REP), accesses a few services (one TGS-REQ/TGS-REP per service type), and then authenticates to those services (AP-REQ). The entire day's Kerberos activity from a single user might be 5–20 ticket requests. Kerberoasting produces 50–500 TGS-REQ messages in under 60 seconds from a single source. AS-REP Roasting produces AS-REQ messages for usernames the attacker enumerated from LDAP. Golden Ticket attacks bypass the KDC entirely — you see AP-REQ to services but no corresponding TGS-REQ in the same time window. The pattern is always rate or sequence anomaly — never a single message that's inherently malicious. Context (what happened before and after, how many, how fast) is the detection signal.
Q & A
Q: How do I identify if a Kerberos TGS response contains a crackable hash for Kerberoasting?
In Kerberoasting, the TGS-REP contains a service ticket encrypted with the service account's password hash (specifically, the portion encrypted with RC4-HMAC or AES128/AES256 depending on configuration). In PCAP: (1) Capture the TGS-REP (kerberos.msg_type == 13), (2) The encrypted service ticket is visible as raw bytes in the kerberos.ticket.enc-part.cipher field. (3) The etype (encryption type) field identifies the cipher: etype=23 is RC4-HMAC (crackable with hashcat -m 13100), etype=17/18 is AES128/AES256 (much harder to crack). If you see TGS-REP with etype=23 in a modern environment, that's significant — modern AD environments should have AES only for service accounts. Defenders who force AES-only service account encryption make Kerberoasting attacks orders of magnitude harder to crack even when the ticket is captured. Tools like tgsrepcrack, Impacket's GetUserSPNs.py, and Rubeus all extract the crackable hash from the captured TGS-REP.