Step 262. Active Directory 2 — Kerberoasting and AS-REP Roasting

Step 262. Active Directory 2 — Kerberoasting and AS-REP Roasting

Level 3 — Real-World CTF & Advanced Offensive Skills | Difficulty ★★★★☆ | Estimated time: 4 hours

Prerequisites: You understand Step 261’s domain structure (the five Kerberos steps, SPNs). You’ve experienced offline cracking (hashcat) in Steps 123–124.

  • What you need: An AD lab on THM/HTB (one domain account required). This environment has no AD domain, so all attack scenes are presented as output examples — learning the hash formats and command structures is today’s practice.
  • ⚠️ All exercises in this chapter are for your own lab and legal platforms only. Applying them to unauthorized systems is a crime.

Step 261 left two sentences behind — "the service ticket arrives encrypted with the service account’s password," and "any domain user can request a service ticket." Today you mesh those two sentences to assemble AD’s flagship attack, Kerberoasting. Receiving a ticket through the normal path, then quietly cracking it at home — what makes this attack frightening is that it leaves no anomaly on the network at all. The cousin attack AS-REP Roasting, plus "so how do you defend against it?" — that’s today’s full set.


1. Learning Objectives

By the end of this chapter, you will be able to:

  • Explain, on top of the Kerberos flow, why Kerberoasting is "abuse of a normal feature"
  • Know the procedure for enumerating SPN accounts and extracting TGS tickets in a crackable format
  • Read the structure of the $krb5tgs$ hash format
  • Know AS-REP Roasting’s prerequisite (pre-authentication disabled) and how it differs from Kerberoasting
  • Describe the offline cracking flow with hashcat modes 13100/18200
  • Connect each defensive measure (long service passwords, gMSA, enforced pre-authentication) to its technique

2. Background Knowledge — Today’s Tools and Concepts

Today’s Tools at a Glance

Category Details
Language/environment Kali (Impacket) + hashcat — all output examples based on labs
Today’s tools GetUserSPNs.py (Impacket), GetNPUsers.py, hashcat -m 13100 / -m 18200
Concepts needed SPNs, the encryption structure of TGS tickets, pre-authentication, offline cracking
Today’s deliverable One Kerberoasting/AS-REP attack flow diagram + a defense mapping table

2-1. Assembling Kerberoasting — Meshing Two Sentences

Unroll Step 261’s Kerberos picture. You can see the point where the attack arrow lands on the TGS-REP (service ticket issuance) arrow:

  1. Any domain user can say "give me a service ticket for that SPN" (TGS-REQ) — normal feature
  2. The KDC hands over that ticket encrypted with a key derived from the service account’s password — normal feature
  3. The attacker carries the received ticket off the network — the attack starts here
  4. At home, they try password candidates one by one: "does the ticket open with this key?" — offline cracking (exactly the method from Step 123)
  5. The moment it opens, that password = the service account is compromised

The culprit doesn’t smash the safe — they legitimately receive a test copy of the safe’s key and take it home to fit a key to it. From the DC’s standpoint, it "merely issued a ticket" — all that remains in the log is a normal ticket request. That is the weight of the word "offline."

2-2. Conditions of the Prey — Which Accounts Get Hit

