skip to content

A forged Kerberos ticket is minted with a stolen long-term key — which exchange validates a golden ticket, and which validates a silver one?

level: seniorimportance: should knowfreq 44%

answer

  1. the stolen key decides the exchange
  2. one is spent at the ticket-granting service
  3. the other never reaches a KDC
  4. krbtgt key mints a ticket-granting ticket
  5. no issuance record exists to check

basics

~20 s

A golden ticket is a ticket-granting ticket minted under the krbtgt key and spent in a TGS-REQ; a silver ticket is a service ticket minted under one service's key and spent in an AP-REQ, so no KDC exchange occurs.

solid answer

~40 s

The stolen key decides which exchange the forgery meets. Mint a ticket-granting ticket under the **`krbtgt`** key of the realm and you present it in a `TGS-REQ` as `pa-tgs-req (padata-type 1)` padata: the ticket-granting service decrypts it, finds it well-formed, and issues genuine service tickets against something **it never issued**. Mint a service ticket under a single **service principal's long-term key** and you present it in an `AP-REQ` directly to that service — and the KDC **never sees the request at all**, which is the more interesting property of the two. In both cases the forger writes every field of the `EncTicketPart` himself: `cname`, `crealm`, `flags`, `authtime`, `starttime`, `endtime`, `renew-till`, `authorization-data`.

code

pseudocode · 20 lines
pseudocode
function accept_ap_req(ap_req, my_long_term_key, now):
    enc_ticket_part = decrypt(ap_req.ticket.enc-part, my_long_term_key)
    if decryption failed:
        return KRB_AP_ERR_MODIFIED

    session_key   = enc_ticket_part.key
    authenticator = decrypt(ap_req.authenticator, session_key)
    if decryption failed:
        reject

    if authenticator.cname  != enc_ticket_part.cname:  reject
    if authenticator.crealm != enc_ticket_part.crealm: reject

    if now < enc_ticket_part.starttime: reject
    if now > enc_ticket_part.endtime:   return KRB_AP_ERR_TKT_EXPIRED
    if absolute(authenticator.ctime - now) > allowed_skew:
        return KRB_AP_ERR_SKEW

    -- no step asks any KDC whether this ticket was ever issued
    accept caller as enc_ticket_part.cname

go deeper

for a junior

The point to retain is that a Kerberos ticket is checked by decrypting it, not by looking it up anywhere, so whoever holds the key that seals a ticket can write one.

for a middle

Distinguish the two by the key and the exchange: the realm's krbtgt key mints a ticket-granting ticket spent at the ticket-granting service, one service's key mints a service ticket spent directly at that service.

for a senior

Point out which party is absent. A forged service ticket reaches no KDC at all, and a forged ticket-granting ticket makes the ticket-granting service issue genuine tickets from input it never produced.

for a principal

The trade to articulate is self-contained verification. Kerberos chose tickets a verifier can check with no lookup, which buys scale and costs you any notion of issuance record or revocation, so key custody becomes the entire control surface.

