Acknowledgements: Special thanks to Charlie Clark (@exploitph) for helping me threat-model the attacks in this series and for his work on refactoring SharpRMS. Thanks to Aaron Margosis and Sean Metcalf for providing feedback that sharpened both the accuracy and the argument of this research. And thanks to Susannah Matt for her help reviewing, formatting, and publishing this post.
Part 1 of this series covered the Active Directory Rights Management Service (AD RMS) architecture, the certificate and license trust model, and how any domain user can discover the deployment and fingerprint which files are RMS-protected from recon alone. This post is where the attack happens.
If you haven't read Part 1, the short version is: every document an AD RMS deployment protects is bound to one root key, the Server Licensor Certificate (SLC) private key, whose certificate carries a 255-year validity period while the key itself has no expiry and no rotation mechanism. This post shows how to reach that key, what to do with it, and why the access persists long after you leave.
One framing correction up front, to level-set expectations: This attack is not a DCSync equivalent. The SLC key is not AD credentials, and this is not domain compromise. It is a total, permanent compromise of everything the RMS service protects, for every user, which is a different thing and the subject of the rest of this post.
A note on prior work and scope
The client-side attacks on AD RMS, where someone who is already allowed to open a protected document uses a non-compliant client to strip its protection and defeat view only, no print, no copy, and expiration, were worked out years ago by Martin Grothe, Christian Mainka, Paul Rösler, and Jörg Schwenk in their DisARMS research at WOOT 2016. That work is the foundation this series is built on, and it is what inspired it. To learn about the client-side attacks, read their paper; this series does not re-cover them. What it adds is the server side: recovering the root key itself and everything that follows once the key is in hand. I ported their original client-side code into a single unified binary, SharpRMS, alongside the new server-side capabilities, so one tool covers both halves of the surface.
The lab and the cast
Part 1 built this lab in detail. Here it is in one picture, since Part 2 leans on it constantly. The service runs on VESUVIO, with the configuration database in SQL on BARONE. The cast is small. Tony, a Service Group member, is the gate to the admin surface and the key. Silvio holds a content grant. Paulie is a plain domain user with nothing. The rest of this post is those three reaching, or being denied, what AD RMS protects.
Figure 1: The New Jersey lab and its cast. The service runs on VESUVIO, with the configuration database in SQL on BARONE. The lower panel is who reaches what. Only Service Group members reach the admin surface and the key, Silvio holds a content grant, and Paulie is a plain domain user with nothing.
The key you can't rotate
The SLC is the root of everything AD RMS does. Every publishing license the deployment has ever issued carries a content key encrypted to the SLC public key, and the server decrypts that content key with the SLC private key on every document open. Whoever holds the private half holds the master key to every document the deployment has ever protected, wherever a copy still exists: files pulled from a share long ago, mail that was deleted from the server, documents on machines that have since been decommissioned. The protected content itself never reaches the RMS servers, so the key, not any server-held copy, is the whole game.
The same dates appear independently from the server endpoint:
Figure 2: Certificate and license relationships in AD RMS. Redrawn from Enrique Saggese, "Licenses and Certificates, and how AD RMS protects and consumes documents," Microsoft TechNet Information Protection blog (archived on Microsoft Tech Community); SLC flagged as the 255-year cluster root.
The comparison that frames the severity: The SLC is to AD RMS what KRBTGT is to Kerberos and what the DPAPI domain backup key is to credential encryption. All three are long-lived cluster roots that protect everything else. The differences matter:
Two keys and a certificate that outlive the domain
Key | Validity | Rotation | What it unlocks |
|---|---|---|---|
| No automatic expiry; issued tickets live ~10h | A double reset invalidates every Golden Ticket. It's a pure signing key, so the KDC simply stops trusting the old one. | Kerberos tickets |
DPAPI domain backup key | No expiry; generated once at domain creation | No Microsoft-supported rotation (their guidance is to build a new domain). Unofficial tools can set a new preferred key, but every secret already backed up stays decryptable by the old key. | DPAPI-encrypted secrets, domain-wide |
AD RMS SLC | ~255 years | A new SLC changes only what's issued going forward. There's no revocation that retroactively protects already-sealed content, so every document sealed to the old key stays decryptable by it forever. | Every document the cluster ever protected |
The 255-year window is not a misconfiguration. Every AD RMS server enrolls as the leaf of a fixed Microsoft certificate chain that ships inside the product: a DRM Production Root, a Production CA, and a Production Server Enrollment CA, which issues the Server Self Enrollment Service certificate that in turn signs your server's SLC. The server generates its own SLC at enrollment and inherits that self-enrollment certificate's validity window verbatim, the span Microsoft fixed as December 5, 2002 through March 3, 2258. The design choice is the shape of the whole thing: a certificate that effectively never expires, certifying a key pair that sits at the root of every cryptographic operation the service performs. The dates are not something SharpRMS calculates. They are in the raw XrML of the licensor chain that rides in the publishing license of every document the deployment protects, which is where SharpRMS reads them.
From the enrollment-CA certificate every AD RMS deployment receives, embedded in the publishing license of every document it protects:
<!-- Microsoft DRM Server Self Enrollment Service certificate, embedded verbatim -->
<!-- in the Publishing License of every document this cluster protects. -->
<OBJECT type="MS-DRM-Server">
<NAME>Microsoft DRM Server Self Enrollment Service</NAME>
</OBJECT>
<RANGETIME>
<FROM>2002-12-05T01:07</FROM>
<UNTIL>2258-03-03T21:33</UNTIL>
</RANGETIME>
The same dates appear independently from the server endpoint:
Figure 3: The same 2002 to 2258 window, read straight from the server endpoint. A second source, the same dates the enrollment CA baked in.
That window is effectively "never," and by design. The exact number is arbitrary; Microsoft could have stamped 150 years or 3,000, and the practical meaning is the same: the certificate lasts for the life of the deployment. The comparison to Kerberos Golden Tickets is instructive but cuts in a specific direction. A Golden Ticket's validity is set by the attacker at forgery time, and Mimikatz defaults to 10 years because that is a round number that fits the Kerberos lifetime field. The SLC's window is fixed at enrollment and inherited from Microsoft's chain, so no cmdlet or console option can change the date. The length of the certificate is not the issue. The private key it certifies is, because that key has no rotation path at all.
You can decommission the cluster and rebuild it, and the new cluster receives a new SLC. But every document protected by the old SLC remains decryptable with the old key, forever. If the key was extracted before the rebuild, nothing changes.
The target: a document only Tony and Silvio can open
Before any key math, here's the document the rest of this post is about: protected by the AD RMS, meant for two identities and nobody else. Everything after this is whether that protection holds.
Figure 4: Restricting BOARD_MINUTES_2026.docx as tony.soprano. File > Info > Protect Document > Restrict Access opens the Permission dialog, where Tony grants himself Full Control and silvio.dante Read.
Figure 5: BOARD_MINUTES_2026.docx as protected. Note the "yellow" banner denoting RESTRICTED ACCESS.
A document protected for tony.soprano and silvio.dante, created by Tony, saved to the workstation. The protection is visible in the file's raw bytes, before Word ever runs:
Figure 6: A normal .docx is a ZIP, starting 50-4B-03-04 (PK). An RMS-protected .docx is wrapped in an OLE compound file, starting D0-CF-11-E0-A1-B1-1A-E1, with Primary (the publishing license) and EncryptedPackage streams inside. So you sweep a share or mailbox for the D0-CF magic plus those DRM streams to pick out exactly the documents worth targeting. Cheap recon, high signal.
Here's what happens when paulie.gualtieri, a plain Domain Users member with no RMS rights, attempts to open it:
Figure 7: paulie.gualtieri is refused access to BOARD_MINUTES.docx by AD RMS, not by Word. Opening the document triggers the RMS client to authenticate Paulie to the cluster and request a use license for his identity. Enforcement lives in the AD RMS authorization layer, not in Word; the cluster, not the application, decides whether a license is issued.
Figure 8: The cluster resolves Paulie's rights server-side, finds none, and declines to issue a license. Word only relays that decision: "You are not signed in to Office with an account that has permission…", and points him to request permission from tony.soprano@newjersey.sopranos.local. The content stays encrypted.
Is this cluster software-keyed?
Before extracting anything, confirm the SLC private key is held in software. An HSM-backed deployment keeps the key in hardware, out of reach of the extraction paths covered here. The keyprotection admin operation answers this as a Service Group member:
Figure 9: keyprotection runs as a Service Group member. IsServicePrivateKeySoftwareBased: true is the go signal, and the call hands back the database connection string on the way out. The string carries no credentials (integrated security=SSPI); it names the SQL server and database and works only for a caller already authorized to that database.
IsServicePrivateKeySoftwareBased: true is the green light. The SLC private key lives in the config database on BARONE (SQL), reachable by the paths below. The DatabaseConnectionString also hands you the SQL server (data source=BARONE) and the database name, which is exactly what the SQL extraction path uses. Both pieces of information come back to a Service Group member.
If the field reads false, the key is in an HSM. The TPD export path shown here may still work, because the export runs server-side and can reach an HSM-backed key when the administrator has allowed export. The paths that instead read the key material directly, the encrypted SLC blob in the config database, cannot, because an HSM never releases the private key in usable form.
Extracting the key: The TPD export path
AD RMS exposes a Trusted Publishing Domain (TPD) export operation through its admin SOAP surface. TPD export is intended for migration and cross-organization trust: it packages a deployment's SLC private key material so a second AD RMS deployment can import it and issue or open licenses as if it were the first. A Trusted User Domain shares only public certificates, but a Trusted Publishing Domain shares the private key itself, which is exactly why the export is the extraction vector. The auth gate is AD RMS Service Group membership, a privileged role in its own right. Given that membership, the export is a single authenticated SOAP call to the admin surface.
That split is worth seeing. The client pipeline is open to any domain user, and the admin surface, where the export lives, is the gated half.
Figure 10: The AD RMS SOAP surface. The client pipeline (certification, licensing, template distribution) answers any domain user. The administrative surface, where the TPD export operation lives, is gated to AD RMS Service Group membership. Service on VESUVIO, configuration database on BARONE.
The export encrypts the key blob with a password. The default implementation uses a SHA-256 key derived from that password, a hardcoded IV, and AES-128-CBC. The IV is:
IV (hardcoded): 01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F-10
The IV is identical on every AD RMS install. It is not unique to your deployment; it is hardcoded in the server implementation. Paired with an AES key that is just an unsalted, single-pass SHA-256 of the export password, the TPD export is the weakest link in the key-protection chain. That weakness applies to stored backups, not to the live attack : a TPD backup file left on a reachable share and sealed with a weak or guessable password can be unwrapped offline, with no access to the server.
In the attack path the password is attacker-chosen, since you set it in the export call, so the weak key derivation is irrelevant to the live extraction. It matters for stored backups. Microsoft's Migrate from AD RMS to Azure Information Protection guidance has admins export the Trusted Publishing Domains, noting that "the trusted publishing domains include the Server Licensor Certificate (SLC) keys to decrypt previously protected files." Each exported .xml is therefore a password-wrapped copy of the SLC private key. Microsoft's own instruction is to "specify and confirm a strong password," the control that fails when that password is weak or reused, and to guard the file: "however you store these files, use security best practices to protect them because this data includes your private key." That is the crux. A TPD export is private-key material, so keep it off any general-purpose share and lock the share and NTFS permissions to the few accounts that genuinely need access, because a file behind admin-only permissions is far harder to reach than one on an Everyone-readable share.
Everything from here assumes Tony's credentials are already in hand. This post takes that compromise as a given; how the credentials were obtained is not the point, and I'll leave that part to the imagination of penetration testers and red teamers 😀. What matters is that Tony is an AD RMS Service Group member, a privileged role in its own right and an effective administrator of the RMS service. That membership alone is the entire gate.
Running as Tony from SATRIALES, a domain workstation, the extraction is one call to the admin surface:
.\SharpRMS.exe extract /method:tpd /server:http://vesuvio.newjersey.sopranos.local /user:NEWJERSEY\tony.soprano /password:Gabagool123! /exportpassword:SharpRMS2026 /outfile:slc.bin
Figure 11: SharpRMS TPD export, run as tony.soprano from SATRIALES. Out comes the 1172-byte SLC private key blob. Note we have a new file dropped to the desktop (slc.bin)
The output is a 1172-byte CAPI PRIVATEKEYBLOB: a standard Windows RSA private key container in little-endian format. Its SHA-256 is a1e7afd5…ece9e5a. The modulus (big-endian) first 8 bytes are CA-10-CF-24-3A-30-6B-9D. These are the verifiable fingerprints of this cluster's root key.
What is this operation logging?
Nothing obvious. The AD RMS logging database (DRMS_Logging on BARONE, the SQL instance) records six specific request types: GetLicensorCertificate, Certification.Certify, Certification.Precertify, TemplateDistribution (both variants), and GroupExpansion. AcquireLicense is not among them, nor is Publish.
The admin SOAP surface, including ExportTrustedPublishingDomain operation, does not appear in that log. There is no Windows Event ID that fires on a TPD export by default. The IIS logs record the POST to /_wmcs/admin/, but that endpoint handles many operations and the specific operation name is in the SOAP body, not the URL. An organization monitoring IIS logs for admin-path POST requests and parsing SOAP bodies would catch the export.
The practical read: The TPD extraction leaves no entry in the RMS application database. The IIS W3SVC log records the POST to /_wmcs/admin/ including the authenticated user, source IP, and user agent, but is rarely parsed for admin SOAP calls. No Windows Event ID fires. The only durable artifact is the slc.bin file on the attacker's machine. We'll cover detection later.
The payoff: What SLC.BIN does that Paulie can't
Same machine, same account, same file. SharpRMS runs with only slc.bin and the protected document:
.\SharpRMS.exe decrypt /keyfile:slc.bin /infile:BOARD_MINUTES_2026.docx /outfile:PAULIE_cracked.docx
Figure 12: SharpRMS decrypt running as paulie.gualtieri with the supplied slc.bin. The key loads (modulus CA-10-CF-24), the content key and package key unwrap, and the unrestricted PAULIE_cracked.docx drops to the desktop as valid OOXML. No server contact, no credentials, no RMS rights.
Figure 13: PAULIE_cracked.docx open in Word. Note there's no RESTRICTED ACCESS banner.
Two things to note in the decrypt output:
Every document carries its own content key and package key, generated fresh at protection time.
The single
slc.binunwrapped it, because its content key was sealed to the same SLC public key.
That's the generalization: one SLC key does not just open every document the deployment has ever protected, it strips the protection off and writes a clean, plaintext copy to disk, regardless of which user created the document, which rights policy it carried, or whether that user still exists. That is more than any authorized reader can do. Silvio can open and read the document, but he cannot save an unprotected copy without the key; the SLC key produces exactly that.
XrML forgery: minting an identity the cluster trusts
Here is where things get interesting. With the SLC private key in hand, you can mint credentials that AD RMS treats as its own: a Rights Account Certificate for any identity you name, signed so the server cannot tell it from a real one. The payoff is that you stop needing a victim's key or session. You ask the server for a use license as that identity, and it issues one. The rest of this section builds that forgery piece by piece, the signature, the certificate, and finally a full license request the server accepts.
The SLC private key is not only a decryption key, it is a signing key. Every certificate in the AD RMS trust hierarchy, from the Rights Account Certificates (RACs) that identify users to the licenses that grant access, is an XrML document signed by the SLC. With the private key on disk you can produce that signature yourself, and the server cannot tell the difference.
The signing is standard once you know the encoding. The input is the raw UTF-16LE bytes of the BODY element, with no XML canonicalization. Hash with SHA-256, sign RSA PKCS#1 v1.5, and the signature is valid. SharpRMS does this natively, with no RMS SDK on the machine. Microsoft's code is only ever involved as a proof step: when Microsoft.RightsManagementServices.Shared, the RMS server DLL, is present, the forge cross-checks its signature against that library's RsaCapiKey.Sign, and the two match byte for byte. The match is expected, since the SLC key is the same, and that is exactly the point. It confirms the from-scratch native signer reproduces Microsoft's output with no encoding quirk that would make the server reject the forgery.
The cross-check is the only step that touches Microsoft's DLL. That DLL, Microsoft.RightsManagementServices.Shared, is a server component the AD RMS role installs into the GAC, so it is not on a domain workstation by default. You could in principle copy it to a workstation and load it there, since it is a managed assembly, but there is no reason to. /verifydll is a one-time proof that the native signer matches Microsoft's byte for byte, not a step in the attack. The forge itself needs no Microsoft code, so on a real engagement you carry nothing. The proof only had to run once, on a box where the reference implementation already lived.
It doesn't mean the forgery behaves differently there. The native signing is deterministic: the same bytes on any machine. The server is merely where we could hold our output up against Microsoft's own. This is a check on our tool, not a step in the attack.
SharpRMS forges the certificate, an XrML certificate signed under the SLC, using only standard .NET crypto, and it runs entirely on the workstation with no RMS SDK on the box. That is the entire point. Because the signature is produced with the SLC private key, it is not a convincing imitation of the server's signature, it is a genuine SLC signature, cryptographically the server's own. A plain workstation, holding the key, mints certificates the server accepts as authentic, and needs nothing from Microsoft to do so.
Microsoft's own AD RMS SDK documentation is explicit about the basis of that trust. It describes RAC as carrying a signature "created by using the private key of the AD RMS activation service," backed by a chain of server licensor certificates up to the root. The signature is the trust. Reproduce it and the cluster has no separate test to fall back on.
Figure 14: Microsoft.RightsManagementServices.Shared on VESUVIO. The reference implementation is a Microsoft-signed server assembly, version 10.0.20348.1, installed in the GAC by the AD RMS role. It is present on the server and absent from a domain workstation, which is why the cross-check in the next figure can only run here.
.\SharpRMS.exe forge /keyfile:slc.bin /verifydll
Figure 15: The native forge, cross-checked against that server DLL with /verifydll.
SharpRMS signs the XrML BODY from scratch with the extracted SLC key, then compares its signature against Microsoft's own RsaCapiKey.Sign. The match is byte for byte. The forged signature is not just valid, it is identical to one the server would produce, so it cannot be told apart from a legitimate certificate by inspecting the signature. The /verifydll cross-check runs where Microsoft's DLL is present, such as the server; the forge itself is ordinary RSA and SHA and runs on the workstation.
Forging an RAC starts from a real one. SharpRMS clones a genuine RAC's envelope, its issuer block and certificate chain, and changes only three fields. The genuine RAC comes from the server itself: Precertify mints an RAC for any named identity and, like the export, requires the same privileged Service Group credentials. Here it mints one for Silvio:
.\SharpRMS.exe impersonate /target:silvio.dante@newjersey.sopranos.local /sid:S-1-5-21-877797059-2172394321-2911316366-1110 /server:http://vesuvio.newjersey.sopranos.local /user:NEWJERSEY\tony.soprano /password:Gabagool123! /outfile:silvio_precert.xml
Figure 16: A PRECERT XML file for silvio.dante is issued, a legitimate server-issued RAC. forgerac takes it as the template, rewrites the identity to the one we want, drops in a public key we generated, sets a validity of our choosing, and re-signs the BODY with the extracted SLC key.
So far this only yields a pre-cert bound to a key the server holds, not a usable identity. Precertify never asked for a key; the server generated the RAC's keypair itself, so silvio_precert.xml is bound to a public key whose private half stays on the server. Request a use license against that pre-cert and the content key comes back sealed to a key only the server can open. Forging the RAC fixes exactly this. The forgerac command takes silvio_precert.xml as a template, keeps Silvio's identity and certificate chain intact, swaps in a keypair you control, sets a validity of your choosing, and re-signs the BODY with the extracted SLC key. The result is a RAC the server still trusts, bound to a private key you hold, so a use license issued to it comes back sealed to a key you can open. That is what turns a server-owned pre-cert into a credential you can actually decrypt with:
.\SharpRMS.exe forgerac /keyfile:slc.bin /template:silvio_precert.xml /target:silvio.dante@newjersey.sopranos.local /sid:S-1-5-21-877797059-2172394321-2911316366-1110 /until:2036-07-08T00:00 /outfile:forged_rac.xml
Figure 17: forgerac builds a complete RAC for Silvio from the silvio_precert.xml template, re-keyed to a keypair we hold (saved to forged_rac_priv.bin) and signed with the extracted SLC key. Both cross-checks pass, including the one against the SLC public key the cluster uses, so its signature check will accept the forgery as genuine.
The forged RAC is ordinary signed XML, not something encrypted. Trimmed and annotated, it is a genuine RAC with three fields changed and nothing else.
Figure 18: A forged RAC, trimmed and abbreviated. It is a genuine RAC with three fields changed: the identity, the public key, and the validity. The certificate chain and everything else are copied verbatim from a real one. The signature is a real SLC signature over this body, which is why the cluster accepts it.
A signature is only interesting if the server accepts it, so the goldenrac command builds the whole request. It forges a RAC for any identity, carrying a keypair it generates, assembles a real AcquireLicense request from the document's own publishing license, and presents it to the server. One command, run from the workstation as paulie.gualtieri. Paulie holds no RMS rights of his own, no grant on this document and no membership that would grant him access. What he does hold is the extracted SLC key, obtained earlier through the Service Group compromise, and that key is the whole of his power here. The target is a document restricted to tony.soprano and silvio.dante. Paulie runs goldenrac to forge Silvio, sets a validity of his choosing, and asks for a license.
The envelope goldenrac clones from a genuine RAC is just a public structure, the issuer block and certificate chain. Getting one needs no privilege: activate as any user and keep your own RAC as the template, or have Precertify mint one for any identity, which does require highly-privileged Service Group credentials. Either way the envelope is only a template; what makes the forgery work is the extracted SLC key that re-signs the body.
.\SharpRMS.exe goldenrac /keyfile:slc.bin /template:forged_rac.xml /infile:BOARD_MINUTES_2026.docx /server:http://vesuvio.newjersey.sopranos.local
/target:silvio.dante@newjersey.sopranos.local /sid:S-1-5-21-877797059-2172394321-2911316366-1110 /until:2036-07-08T00:00 /outfile:use_license.xml /keyout:forged_rac_priv.bin
Figure 19: goldenrac run as paulie.gualtieri. The forged RAC for silvio.dante is signed by the extracted SLC key, presented to the live cluster, and the cluster issues a use license. The cluster never issued this RAC. It trusts the SLC signature alone.
The server issues a USE LICENSE naming silvio.dante as the licensee and seals the content key to the public key goldenrac generated. Only you hold the matching private key, so you decrypt with that generated keypair plus the server's own license. The master SLC key never decrypts the document itself; it only signed the forged RAC that made the server issue the license.
One detail worth pulling out: Microsoft documents that "each RAC is tied to the machine certificate of the computer on which the user is activated" and that a user "cannot transfer a RAC between computers." That binding is a client-side lockbox: the machine private key underneath the RAC is "securely stored, protected by cryptographic keys related to the user's logon credentials and computer configuration," so the RAC's private key cannot be unwrapped on a different machine. None of that is a check the licensing server performs. The forged RAC carried no machine binding at all, and the server issued a license anyway, because the server validates only the SLC signature and the identity's rights, never which machine the RAC belongs to. Because goldenrac generates its own keypair, there is no machine binding to satisfy in the first place.
.\SharpRMS.exe decrypt /keyfile:forged_rac_priv.bin /uselicense:use_license.xml /infile:BOARD_MINUTES_2026.docx /outfile:silvio_read.docx
Figure 20: The payoff. The document was published for tony.soprano and silvio.dante only, and paulie.gualtieri is neither.
By forging Silvio and requesting a use license, Paulie obtains the content key and opens the document in cleartext in his own session, shown by his account in Word's top-right corner and title bar. There is no RMS restriction banner because Paulie is now holding decrypted content, not a protected file. Recovering a valid Office document this way proves the key was right; a wrong key yields random bytes, not a readable file.
The negative control confirms this is identity theft, not a blanket bypass. Forge paulie.gualtieri, a user on no access list, and the server returns NoRightsForRequestedPrincipal. The forged Paulie identity was accepted completely; the server denied him only because it looked up his real rights and found none.
.\SharpRMS.exe goldenrac /keyfile:slc.bin /template:forged_rac.xml /infile:BOARD_MINUTES_2026.docx /server:http://vesuvio.newjersey.sopranos.local /target:paulie.gualtieri@newjersey.sopranos.local /sid:S-1-5-21-877797059-2172394321-2911316366-1111 /until:2036-07-08T00:00
Figure 21: The same forgery for paulie.gualtieri, who has no rights to the document. The forged identity is trusted, but the server resolves its rights and finds none. Forging an identity is not the same as forging authorization.
That control is the whole distinction, and it is worth stating plainly because it will not be obvious to anyone who has attacked Kerberos.
This is not quite a Golden Ticket
If you have attacked Kerberos, the SLC key will feel familiar. It is the root signing key, the KRBTGT of the RMS trust domain—hold it and you can mint certificates the cluster accepts for any identity, valid for as long as you like. So it is tempting to call a forged RAC a Golden Ticket. It is worth being precise however, because the analogy breaks in one important place.
A Golden Ticket forges identity and authorization together. The PAC rides inside the ticket and the KDC trusts it, so you self-authorize: Drop the Domain Admins SID into the PAC and the account is a Domain Admin, because the membership is carried, not looked up.
A forged RAC forges identity only. The RAC says who you are: a SID, an email, a public key. It carries no rights and no group list. When the client presents it, the cluster resolves authorization on its own side; it checks the identity against the document's rights policy, and for group-based policies it asks the GroupExpansion service to look up that principal's real memberships in Active Directory. That is why silvio returned a license and plaintext, while paulie returned NoRightsForRequestedPrincipal. Both forged identities were trusted completely. Only one was authorized. There is no PAC to stuff.
The consequence is a different attack shape. You do not escalate through the certificate, you escalate by choosing whom to impersonate: to read a document restricted to a group, forge a RAC for a real member of that group. Both paths use the same extracted SLC key, so the difference is not the key, it is how the key is spent. The offline decrypt unseals the content key directly, with no license request, no rights check, and no server contact at all: silent, unconditional access to any document sealed under that key. The forged RAC instead signs an identity the live server then honors, so the server itself issues a use license to a principal that does not really exist. That is a different result, not a longer road to the same one: the offline decrypt proves the key breaks confidentiality, and the forged RAC proves the running service can be made to trust and license a forged identity.
So the more accurate label is a hybrid. Forged with the root key like a Golden Ticket, which is why the cluster accepts the forgery. Shaped like a "Silver Ticket," because it carries identity and inherits the victim's real authorization rather than injecting its own.
And that key, unlike KRBTGT, can never be taken back. A stolen KRBTGT hash is survivable; reset it twice and every Golden Ticket forged with the old key stops working. The KDC accepts the current and the previous KRBTGT, so a single reset leaves the old one valid; the second reset flushes it, and the forgeries die retroactively. It helps that Kerberos only protects transient network traffic: once the old key is flushed, there is nothing persisted for a stale ticket to unlock. The SLC gives you none of that mercy. It is a signing key and the root decryption key at once, and what it protects persists for years. Every protected document's content key is sealed to the SLC public key, and that ciphertext is already written into every copy of the file, on every share, mailbox, and backup. Minting a new SLC changes none of those bytes. No operation re-seals existing content to a new key, and deleting the old key only means you can no longer read your own documents, so it must stay archived in a trusted publishing domain forever. The attacker's extracted copy stays valid against all of it, forever. You can rotate KRBTGT to evict an intruder. You cannot rotate the SLC to un-leak a document.
Why forge a RAC and not the SLC
Trust in AD RMS flows downward from the SLC, exactly as it does in any PKI, and that direction is the whole game.
Note what the attack does not do: it does not forge a new SLC. The value is the extracted private key of the real SLC, whose public certificate is public anyway. A brand-new SLC you generate yourself, a rogue root, is worthless: nothing in the environment points to it, and to make it mean anything you would have to insert it into the trust store of every client and server you wanted to fool, which is loud, high privilege, and self-defeating, because by then you already own the machines you were trying to trick. Minting a new root buys you nothing. Holding the real one's private key buys you everything.
A forged RAC is a leaf. It is signed by the extracted SLC key, so it chains straight to the root the service already trusts. You do not expand the trust graph, you exploit the one that is already there. The server validates the signature, sees a chain terminating at its own trusted root, and issues a use license.
That key gives you two things at once: You can sign leaf certificates the server cannot tell from its own, which lets you forge any identity the server trusts. And you can unprotect any content the deployment ever protected, decrypting offline with no license request. Both powers fall out of the same extracted key.
Consideration | Forged SLC (rogue root) | Forged RAC (leaf under the real root) |
|---|---|---|
Trust anchor | None. Chains to nothing trusted. | The genuine stolen SLC key. Chains to the root already trusted. |
To weaponize | You can't. The import validates the SLC signature against Microsoft's enrollment root, so a self-generated root is rejected regardless of privilege. It is a cryptographic barrier, not a permission one. | Present it. Nothing else. |
Blast radius | Only what you already control. | Live impersonation of any identity on the issuing cluster. The cluster issues use licenses to a keypair we hold, so we read that user's content in our own session. |
Verdict | Not worth forging. | The actual weapon. |
Remediation
These are the controls that actually move the needle, in order of impact:
Govern the AD RMS Service Group as a highly-privileged group
This is the most important single change. The Service Group grants the TPD export surface, the remote extraction path, so it should be governed with the same rigor you apply to any highly privileged group: Protected Users, a privileged-access-workstation requirement, quarterly membership review, and alerting on any change. A Service Group member can extract the deployment's root key with a single remote SOAP call, no local access to the RMS server required. Treat the group accordingly.
TPD backup files are key material, not backups
If your organization has exported its Trusted Publishing Domains, as Microsoft instructs, those files sit wherever an admin saved them, a share, a workstation, a USB drive, so treat them as the equivalent of every secret the AD RMS deployment holds, the SLC private key included: encrypted storage, access auditing, and never a general-purpose file share. A TPD file protected by a weak or guessable password is effectively an unprotected copy of the SLC private key. And rotating the password does not undo exposure: if that file was ever on an accessible share, re-exporting under a new password protects nothing, because any copy an attacker already pulled stays valid forever. The only real responses are to remove the exposed file and tighten the share and NTFS permissions, and to recognize that once the key has leaked, it cannot be rotated out.
Use TLS and Extended Protection for Authentication (EPA)
The default VESUVIO server in this series runs HTTP-only. Over plain HTTP the SOAP traffic travels in the clear, including the exported key material, and the NTLM handshake is relayable. TLS is table stakes. EPA (NTLM channel binding) prevents relay of admin-surface credentials. Neither changes the blast radius of an extracted SLC, but both raise the cost of getting the credentials needed to reach the admin surface in the first place.
HSM for the SLC private key
An HSM-backed cluster sets IsServicePrivateKeySoftwareBased: false. The TPD export and DPAPI/SQL extraction paths won't produce usable key material from an HSM. The export operation may still function (the HSM signs and returns the wrapped key), but the blob it returns is protected by the HSM in a way that can't be unwrapped without the hardware. This is the remediation that actually closes the software-extraction path. It requires planning (HSM procurement, AD RMS configuration) and doesn't help if the cluster was software-keyed for any part of its life, as the historical protected documents remain decryptable with any key material extracted before the HSM was installed.
What can't be fixed
If the SLC private key was ever accessible in software, any document protected during that period is permanently decryptable with that key. Rebuilding the deployment issues a new SLC, but old documents remain sealed to the old key. Decommissioning and re-protecting every sensitive document is the only way to truly close the window, and that is operationally impractical for most organizations. The certificate's lifetime, roughly 255 years, is effectively "never," and it is not a misconfiguration you can change: it is a fixed span inherited from Microsoft's enrollment chain, not a window anyone sets or can tighten.
Azure Information Protection and HYOK
This series covers on-premises AD RMS. The finding does not apply to Azure Information Protection or Microsoft Purview in their default configuration. The Azure tenant key lives in Microsoft's infrastructure,or in a customer-managed Azure Key Vault for bring your own key (BYOK) deployments. It is not reachable from a compromised on-premises endpoint. A service-group member on an on-premises workstation cannot export a Purview tenant key via the AD RMS admin SOAP surface, because there is no such surface in a cloud-only deployment.
The notable exception: hold your own key (HYOK) deployments. HYOK allows organizations to back Azure sensitivity labels with an on-premises AD RMS cluster, typically for their most sensitive content. In a HYOK deployment, the key is deliberately kept on-premises, which means it falls under the same trust model this series covers. The organizations most concerned about their data leaving Microsoft's infrastructure are, in many cases, the ones whose root key is reachable from an on-premises service-group member. That's worth stating plainly: Full Purview cloud protection is not exposed here. HYOK, the most security-conscious option, is.
Coming in Part 3
Part 2 covered the attack surface of a single AD RMS deployment: extract the key, decrypt anything offline, and forge an identity the server trusts.
All of that was one deployment. Real organizations run several, wired together with trust, and what a stolen, non-rotatable key means once that trust enters the picture is the subject of Part 3.
References
- Enrique Saggese: Licenses and Certificates, and how AD RMS protects and consumes documents (https://techcommunity.microsoft.com/t5/security-compliance-and-identity/licenses-and-certificates-and-how-ad-rms-protects-and-consumes/ba-p/247309) (Microsoft TechNet Information Protection blog, archived on Microsoft Tech Community)
- Enrique Saggese: AD RMS Infrastructure Concepts, Part 1 (https://techcommunity.microsoft.com/t5/Enterprise-Mobility-Security/AD-RMS-Infrastructure-Concepts-Part-1/ba-p/247305) (Microsoft TechNet Information Protection blog, archived on Microsoft Tech Community)
- Grothe, Mainka, Rösler & Schwenk: How to Break Microsoft Rights Management Services (https://www.usenix.org/system/files/conference/woot16/woot16-paper-grothe.pdf) (DisARMS, USENIX WOOT '16, Ruhr-Universität Bochum)
- RUB-NDS: MS-RMS-Attacks (https://github.com/RUB-NDS/MS-RMS-Attacks)(reference implementation for the DisARMS attacks)
- Microsoft: Rights Account Certificates (https://learn.microsoft.com/en-us/previous-versions/windows/desktop/adrms_sdk/rights-account-certificates) (AD RMS SDK)
- Migrate from AD RMS to Azure Information Protection - Phase 2 (https://learn.microsoft.com/en-us/azure/information-protection/migrate-from-ad-rms-phase2)
- Rights Account Certificates (AD RMS SDK) (https://learn.microsoft.com/en-us/previous-versions/windows/desktop/adrms_sdk/rights-account-certificates)
- RMS FAQ: Certificates, Keys, and Encryption (https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-rights-management-services-rms/cc747725(v=ws.10))