Not every account falls to Kerberoasting. There are three conditions:

  • It has an SPN attached — there must be a ticket-ordering address for an order to go through. Usually service accounts like svc_sql (Step 261’s setspn -Q */* is the hunting list).
  • It uses a human-chosen password — cracking is dictionary + rule attacks, so "human-ish" passwords like Summer2026! fall. Conversely, a random password of 25+ characters effectively never cracks — this becomes the core of the defense.
  • Computer accounts (names ending in $) have SPNs but their passwords are system-generated 128-character random values, so they’re effectively immune — just exclude them from the hunting list.

2-3. AS-REP Roasting — The Loophole at the Wristband Window

Kerberos originally has a safety device — before handing out a TGT (wristband), it tests you: "first decrypt this timetable encrypted with your password," called pre-authentication. But if that’s turned off in the account settings (the Do not require Kerberos preauthentication checkbox — a trap left for legacy compatibility), then a request of "give me that account’s AS-REP" goes through with no password at all.

The returning AS-REP response contains a part encrypted with a key derived from that account’s password — again, take it away for offline cracking. Summarizing the difference:

  • Kerberoasting: a domain account is required (only authenticated users can request tickets) / prey = accounts with SPNs / cracking target = TGS ticket
  • AS-REP Roasting: works without a domain account (just the names of pre-auth-disabled accounts) / prey = pre-auth-disabled accounts / cracking target = AS-REP response

Both arrive at the same destination — "take a ciphertext home and crack it."

2-4. Reading the Hash Format — Dissecting $krb5tgs$

To feed a ticket to a cracking tool (hashcat), you convert it into an agreed string format. Get familiar with what the format looks like in advance (structure example):

$krb5tgs$23$*alice$CORP.LOCAL$MSSQLSvc/db01.corp.local:1433*$<16-char checksum>$<several hundred chars of encrypted ticket body...>

Reading the $-separated compartments: krb5tgs = a Kerberos TGS ticket / 23 = encryption type (RC4-HMAC family) / alice = the user who requested the ticket / CORP.LOCAL = the realm (domain) / MSSQLSvc/... = the SPN / the long blob at the end = the actual ciphertext being cracked. This one line is "a ticket that can be saved to a file," and hashcat distinguishes these formats by mode number — TGS cracking is -m 13100, AS-REP is -m 18200.

2-5. Why the Defenses Work

Both of today’s attacks rely on crackability, so the defenses gather toward making cracking futile:

  • Service account passwords: 25+ random characters — a length dictionary and rule attacks can never reach
  • gMSA (Group Managed Service Accounts) — AD auto-generates the password as 128 random characters and rotates it periodically. No human chose it, so cracking doesn’t even apply
  • Enforced pre-authentication — audit and clear the "Do not require preauthentication" checkbox across all domain accounts. Removes AS-REP Roasting’s prerequisite
  • Detection — requesting tickets for many SPNs in a short time is an anomaly (a spike in event ID 4769)

3. Follow Along

This environment has no AD domain, Impacket, or hashcat (confirmed by measurement 2026-09-09: neither hashcat nor impacket-GetUserSPNs is installed), so today’s Follow Along is training to read output examples and reproduce the flow by hand. Commands are written in real form so you can use them as-is when you enter a lab.

3-1. Checking the Prerequisite — One Domain Account Is the Starting Point

Everything begins with "one domain account." Phishing, a web vulnerability, a spray attack (Step 165) — the method varies, but the opening of an AD attack is the same. Labs usually hand you an account like corp.local\alice:Password123.

Flow check: Draw today’s attack arrows on top of Step 261’s picture — four arrows: "alice (domain user) sends a TGS-REQ for svc_sql’s SPN → receives the ticket → carries it off the network → offline cracking."

3-2. Building the SPN Hunting List — Output Example

Impacket’s GetUserSPNs.py does SPN enumeration and ticket requesting in one go:

GetUserSPNs.py corp.local/alice:Password123 -dc-ip 10.10.10.10

Output example:

ServicePrincipalName            Name       MemberOf  PasswordLastSet             LastLogon
------------------------------  ---------  --------  --------------------------  --------------------------
MSSQLSvc/db01.corp.local:1433   svc_sql              2026-01-15 09:12:33         2026-09-01 14:02:11
HTTP/backup.corp.local          svc_backup           2025-11-02 10:41:07         <never>

How to read it: This table is the hunting list. Reading order — ① Name: the account names the SPNs are attached to (svc_sql, svc_backup). ② PasswordLastSet: when the password was last changed — the older it is, the higher the chance it’s "a weak password a human set long ago." Doesn’t svc_backup, frozen since November 2025, look promising? ③ An empty MemberOf (as here) means no privileged groups — in labs, a service account with Domain Admins in this column is the jackpot prey.

3-3. Requesting and Extracting Tickets — Output Example

The -request option "actually orders the tickets and outputs them in cracking format":

GetUserSPNs.py corp.local/alice:Password123 -dc-ip 10.10.10.10 -request

Output example (excerpt — note the format’s structure):

ServicePrincipalName            Name      ...
------------------------------  --------  ...
...
$krb5tgs$23$*alice$CORP.LOCAL$MSSQLSvc/db01.corp.local:1433*$a1b2c3d4e5f60718$9f8e7d6c...(several hundred chars)

How to read it: Exactly the $krb5tgs$ format dissected in 2-4. Save this entire long line to a file and the cracking material is complete:

GetUserSPNs.py corp.local/alice:Password123 -dc-ip 10.10.10.10 -request > tgs.txt

The only trace left on the DC so far is a "normal ticket issuance" log. The attack’s online part ends with this one request — everything after is offline.

3-4. Offline Cracking — Output Example

Exactly the hashcat you learned in Steps 123–124. Only the mode number is new:

hashcat -m 13100 tgs.txt /usr/share/wordlists/rockyou.txt

Output example:

$krb5tgs$23$*alice$CORP.LOCAL$MSSQLSvc/...:Summer2026!

Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 13100 (Kerberos 5, etype 23, TGS-REP)

How to read it: With Status: Cracked, the Summer2026! appended after the ticket is the recovered password. The service account svc_sql‘s password has been stolen. What follows — log into the DB server with this account, and aim for the next step with that account’s privileges (sometimes domain-admin level). Conversely, if Exhausted (dictionary exhausted, not cracked) shows here, that’s a result too — "the defense worked" becomes a line in your report.

3-5. AS-REP Roasting — Output Example

Hunting accounts with pre-authentication disabled. With just an account list (users.txt), you try without any password:

GetNPUsers.py corp.local/ -dc-ip 10.10.10.10 -no-pass -usersfile users.txt

Output example:

$krb5asrep$23$bob@CORP.LOCAL:c4d3e2f1...(several hundred chars)

How to read it: The only difference is the format changed to $krb5asrep$ — it’s the encrypted part of an AS-REP response. The bob account had pre-authentication disabled. Cracking just changes the mode:

hashcat -m 18200 asrep.txt rockyou.txt

Flow summary: If Kerberoasting is "collecting passes after entering," AS-REP Roasting is "collecting wristband responses before entering." Only the prerequisite (whether a domain account is needed) differs; the finish (offline cracking) is the same.

3-6. Completing the Defense Mapping Table

Pair the four attack steps with defenses and organize them on paper — this table is half of today’s deliverable:

Attack step Defensive measure How it works
SPN enumeration (Hard to block — a normal feature)
Ticket collection Anomaly detection (4769 spike) Many SPN requests in a short time is abnormal
Offline cracking 25+ char random passwords / gMSA Makes cracking itself futile
(AS-REP) pre-auth bypass Enforced pre-auth audit Removes the prerequisite

4. Missions & Exercises

Mission — Kerberoasting Flow Diagram and Cracking Reproduction

  1. Lay today’s four attack arrows (TGS-REQ → collection → exfiltration → cracking) onto Step 261’s Kerberos picture to complete the "attack flow diagram"
  2. Dissect a $krb5tgs$ format string (the 3-3 output example) compartment by compartment and write each part’s meaning
  3. (If you have a lab) Extract a ticket with GetUserSPNs.py -request in a THM/HTB AD room, crack it with hashcat -m 13100, and save the Status: Cracked screen as evidence
  4. (In the lab) Find pre-auth-disabled accounts with GetNPUsers.py and attempt -m 18200 cracking
  5. If there was an account that did not crack, write one report sentence using that case: "the defense worked"

Exercises

Q1. Explain why, in Kerberoasting, the DC’s logs show only "normal ticket issuance," not "an attack."

Q2. Compare Kerberoasting and AS-REP Roasting across four items: prerequisite, prey, cracking target, and hashcat mode.

Q3. Explain why changing a service account’s password to 25+ random characters is a complete defense against Kerberoasting, from the perspective of how cracking works.

Q4. State two reasons gMSA is fundamentally safer than accounts with "human-chosen passwords."


5. Model Answers & Completion Criteria

Mission Model Answer

How to verify the flow diagram: Check that four arrows are laid on the TGS-REQ/TGS-REP stretch of Step 261’s picture — ① alice ordering via svc_sql’s SPN, ② receiving the encrypted ticket, ③ exfiltrating it as a file (tgs.txt), ④ hashcat trying rockyou.txt against it. Full marks if a note "offline — the DC doesn’t know" sits beside ④.

The correct dissection: $krb5tgs$ / 23 (etype, RC4-HMAC) / requesting user / realm / SPN / checksum / ciphertext body — cross-check against 2-4’s table.

Evidence of successful cracking: The hashcat output’s Status...: Cracked and the recovered password must be saved. A non-crack (Exhausted) is also evidence — in that case, an interpretation sentence must be attached: "the dictionary and rules couldn’t reach this password’s length/composition = the defense worked" for the mission to be complete.

Exercise Answers

A1. The attacker merely walks Kerberos’ normal procedure — an authenticated domain user requesting a service ticket for an SPN. The cracking that happens after receiving the ticket occurs inside the attacker’s computer, unrelated to the DC. There’s no protocol violation and no anomalous packet, so signature detection is hard — which is why detection must detour through "behavior patterns" (many SPN requests in a short time).

A2. Prerequisite: Kerberoasting needs a domain account; AS-REP doesn’t (account names only). Prey: accounts with SPNs / accounts with pre-authentication disabled. Cracking target: TGS ticket / AS-REP response. hashcat mode: -m 13100 / -m 18200. The common ground is the structure "take a ciphertext and crack it offline."

A3. Offline cracking is an attempt that tries dictionary words and mutation rules in order. Success depends on "is the password inside that candidate set?" — and a random string of 25+ characters lies outside the reach of any dictionary/rule combination, while exhaustive search has an astronomical combination count that doesn’t finish in realistic time. Making it impossible to crack even after the ticket is taken — a defense that nullifies the attack’s final step.

A4. First, the password is a 128-character random value generated by AD, so it doesn’t exist in any cracking candidate set to begin with. Second, AD rotates it automatically on a schedule, so even if a past ticket leaks, its validity window is short — and there’s no room for a human to revert it to "a memorable value." It’s a case where the structure "human memorability equals vulnerability" is removed by design.

Completion Criteria Checklist

  • [ ] Can state Kerberoasting’s five steps in order (request → collection → exfiltration → cracking → compromise)
  • [ ] Can read each compartment’s meaning in the $krb5tgs$ format
  • [ ] Know the difference between what -m 13100 and -m 18200 target
  • [ ] Can explain AS-REP Roasting’s prerequisite (pre-authentication disabled)
  • [ ] Know why accounts with an old PasswordLastSet are promising
  • [ ] Can connect the 4 defenses (long passwords, gMSA, pre-auth, 4769 detection) to attack steps
  • [ ] Mission: completed attack flow diagram + format dissection + (lab) cracking evidence

6. Common Pitfalls & Fixes

Wall 1. GetUserSPNs.py throws an authentication error

Symptom (output example): KDC_ERR_PREAUTH_FAILED or SessionError: ....

Cause: The account name, password, or domain notation is wrong. The most common is the domain notation — corp.local/alice vs CORP.LOCAL/alice, or alice actually belonging to a different domain.

Fix: Check in order — ① the domain/user:password notation ② whether -dc-ip is the actual DC’s IP ③ re-copy the account string exactly as the lab gave it. When stuck at the authentication-error stage, nine times out of ten it’s spelling.

Wall 2. Got the ticket but hashcat can’t read the format

Symptom (output example): No hashes loaded. or Token length exception.

Cause: The file has junk mixed in besides the ticket (table headers, broken newlines), or a one-line ticket got saved split across multiple lines.

Fix: Open tgs.txt and keep only the one whole line starting with $krb5tgs$. A ticket string is a single line of several hundred characters — a newline in the middle makes a dead hash. Also check that the mode number (-m 13100) matches the format ($krb5tgs$) — running an AS-REP through 13100 produces the same symptom.

Wall 3. Cracking never finishes

Symptom: hashcat has been Running for hours.

Candidate causes: ① The dictionary is small or has no rules — or conversely ② the password is genuinely strong and won’t crack.

Fix: Lab passwords are mostly inside rockyou.txt — first check that the dictionary and mode are right. If it still fails, that is the conclusion — as learned in 2-5, an "uncrackable password" means the defense worked, and Exhausted is a valid result in a report. Don’t run it indefinitely; the judgment to move to another path (another account, another technique) is also skill.

Wall 4. No SPNs come back at all

Symptom: GetUserSPNs.py returns an empty table.

Candidate causes: ① The domain really has no service accounts (happens in small labs) ② something went wrong at the list-query stage without -request.

Fix: Cross-check from another angle — inside a lab machine, does setspn -Q */* (Step 261) show the same list? If both are empty, record this path as dead and move to AS-REP Roasting (pre-auth-disabled accounts) or another chapter’s path. Confirming "none" is also an enumeration result.

Wall 5. The attack worked but I can’t explain "why it worked"

Symptom: The commands ran and the password came out, but you freeze when asked the principle.

Cause: You merely typed along with commands without laying them on the Kerberos picture.

Fix: Pull Step 261’s five-arrow picture back out and point with your finger at which arrow what you just did abused — TGS-REP. When the sentence "I legitimately received a normal issuance arrow and cracked it offline" comes out, you’ve explained it. If you can’t point at what a tool does on the picture, you can’t yet say you know that attack.


7. Summary

Today’s Concepts

Concept One-line description
Kerberoasting Receive an SPN account’s TGS ticket and crack it offline — abuse of a normal feature
Offline cracking Taking a ciphertext off the network to break — the victim never knows
AS-REP Roasting Cracking the AS-REP response of a pre-auth-disabled account — possible without an account
$krb5tgs$ / $krb5asrep$ Ticket string formats for cracking — modes 13100 / 18200
gMSA AD-managed 128-char automatic passwords — structurally neutralizes cracking
Event 4769 Ticket issuance log — a short-time spike is a detection signal

Today’s Commands (All Output Examples)

Command What it does
GetUserSPNs.py domain/user:password -dc-ip DC_IP SPN hunting list
... -request > tgs.txt Order tickets + save in cracking format
hashcat -m 13100 tgs.txt rockyou.txt Crack TGS tickets
GetNPUsers.py domain/ -dc-ip DC_IP -no-pass -usersfile users.txt Harvest pre-auth-disabled accounts
hashcat -m 18200 asrep.txt rockyou.txt Crack AS-REP

The Instinct That Matters More Than Commands

The essence of today’s attacks is not technique but location — the ciphertext sits "in a place the attacker can take away." Kerberos is a fine design, but it can’t prevent the property that "whoever receives a ticket can take it home." That’s why the defensive conclusion gathers not toward "blocking requests" but "making cracking useless" (25-char random, gMSA). Learn the attack and the defense’s design rationale becomes visible; look at the defense and the attack’s limits become visible — the habit of reading in both directions is the core strength of this whole course.


Once every box is checked, Step 262 is complete. Click the checkbox in the sidebar to save your progress.