## What forging a Kerberos ticket actually requires A ticket is not a signed statement a verifier looks up. It is a structure whose `enc-part` is sealed under **one key**, and the verifier's entire test is whether that seal opens under the key it holds. Anyone in possession of the sealing key can therefore construct a ticket from nothing, fill in every field, seal it, and have it accepted — there is no issuance register, no serial number, and no revocation list in RFC 4120 for a verifier to consult. So the only question is *which* key was obtained, and that alone decides which exchange the forgery is presented to. ## The golden ticket: validating something it never issued The `krbtgt` principal (`krbtgt/REALM@REALM`) holds the key under which every ticket-granting ticket in a realm is sealed. A ticket-granting ticket minted with it is presented back to the KDC: 1. The forger builds an `EncTicketPart` naming any `cname` and `crealm` he likes, with whatever `flags`, `authtime`, `starttime`, `endtime` and `renew-till` suit him, and a session key of his own choosing. 2. He seals it under the `krbtgt` key to produce a `Ticket`. 3. He sends a `TGS-REQ` carrying that ticket as `pa-tgs-req (padata-type 1)` padata, with an `Authenticator` sealed under the session key he himself put inside it. 4. The ticket-granting service decrypts under the `krbtgt` key, finds a valid structure, checks the `Authenticator` against the enclosed session key, and issues a genuine service ticket for whatever `sname` was requested. Every ticket the TGS then issues is real. The forgery is upstream of them, and the TGS has no way to notice, because *decrypting successfully under its own key is the only issuance check the protocol gives it*. ## The silver ticket: the exchange that never happens Obtain instead the long-term key of a single service principal and you can mint a service ticket for that service directly. It is presented in an `AP-REQ` to the application service itself. That service decrypts `ticket.enc-part` with its own long-term key, reads the session key, opens the `Authenticator`, checks the names and the times, and accepts. The structurally interesting property is not that the forgery works — it is **which parties are absent**. No `AS-REQ`, no `TGS-REQ`, nothing traverses the KDC at all. The realm's authentication and ticket-granting services are simply not participants in this exchange. A golden ticket at least shows up as traffic at the ticket-granting service; a silver ticket is a conversation between the forger and one service. | | Golden ticket | Silver ticket | |---|---|---| | Key required to mint it | the realm's `krbtgt` key | one service principal's long-term key | | What is minted | a ticket-granting ticket | a service ticket for that one service | | Where it is presented | `TGS-REQ`, as `pa-tgs-req` padata | `AP-REQ`, straight to the service | | Who validates it | the ticket-granting service | the application service | | Does the KDC participate | yes, and it issues real tickets from it | no, not at any point | ## The fields the forger chooses Because the whole `EncTicketPart` is authored rather than requested, the forger sets `flags` — including `forwardable(1)`, `proxiable(3)`, `renewable(8)`, `initial(9)` and `pre-authent(10)` — and every time field. A lifetime policy expressed as "tickets last eight hours" is a constraint on what the **KDC issues**, not on what a forged structure may contain: an `endtime` years out is as acceptable to the verifier as any other, because the verifier only compares it with the current clock. `authorization-data` is likewise whatever was written into it. ## Why both are accepted, and where the line is Neither forgery exploits a defect. Kerberos's design decision is that a sealed ticket is self-contained so that verification needs **no lookup**, and self-contained plus symmetric means whoever holds the sealing key is indistinguishable from the issuer. Two consequences follow directly: - **Possession of a sealing key is equivalent to issuance authority for everything that key seals** — the realm's TGTs for `krbtgt`, that one service's tickets for a service key. - **Validity is bounded only by what the verifier can check locally**: that the seal opens, that the enclosed `Authenticator` matches, and that the current time falls inside the interval the forger wrote. The forged ticket stops working when the sealing key changes, and not before. Name the key, name the exchange it is presented to, and say which party is missing from that exchange — that is the complete protocol answer.

  • Why does a short ticket lifetime policy not limit a forged ticket?
    Because a lifetime policy governs what the KDC writes into tickets it issues. A forger authors the `EncTicketPart` himself and chooses `starttime`, `endtime` and `renew-till` freely. The verifier compares those fields with its own clock and nothing else, so the forged interval is whatever was written. Only changing the sealing key invalidates the ticket.
  • Why does a golden ticket produce service tickets that are indistinguishable from legitimate ones?
    Because they are legitimate. The ticket-granting service accepted the forged ticket-granting ticket as valid input and then did its ordinary job: it minted a real service ticket, sealed under the real service principal's key, for the `sname` requested. The forgery is confined to the input; everything downstream of it is genuine protocol output.
  • Which of the two forgeries can a ticket-granting service see traffic for at all?
    Only the golden ticket, because it must be presented in a `TGS-REQ` as `pa-tgs-req (padata-type 1)` padata for the forger to obtain service tickets from it. A silver ticket is minted for one service and presented directly in an `AP-REQ` to that service, so no message reaches the authentication or ticket-granting service.

Holding the die that embosses the seal is not the same as being granted a seat. You emboss your own document, and the clerk who receives it checks only that the seal is genuine, because that is the only check he was given.

saying these in an interview costs you the question

  • Thinks the ticket-granting service keeps a record of tickets it issued
  • Says a forged service ticket is checked by the KDC
  • Believes a forged ticket carries a KDC signature to verify
  • Assumes a golden ticket needs the target service's key
  • Thinks a short lifetime policy limits a ticket the forger authored