Lab 02 — Kerberos / Identity Exposure Analyzer

Lens: The directory's Kerberos and identity weaknesses, account-by-account. WARMUP: Chapters 5–8 (the Kerberos dance, Kerberoasting, AS-REP roasting, the three delegations). Engagement tie-in: Operation Cedar Lattice, Phase 05. Lab 01 found the path through Meridian's directory graph; this analyzer finds the exposed accounts that make the path possible — the Kerberoastable service account whose crack opens the first door, the unconstrained-delegation server that hands you a Domain Admin's ticket — and pairs each with its detection and fix.

The problem

Lab 01 walks the directory graph. This lab reads the directory facts and asks the question a red team answers in the first hour and a defender should have answered first: which accounts are exposed, by which technique, and how do I detect and remediate each one? These are the canonical Kerberos and identity weaknesses:

  • Kerberoasting (T1558.003) — a user account with a Service Principal Name. Any domain user can request a service ticket (TGS) for it; the reply is encrypted with the account's password-derived key, so it can be cracked offline. RC4 encryption plus an old/weak password makes the crack trivial. A gMSA (128-char auto-rotated key) is effectively immune.
  • AS-REP roasting (T1558.004) — an account with Kerberos pre-authentication disabled. The KDC returns an AS-REP encrypted with the account's key without proof of identity, so anyone can request and crack it offline.
  • Unconstrained delegation — a computer that caches the TGT of every user who authenticates to it. Compromise it (or coerce a DC to authenticate to it, PetitPotam-style) and you replay a captured TGT, including a Domain Admin's. The single highest-severity delegation flag.
  • RBCD-writable — an object whose msDS-AllowedToActOnBehalfOfOtherIdentity an attacker can write. That grants resource-based constrained delegation: impersonate any user to the object.
  • Privileged account with an SPN — a Domain/Enterprise Admin (or adminCount=1) carrying an SPN is a Kerberoastable account whose crack yields domain-level privilege directly — the worst case.

What you build (lab.py)

The Account dataclass, the thresholds (OLD_PASSWORD_DAYS, WEAK_ETYPES), the privileged-group set, and the _is_privileged / _uses_weak_etype helpers are given. You implement the checks:

  • kerberoastable(directory) → findings for SPN user accounts (gMSA exempt); risk rises with RC4, an old password, and privilege.
  • asrep_roastable(directory) → findings for pre-auth-disabled accounts.
  • delegation_risks(directory) → unconstrained-delegation computers and RBCD-writable objects.
  • privileged_with_spn(directory) → the high-value Kerberoast, flagged separately at top risk.
  • analyze(directory) → all findings, sorted by (risk desc, technique, account, title).

Every finding is a dict carrying at least technique, title, account, risk, detection (the Kerberos event ids), and hardening (the fix).

Why RC4 vs AES decides the crack

RC4 (etype 0x17)AES256 (etype 0x12)
Key derivationNTLM hash (MD4 of the password) — fastPBKDF2, 4096 iterations + salt — slow
Offline crackbillions/sec on a GPUorders of magnitude slower
In a roastthe cheap-crack red flagmakes Kerberoasting expensive, often infeasible
Telemetry4769 with ticket encryption type 0x174769 with 0x11/0x12

This is why the analyzer ranks an RC4 + old-password Kerberoastable account above an AES + fresh one, and why "AES-only + gMSA" is the durable fix. The detection — 4769 with encryption type 0x17, or a spike of 4769 across many SPNs from one principal — is the SOC's signal that roasting is underway.

Attack cases the tests cover

  • Each exposure is detected: an RC4/old-password Kerberoastable account, an AES/fresh one, an AS-REP-roastable (pre-auth-off) account, an unconstrained-delegation computer, an RBCD-writable object, and a privileged account with an SPN.
  • The hardened account is clean: a gMSA, AES-only, fresh-password service account and a plain user appear in no finding (no false positives).
  • RC4 + old password ranks higher than AES + fresh among Kerberoast findings; analyze returns findings sorted by risk descending, top-severity (unconstrained delegation / privileged-SPN) first.
  • Every finding carries a detection and a hardening string; the 4769/4768/5136 event ids appear where they belong.
  • Empty input is handled; output is deterministic.

Run

pip install -r requirements.txt
LAB_MODULE=solution pytest -q   # reference passes (11 tests)
pytest -q                        # your implementation after the TODOs

Hardening / detection (the break-the-chain pairing)

The analyzer is the hardening report. Each finding names the fix at the mechanism level:

  • Kerberoast → gMSA (auto-rotated 128-char key) or a long random password + AES-only; remove unused SPNs; never run services as a Domain Admin. Detect 4769 with etype 0x17.
  • AS-REP roast → re-enable pre-authentication; if a legacy app forces it off, AES-only + long password + monitor 4768 for the account.
  • Unconstrained delegation → remove TRUSTED_FOR_DELEGATION; move to constrained/RBCD; put DAs in Protected Users and mark them "sensitive — cannot be delegated".
  • RBCD-writable → audit the object's DACL, remove unexpected write principals, alert on 5136 to msDS-AllowedToActOnBehalfOfOtherIdentity.

These map straight to the choke edges Lab 01 finds: fixing the exposure removes the graph edge.

Extensions (your own isolated, owned range)

  • Parse a real SharpHound/PingCastle/PurpleKnight export from an owned GOAD-style forest and run the same checks over collected facts (never a production domain).
  • Add ADCS ESC1–ESC8 template-misconfiguration checks (vulnerable enrollment + SAN supply).
  • Add DCSync rights detection (principals with DS-Replication-Get-Changes-All) and golden- ticket pre-conditions (KRBTGT password age).
  • Emit Sigma rules for each finding's detection (e.g. 4769 etype 0x17 frequency) so the blue team keeps a durable control.
  • Score the whole directory with a single identity-exposure index and trend it across collections.

Interview / resume

"Built a Kerberos/identity exposure analyzer over synthetic directory facts: flags Kerberoastable SPN accounts (ranking RC4 + old-password highest), AS-REP-roastable accounts, unconstrained- delegation and RBCD-writable objects, and privileged accounts carrying SPNs — each finding paired with the exact Kerberos event id that detects it (4769 etype 0x17, 4768, 5136) and the mechanism- level fix (gMSA, AES-only, pre-auth, Protected Users)."

Limitations: a representative set of exposures, not the full SpecterOps/PingCastle catalog; risk scores are ordinal heuristics, not CVSS; encryption-type and password-age thresholds are illustrative defaults; reasons over the given synthetic facts only — it does not collect them, request tickets, or crack anything; no live AD, no weaponization.