Skip to content
ADscan Docs

🎯 SPNJack — SPN-Jacking + Constrained Delegation

Deterministically take over a computer (including a Domain Controller) by relocating a delegation SPN onto it — no offline password crack required.

SPNJack is the attack step ADscan surfaces when a principal can abuse Kerberos constrained delegation with protocol transition to take over a target computer by moving a service principal name (SPN) onto it. It is fully deterministic: there is no offline cracking step, and when the target is a Domain Controller it chains straight to domain compromise.

SPNJack replaces the old phantom path ADscan used to draw, where a WriteSPN ACE over a computer was treated as a Kerberoasting opportunity. That path was never real — a machine account password is 120 random bytes and is uncrackable, so the Kerberoast ticket is worthless. SPNJack models the escalation that an SPN-write over a machine account actually enables.

What this attack does

The technique combines three primitives:

  • SPN-jacking — an SPN (e.g. HTTP/WEB01) is just a string attribute on an account. If you can write servicePrincipalName, you can delete the SPN from its current owner and re-add it onto a target you control. From that moment the KDC issues tickets for that SPN encrypted with the target's key.
  • Kerberos Constrained Delegation (KCD) with protocol transition (TrustedToAuthForDelegation / T2A4D) — the attacking principal is allowed to request service tickets on behalf of any user, including a privileged one, via S4U2Self followed by S4U2Proxy.
  • altservice (sname rewrite) — the resulting service ticket is accepted by the target because of its encryption key, not the service-class string. Rewriting the service name (HTTPCIFS/LDAP, same host) yields a ticket that grants full access to the target.

Because KCD binds to the account that owns the SPN string rather than to a host, relocating the delegated SPN onto a different computer redirects the whole delegation chain at that computer — as any user the attacker chooses (e.g. Administrator).

When it applies

ADscan emits a SPNJack step from a principal P to a target computer T only when all three of the following conditions hold. This is the gate; if any one fails, no SPNJack step is shown.

  1. P has a constrained-delegation vehicle with protocol transition. P's account is configured for protocol transition (TrustedToAuthForDelegation) and has at least one allowed-to-delegate SPN. Without protocol transition, P cannot mint a ticket for an arbitrary privileged user, so the chain is not possible.

  2. P can write the SPN of the target computer T. P has an effective right to write servicePrincipalName on T — either directly or through a group P belongs to. ADscan accepts WriteSPN, GenericAll, GenericWrite, WriteDacl, or Owns over T. Group-mediated rights are resolved transitively through P's group memberships and are reported as group-mediated.

  3. The delegation SPN can be freed up. At least one SPN in P's allowed-to-delegate list is plantable onto T: either the SPN currently has no owner (free), or P can also write the SPN of the account that currently owns it (so P can remove it first before re-adding it to T).

Single-principal by design

ADscan attributes a SPNJack step only when the delegation vehicle and the SPN-write right are held by the same principal P (the SPN-write may come through P's own group memberships, since that right is literally inside P's Kerberos token). It does not chain the SPN-write through a separate control edge to another principal — that would misrepresent who actually holds the rights. The convergent multi-principal case is intentionally not modelled as a single SPNJack step.

Why it matters

  • Deterministic host/DC takeover, no crack. Unlike Kerberoasting, SPNJack does not depend on a guessable password. Every step is a guaranteed protocol operation, so ADscan ranks it as a low-effort escalation — well above the previous WriteSPN → Kerberoast path, whose value depended on an offline crack that never succeeds against a machine account.
  • Direct domain compromise when T is a DC. When the target computer is a Domain Controller, SPNJack chains to full domain takeover: SPNJack → DC$ → Domain Controllers → DCSync → Domain. A single low-privileged account holding the delegation vehicle and an SPN-write over the DC computer object is enough to compromise the domain.
  • It removes a false negative and a false positive. The old behaviour both hid the real escalation and drew an impossible Kerberoast path. SPNJack surfaces the real one and suppresses the phantom.

How ADscan surfaces it

ADscan derives SPNJack during native graph collection — no extra LDAP traffic and no new collected field; the gate is evaluated over properties ADscan already reads (TrustedToAuthForDelegation, the allowed-to-delegate SPN list, and each computer's servicePrincipalName).

  • As an attack step. SPNJack appears in attack_steps and as a node-to-node step in attack_paths, classified as an escalation edge with direct_target_compromise semantics (you compromise the target, not just gain a capability) and low effort (deterministic). It maps to MITRE ATT&CK T1558.003 (Kerberoasting family) combined with delegation abuse.
  • WriteSPN over a computer is no longer traversable. The raw WriteSPN ACE is still recorded in the graph (it remains a true ACL fact for reporting), but the attack-path engine no longer walks WriteSPN → Computer as a Kerberoast. WriteSPN → User is unchanged and still surfaces as a targeted Kerberoast.
  • Faithful precondition chain in the step notes. So the single step never over-simplifies a multi-step technique, ADscan attaches the full requirement chain: the delegation (vehicle) SPN, its current owner, whether the SPN is free or must be removed from its owner first, and whether the SPN-write right is direct or comes through a named group in P's token.

A representative path in the JSON report:

{
  "id": "path_001",
  "tier": "tier0",
  "steps": [
    { "step": "spnjack", "from": "low_priv_user", "to": "DC01$" },
    { "step": "dcsync", "from": "DC01$", "to": "DOMAIN\\Administrator" }
  ],
  "total_steps": 2,
  "exploited": false
}

Reviewing SPNJack paths

SPNJack steps show up wherever you already review escalation opportunities:

# Show attack steps for the domain (SPNJack appears when the gate is met)
attack_steps corp.local

# Find paths from owned users — SPNJack to a DC is the headline Tier-0 path
attack_paths corp.local owned

# Inspect a specific path (index from the list output)
attack_paths corp.local owned 1

When you select a SPNJack path, ADscan shows the chain (From → Relation → To), the vehicle SPN and its current owner, and whether the SPN must first be removed from its owner — so you can validate the technique against your rules of engagement before executing anything.

Authorization Required

SPNJack mutates directory objects (it moves an SPN between accounts) and mints tickets for privileged users. Only execute it in environments where you have explicit written authorization and a defined scope, and confirm cleanup expectations with the client before relocating any SPN.

References

Find this useful?
Pass it to the next pentester running an AD engagement
Running 2+ AD engagements/year?
Get PRO free — beta access·Free in exchange for feedback
Automated PDF reports. Save ≥1 day per engagement.

ADscan — AD pentest automation for security consultants

🎯 SPNJack — SPN-Jacking + Constrained Delegation | ADscan