6 minute read

Part 1 established that Kerberos to an IP address works, and that the single gate between a failed local resolution and a working ticket is whether an IP-based SPN exists in the directory for that address. That naturally raises the next question, and it is the one that decides how much any of this matters in practice: who can actually register such an SPN?

The short answer turns out to be reassuring, but getting to it means walking through a misleading error and a piece of directory validation that is easy to misread. This part is still pure mechanism. No coercion, no relay. Just the registration boundary and what enforces it.

The question, framed correctly

An SPN like host/192.168.1.50 is just a value in the servicePrincipalName attribute of some account. So “can I register an IP SPN” is really “can I write that value onto an account.” In Active Directory, the answer to any “can I write this attribute” question is decided by the DACL on the target object, and computer accounts have a specific and slightly unusual set of default rights over their own servicePrincipalName. That detail is the whole story here.

The scenario worth testing is the one that would matter to an attacker: a low-privilege domain user who has created a computer account (every authenticated user can, by default, up to the ms-DS-MachineAccountQuota of 10). That user controls the computer account. Can they place an arbitrary IP SPN on it?

The misleading part: an SPN that looks rejected outright

The first result looks like AD flatly refusing IP SPNs. Attempting to write host/<some-IP> to a controlled computer account, acting as that account or its creator, returns:

1
0x200b / 8203  ERROR_DS_INVALID_ATTRIBUTE_SYNTAX

Read literally, “invalid attribute syntax” suggests the IP-form SPN is malformed, that AD does not accept an address where it wants a hostname. That reading is wrong, and it sent the early part of this investigation down a false trail worth recounting, because the way it resolves is the actual finding.

The tell is that the same value behaves differently depending on the target. Registering the identical host/<IP> string onto a real, domain-joined computer account, as an administrator, succeeds cleanly. The value is not malformed. AD stored it happily on one account and rejected it with a syntax error on another. So the error is not really about syntax, and it is not really about the IP. Something about the writer or the target differs.

Isolating the variable

The way to resolve a “same value, different outcome” situation is to change one thing at a time. Two comparisons settle it.

First, error codes across targets. Writing the IP SPN as a low-privilege user to an account that user does not control returns a different, honest error:

1
0x2098 / 8344  Insufficient access rights to perform the operation.

That is a clean permissions denial. Meanwhile the same low-privilege user writing to an account they do control returns the misleading 0x200b syntax error. Two different failure codes for what turns out to be the same underlying cause, which is exactly why the syntax error misleads: on the controlled account, AD gets far enough to run a validation that the uncontrolled account never reached.

Second, and decisively, the value type. On the controlled computer account, writing a hostname SPN that matches the account’s own name succeeds:

1
2
HOST/<account>.<domain>     -> accepted
MSSQLSvc/<account>.<domain> -> accepted (any service class, as long as the host matches)

while writing a hostname SPN that does not match the account, or the IP-form SPN, both fail with the same 0x200b:

1
2
HOST/some-unrelated-host    -> 0x200b
host/<some-IP>              -> 0x200b

The discriminator is not IP-versus-name. It is whether the SPN’s host component matches the account’s own identity.

The mechanism: the Validated-Write to servicePrincipalName

The rights that a computer account (and its creator) hold over the account’s own servicePrincipalName are not a plain WriteProperty. They hold a validated write, exposed in the DACL as a Self right with the object type:

1
f3a64788-5306-11d1-a9c5-0000f80367c1   (Validated write to service principal name)

A validated write is a constrained write. Rather than letting the principal put any value into the attribute, AD runs a built-in check and only permits values that pass it. For servicePrincipalName, that check requires the SPN’s host component to correspond to the account’s dNSHostName or sAMAccountName. A hostname SPN that matches the machine’s own name passes. An arbitrary hostname that belongs to some other host fails. And an IP literal, which can never match a machine’s own DNS name or SAM account name, fails the same way. The INVALID_ATTRIBUTE_SYNTAX surfaced by the validated write is simply how that rejection presents; it is not a comment on the IP format as such.

This is why the earlier administrator write to a real machine succeeded: an administrator does not go through the validated Self write. BUILTIN\Administrators has full WriteProperty / GenericAll, which bypasses the validation entirely and can place any SPN, IP-form included, on any account.

Confirming the boundary from the other direction

If the gate is “validated write cannot, full write can,” then granting a low-privilege user an explicit unconstrained write over a target’s SPN attribute should let that user place the IP SPN that the validated self-write refused. Testing exactly that, granting a plain user WriteProperty on servicePrincipalName over a target computer, and then writing host/<IP> as that user, succeeds.

So the picture is complete and consistent:

  • A computer account’s default self-write over its own SPN is a validated write. It enforces a host-match, which an arbitrary IP can never satisfy. Self-registration of an arbitrary IP SPN is therefore blocked.
  • An unconstrained WriteProperty / GenericWrite / GenericAll over the target bypasses the validation and can place any IP SPN. That level of access comes from either administrative rights or an explicit delegation.

Why this is the reassuring reading

The practical consequence is the important part. The scenario that would make IP SPN dangerous in the trivial case, a low-privilege user spinning up a throwaway computer account and claiming an arbitrary host/<attacker-chosen-IP> on it, does not work. The Validated-Write host-match stops it. To register an arbitrary IP SPN, a principal needs full write over the target’s SPN attribute, and that is a pre-existing, well-understood dangerous permission: unconstrained write (GenericWrite, GenericAll, or WriteProperty on servicePrincipalName) over a computer object. It is the same class of ACL edge that already enables resource-based constrained delegation and shadow-credential attacks, and that tools like BloodHound already flag as high-value.

In other words, IP SPN does not introduce a new low-privilege primitive for placing service identities. It is only reachable from an access level an attacker would already be escalating through, and defenders already have reason to audit for. That is a meaningful containment, and it is the sort of precise permission boundary that is worth stating explicitly, because the misleading syntax error makes it easy to conclude either too much (“AD blocks IP SPNs entirely”) or too little (“anyone can register these”) if you stop at the first result.

Where this leaves us

Two parts in, the mechanism is fully characterized: Kerberos to an IP works, gated on an SPN existing, and registering that SPN for an arbitrary address requires unconstrained write over the target account rather than the constrained self-write every machine holds. Both of those are things a defender can reason about with existing concepts.

The later parts of this series move from “how the feature works” to “how it behaves under adversarial conditions,” specifically what happens when a machine is induced to authenticate to an IP that carries an SPN, what that authentication does and does not expose, and why enforced signing and channel binding remain the controls that matter. Those parts are written at the behavioral level and were prepared with coordinated disclosure in mind, so they describe what was observed and what it means for defenders without serving as a step-by-step reproduction.


This series documents original lab research conducted in an isolated environment, and is educational and defensive in intent.

Updated: