Normal view

There are new articles available, click to refresh the page.
Before yesterdayTenable TechBlog - Medium

Stealthy Persistence & PrivEsc in Entra ID by using the Federated Auth Secondary Token-signing Cert.

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:

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 😉


Stealthy Persistence & PrivEsc in Entra ID by using the Federated Auth Secondary Token-signing Cert. was originally published in Tenable TechBlog on Medium, where people are continuing the conversation by highlighting and responding to this story.

Entra Roles Allowing To Abuse Entra ID Federation for Persistence and Privilege Escalation

Introduction

Microsoft Entra ID (formerly known as Azure AD) allows delegation of authentication to another identity provider through the legitimate federation feature. However, attackers with elevated privileges can abuse this feature, leading to persistence and privilege escalation 💥.

But what are exactly these “elevated privileges” that are required to do so? 🤔 In this article, we are going to see that the famous “Global Administrator” role is not the only one allowing it! 😉 Follow along (or skip to the conclusion!) to learn which of your Entra administrators have this power, since these are the ones that you must protect first.

This was discovered by Tenable Research while working on identity security.

Federation?

By default, users submit their credentials to Entra ID (usually on the login.microsoftonline.com domain) which is in charge of validating them, either on its own if it’s a cloud-only account, or helped by the on-premises Active Directory (using hashes of AD password hashes already synchronized from AD via password hash sync, or by sending the password to AD for verification via pass-through authentication).

But there is another option: a Microsoft Entra tenant can use federation with a custom domain to establish trust with another domain for authentication and authorization. Organizations mainly use federation to delegate authentication for Active Directory users to their on-premises Active Directory Federation Services (AD FS). This is similar to the concept of “trust” in Active Directory. ⚠️ However, do not confuse the “custom domain” with an Active Directory “domain”!

When a user types their email on the login page, Entra ID detects when the domain is federated and then redirects the user to the URL of the corresponding Identity Provider (IdP), which obtains and verifies the user’s credentials, before redirecting the user to Entra ID with their proof (or failure) of authentication in the form of a signed SAML or WS-Federation (“WS-Fed” for short) token.

🏴‍☠️ However, if malicious actors gain elevated privileges in Microsoft Entra ID, they can abuse this federation mechanism to create a backdoor by creating a federated domain, or modifying an existing one, allowing them to impersonate anyone, even bypassing MFA.

The potential for abuse of this legitimate feature was initially discovered by Dr. Nestori Syynimaa: “Security vulnerability in Azure AD & Office 365 identity federation”, where he described how it concerns even cloud-only users, and even allows bypassing MFA, and further described it in “How to create a backdoor to Azure AD — part 1: Identity federation”. If you are curious, he also shared a “Deep-dive to Azure Active Directory Identity Federation”. He also hosts an OSINT tool allowing to list the domains, including if they are federated (to which IdP), of any tenant without even having to be authenticated to it!

This technique is currently used by threat actors, such as reported by Microsoft Incident Response on October 2023 in “Octo Tempest crosses boundaries to facilitate extortion, encryption, and destruction”:

Octo Tempest targets federated identity providers using tools like AADInternals to federate existing domains, or spoof legitimate domains by adding and then federating new domains. The threat actor then abuses this federation to generate forged valid security assertion markup language (SAML) tokens for any user of the target tenant with claims that have MFA satisfied, a technique known as Golden SAML

I also wrote an article describing how attackers can exploit the federated authentication’s secondary token-signing certificate for stealthier persistence and privilege escalation.

The corresponding MITRE ATT&CK techniques are:

🛡️ You will find recommendations to defend against this at the end of this article.

This federation feature for internal users (aka “members”) must not be confused with another federation feature in Entra ID, meant for guests (aka “external identities”) which allows “Federation with SAML/WS-Fed identity providers for guest users” using configurable “Identity Providers for External Identities”. This research and article are focused on the former: internal federation.

APIs available to interact with Entra ID

Performing this attack requires interacting with Entra ID of course, which is done through APIs. There are several available, offering more or less the same features, as described by Dr. Nestori Syynimaa in his talk “AADInternals: How did I built the ultimate Azure AD hacking tool from the scratch”. However, we will see that sometimes, an action that is forbidden for a certain role by one API is allowed by another! 😨 The behavior of some actions is also different between the APIs, while some actions are only possible with older APIs.

I prefer mentioning the APIs instead of the admin (i.e. PowerShell) or hack tools that I used, since it is what actually matters whether the tool calling them.

🟥 Provisioning API / MSOnline (MSOL)

The MSOnline V1 PowerShell module is going to be ⚠️ deprecated soon in March 2024 but it is still working, so it remains available to attackers too. You can recognize its usage because all the cmdlets contain “Msol”, for example “Get-MsolUser”.

It relies on an API unofficially called the “provisioning API” available at the “https://provisioningapi.microsoftonline.com/provisioningwebservice.svc” address. This API is not publicly documented and it uses the SOAP protocol.

It was replaced by the Azure AD Graph API (see below).

🟦 Azure AD Graph API

Likewise, the AzureAD PowerShell module is going to be ⚠️ deprecated soon in March 2024 but it is still working, so it remains available to attackers too. You can recognize its usage because all the cmdlets contain “AzureAD”, for example “Get-AzureADUser”.

It relies on an API called the Azure AD Graph API available on https://graph.windows.net/. This API is publicly documented and it exposes REST endpoints.

It was replaced by the Microsoft Graph API (see below), with which it must not be confused.

🟩 Microsoft Graph API / Microsoft Graph PowerShell SDK

Microsoft Graph is the newest API offered, and currently recommended, by Microsoft to interact with Entra ID and other Microsoft cloud services (e.g. Microsoft 365). The API is available on https://graph.microsoft.com. It is publicly documented and it exposes REST endpoints.

There are also several SDKs offered to interact with it, including the Microsoft Graph PowerShell SDK. You can recognize its usage because all the cmdlets contain “Mg”, for example “Get-MgUser”.

Entra roles and permissions

Entra ID follows the RBAC model to declare who can do what. Principals (user, group, service principal) are assigned Roles on some Scope (entire tenant, or specific Administrative Unit, or even a single object). Each Entra Role is defined by the Entra Permissions (also called “actions” in Microsoft documentation) it gives.

⚠️ Do not confuse Entra RBAC, using Entra roles and meant to control access to Entra ID resources (users, groups, devices, IdP configuration, etc.), with Azure RBAC, using Azure roles and meant to control access to Azure cloud resources (virtual machines, databases, network, storage accounts, websites, etc.). Take the time to read this article if you have doubts: “Azure roles, Microsoft Entra roles, and classic subscription administrator roles”.

⚠️ Do not confuse Entra permissions (like “microsoft.directory/domains/allProperties/allTasks”) with the Entra API permissions (like the famous “Directory.ReadWrite.All” permission of MS Graph API).

There are around 100 Entra built-in roles (as of December 2023), the most famous and powerful being Global Administrator. Customers can create their own Entra custom roles containing exactly the permissions they want (but only some are supported).

My goal in this article is to identify exactly which Entra roles, and hopefully exact Entra permission(s), allow attackers to abuse the federation feature for malicious purposes.

After a quick review of the Entra roles recommended by the documentation to configure this feature, and the list of all available Entra permissions (in particular those under “microsoft.directory/domains/”), I have selected for my tests these roles listed with their relevant permissions. The “[💥privileged]” tag below marks privileged roles according to Microsoft (as of November 2023), thanks to the recent feature “Privileged roles and permissions in Microsoft Entra ID”. Notably, none of these permissions is considered privileged.

Global Administrator [💥privileged]

  • microsoft.directory/domains/allProperties/allTasks
  • microsoft.directory/domains/federationConfiguration/basic/update
  • microsoft.directory/domains/federationConfiguration/create

Security Administrator [💥privileged]

  • microsoft.directory/domains/federation/update
  • microsoft.directory/domains/federationConfiguration/basic/update
  • microsoft.directory/domains/federationConfiguration/create

Hybrid Identity Administrator [💥privileged]: according to its description, this role is meant to manage federation for internal users (among other features), which is the feature I’m focusing on

  • microsoft.directory/domains/federation/update
  • microsoft.directory/domains/federationConfiguration/basic/update
  • microsoft.directory/domains/federationConfiguration/create

External Identity Provider Administrator: according to its description, this role is meant to manage federation for external users, which is not what this is about, but we never know… so I have included it

  • microsoft.directory/domains/federation/update

Domain Name Administrator

  • microsoft.directory/domains/allProperties/allTasks

Partner Tier1 Support [💥privileged]: Microsoft has been saying for months that this role should not be used since it is deprecated, and its mentions have been recently removed from the documentation, but since it is still functioning (as of November 2023) and thus abusable by attackers, I have decided to include it

  • <none>

Partner Tier2 Support [💥privileged]: Microsoft has been saying for months that this role should not be used since it is deprecated, and its mentions have been recently removed from the documentation, but since it is still functioning (as of November 2023) and thus abusable by attackers, I have decided to include it

  • microsoft.directory/domains/allProperties/allTasks

Methodology

I used a single Entra tenant, with several Entra users: one user per role I wanted to test (with the role assigned of course).

I wrote several PowerShell scripts, which clean the environment if needed (to allow several consecutive runs), call the cmdlets corresponding to the API to test, and then check the result. That way I obtained reliable and reproducible test cases.

The scripts are publicly available on GitHub: https://github.com/tenable/entra-id-federation-abuse-research-required-roles

Steps of the killchain

Create and verify domain

Federation needs a custom domain name configured in Entra ID to work. You can list them in the Entra admin center (or Azure Portal):

Domains can either be:

  • “Managed”, by default. No check in the “Federated” column in the screenshot above.
    Users submit their credentials to Entra ID.
  • “Federated”, when federation is enabled on a domain. Check in the “Federated” column.
    Users are redirected to the federated IdP to which they submit their credentials and Entra ID trusts the token it emits.

Administrators can convert a domain between each of these modes.

Now, from an attacker’s perspective, if there is no custom domain available (apart from the default <tenant>.onmicrosoft.com), we have to create one and verify it to prove that we own it. These are two steps, using different API endpoints / PowerShell cmdlets.

Creating a new domain is at the same time more visible, due to the added domain, but also less visible since this new domain will only be used by the attacker and it will not disrupt the existing authentication process for normal users, as hinted by Mandiant:

Note: To not interrupt production and authentication with an existing federated domain (and to remain undetected), an attacker may opt to register a new domain with the tenant.

🟥 Provisioning API: using New-MsolDomain and Confirm-MsolDomain

Attempts were:

✅ allowed for:

  • Global Administrator
  • Partner Tier2 Support

❌ denied for these, with this error message right from the first creation step “Access Denied. You do not have permissions to call this cmdlet”

  • Security Administrator
  • Hybrid Identity Administrator
  • External Identity Provider Administrator
  • Domain Name Administrator
  • Partner Tier1 Support

🟦 Azure AD Graph API: using New-AzureADDomain and Confirm-AzureADDomain

API endpoints: create a domain and verify action

Attempts were:

✅ allowed for:

  • Global Administrator
  • Domain Name Administrator
  • Partner Tier2 Support

❌ denied for these, with this error message right from the first creation step “Insufficient privileges to complete the operation.”

  • Security Administrator
  • Hybrid Identity Administrator
  • External Identity Provider Administrator
  • Partner Tier1 Support

I noticed that contrary to the provisioning API, the Domain Name Administrator role is allowed to create and verify a domain with the MS Graph API.

🟩 MS Graph API: using New-MgDomain and Confirm-MgDomain

API endpoints: create domain and verify domain

Attempts were:

✅ allowed for:

  • Global Administrator
  • Domain Name Administrator
  • Partner Tier2 Support

❌ denied for these, with this error message right from the first creation step “Insufficient privileges to complete the operation.”

  • Security Administrator
  • Hybrid Identity Administrator
  • External Identity Provider Administrator
  • Partner Tier1 Support

So, exactly the same results as with Azure AD Graph just above.

Convert domain to federated mode / add federation configuration

The next step is to convert the target custom domain to Federated mode, either:

  • the custom domain was already present, but configured in the default Managed mode. ⚠️ converting it to Federated mode will cause disruptions to users who normally use this domain for authentication!
  • the attacker was able to create and verify a new domain as described just above

Converting the domain to federated requires providing federation configuration information. Indeed, federation requires some configuration on Entra ID-side, for instance the certificate used by the federated IdP to sign the token which is the authentication proof, and the IssuerUri that uniquely identifies a federation service allowing to identify to which domain the token is linked.

This technique was described by Mandiant:

This can be obtained by converting a managed domain to a federated domain
The threat actor must first compromise an account with permission to modify or create federated realm objects […] Mandiant observed connections to a Microsoft 365 tenant with MSOnline PowerShell followed by the configuration of a new, attacker-controlled domain as federated

And also by Dr. Nestori Syynimaa in “How to create a backdoor to Azure AD — part 1: Identity federation”.

🟥 Provisioning API: using Set-MsolDomainAuthentication or AADInternals’ ConvertTo-AADIntBackdoor

Attempts were:

✅ allowed for:

  • Global Administrator
  • Partner Tier2 Support

❌ denied for these, with this error message “Access Denied. You do not have permissions to call this cmdlet”

  • Security Administrator
  • Hybrid Identity Administrator
  • External Identity Provider Administrator
  • Domain Name Administrator
  • Partner Tier1 Support

🟦 Azure AD Graph API: not supported

I did not find any Azure AD Graph API endpoint, nor AzureAD PowerShell cmdlet, for converting a domain to federated.

🟩 MS Graph API: using New-MgDomainFederationConfiguration

API endpoint: Create internalDomainFederation

Attempts were:

✅ allowed for:

  • Global Administrator
  • Security Administrator
  • External Identity Provider Administrator
  • Domain Name Administrator
  • Partner Tier2 Support

❌ denied for these, with this error message right from the first creation step “Insufficient privileges to complete the operation.”

  • Hybrid Identity Administrator
  • Partner Tier1 Support

Once again, I noticed differences between the roles allowed by the provisioning API and the MS Graph API.

Thanks to this observation, I suggested an update in the official Entra ID doc page.

Add second federation configuration

While looking at the APIs, I noticed that it was possible to List internalDomainFederations, notice the plural, and that it returned a collection (array). So I had the idea of trying to add a second federation configuration to an existing domain!

Unfortunately, it failed with this error “Domain already has Federation Configuration set.” and indeed the doc could have given me a hint: “This API returns only one object in the collection […] collection of one internalDomainFederation object in the response body.”

Change existing federation configuration

Another way for attackers is to change the federation configuration of an existing federated domain to allow crafting tokens with the attacker’s own token-signing certificate. This is similar to a Golden SAML attack but instead of stealing the key, the attacker is inserting theirs, and instead of presenting the forged token to a service, they present it to the IdP.

This technique 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.

The main way is to modify the current token-signing certificate, stored in the “signingCertificate” attribute of the federation configuration, which has the disadvantage of temporarily breaking the authentication and thus making it noticeable.

A variant is also possible, where instead of changing the main token-signing certificate, the attacker adds a secondary token-signing certificate thanks to the “nextSigningCertificate” attribute. This variant was described by Mandiant in Remediation and hardening strategies for Microsoft 365 to defend against UNC2452 (2021):

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.

This secondary token-signing certificate was meant to prepare a rollover operation when the main one expires. However, both are accepted as token signers even when the first one has not expired yet. Microsoft Security (MSRC) has confirmed to me it was an intended behavior and working as expected. Therefore, I updated the public documentation:

nextSigningCertificate: Fallback token signing certificate that can also be used to sign tokens

This is also the reason why Microsoft recommends in their “Emergency rotation of the AD FS certificates” article to renew twice the token-signing certificate because:

You’re creating two certificates because Azure [Entra ID] holds on to information about the previous certificate. By creating a second one, you’re forcing Azure [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 Azure [Entra ID] with it, it might be possible for the old token-signing certificate to authenticate users.

🟥 Provisioning API: using Set-MsolDomainFederationSettings

Attempts were:

✅ allowed for:

  • Global Administrator
  • Hybrid Identity Administrator
  • Partner Tier2 Support

❌ denied for these, with this error message right from the first creation step “Insufficient privileges to complete the operation.”

  • Domain Name Administrator
  • External Identity Provider Administrator
  • Security Administrator
  • Partner Tier1 Support

I noticed a difference here, with Set-MsolDomainAuthentication shown above, in that the “Hybrid Identity Administrator” role is now allowed.

🟦 Azure AD Graph API: not supported

I did not find any Azure AD Graph API endpoint, nor AzureAD PowerShell cmdlet, for modifying federation configuration. In the AzureADPreview module, there is the “New-AzureADExternalDomainFederation” cmdlet but it deals with federation for external users, not for internal users (as described at the beginning) which is the one I needed.

🟩 MS Graph API: using Update-MgDomainFederationConfiguration

API endpoint: Update internalDomainFederation

Attempts were:

✅ allowed for:

  • Global Administrator
  • Security Administrator
  • External Identity Provider Administrator
  • Domain Name Administrator
  • Partner Tier2 Support

❌ denied for these, with this error message right from the first creation step “Insufficient privileges to complete the operation.”

  • Hybrid Identity Administrator
  • Partner Tier1 Support

So, exactly the same results as for creating a federated domain with New-MgDomainFederationConfiguration shown above.

Remarks on inconsistency

🔍 I have no clue how Entra roles and permissions are implemented, nor used, by Entra ID but I noticed something strange. I feel like some operations are explicitly allowed to some roles instead of based on the exact permissions they contain. For example, while Security Administrator and Hybrid Identity Administrator contain exactly the same 3 permissions under “microsoft.directory/domains/*”, the former is allowed to Create internalDomainFederation with the Graph API (using New-MgDomainFederationConfiguration) whereas the latter is not.

Similarly, while Domain Name Administrator and Partner Tier2 Support both contain the “microsoft.directory/domains/allProperties/allTasks” permission, the former is forbidden to call Set-MsolDomainAuthentication while the latter is allowed.

🤔 I also noticed that some roles were forbidden to do some of the mentioned operations by the old 🟥 Provisioning API (MSOL) while the newer 🟦 Azure AD Graph and 🟩 MS Graph APIs allow it, and the contrary too.

Full chain

So, in summary, if you remember the goal of this article 😉, what are the roles actually required to perform this attack end-to-end?

If a verified custom domain is not already present, the attacker will need to be assigned either:

  • Global Administrator
  • Domain Name Administrator
  • Partner Tier2 Support

However, if a verified custom domain is already present, the attacker will need to be assigned either:

  • Global Administrator
  • Security Administrator
  • Hybrid Identity Administrator
  • External Identity Provider Administrator
  • Domain Name Administrator
  • Partner Tier2 Support

😨 As you can see, Global Administrator is far from being the only role allowing to compromise Entra ID by abusing the federation feature! In my opinion, the most dangerous roles in these lists are “External Identity Provider Administrator” and “Domain Name Administrator” because they are not identified as 💥privileged by Microsoft, and thus, are subject to less scrutiny and security efforts.

I believe that it comes from the fact that none of the Entra permissions that seem related to domains and federation configuration are identified as privileged by Microsoft. I wish I could have identified the exact Entra permission(s) allowing this, by testing them one by one in an Entra custom role, but unfortunately only a subset of permissions is currently supported in custom roles and none are in this subset.

I contacted MSRC (VULN-113566) suggesting to mark these permissions, “microsoft.directory/domains/allProperties/allTasks” and “microsoft.directory/domains/federation/update”, as privileged but they will not be doing it as they consider their baseline is correct even though some customers may have different interpretations.

You can also notice that an already existing custom domain is useful to attackers since it allows them to skip the domain creation and verification steps, which is stealthier, and makes the attack possible with more roles. However, it causes temporary disruptions for users who normally authenticate via the abused domain, so it is also less stealthy.

Recommendations for defense

The goal of this article was not to make you discover how federation itself can be abused, since great researchers have already done this a year ago, but still, you may wonder how to defend against such an attack.

Microsoft has long recommended to migrate away from federated authentication to managed authentication, however as we saw, even if an organization is not using (anymore) federated authentication, an attacker could still re-enable it.

🤔 First of all, apply the principle of least privilege and be mindful of whom you assign the roles mentioned previously (that was the goal of this article, do you remember? 😅). I hope I have convinced you that Global Administrator is not the only sensitive role.

🔍 Second, you should audit and monitor the federated domains (including their federation configuration(s)) in your Entra ID to detect the potential backdoors (already present, or to be added). Especially if your organization is not using (anymore) federated authentication. One of the available solutions is of course Tenable Identity Exposure which offers Indicators of Exposure dedicated to this subject (“Known Federated Domain Backdoor”, “Federation Signing Certificates Mismatch”, and more to come!). Microsoft has also published a guide describing how to “Monitor changes to federation configuration in your Microsoft Entra ID” but which leaves up to you the analysis of the federation configuration when an event occurs. Changes in federated domains, and the associated federation configurations, are normally rare so any event should be properly investigated.

🆘 Third, in case of a suspected or confirmed attack, it is highly recommended to seek assistance from incident response specialists with expertise on Entra ID to help identify the extent of the attack including the other potential means of persistence of the attacker. You can follow this remediation guide from Microsoft “Emergency rotation of the AD FS certificates”.

Conclusion

We have seen together that several built-in Entra roles can be leveraged by attackers to abuse the federation feature to elevate their privileges and persist in an Entra tenant. Of course, the most famous role, Global Administrator, is one of them, but these can also be used: Security Administrator, Hybrid Identity Administrator, External Identity Provider Administrator, Domain Name Administrator, and Partner Tier2 Support. Microsoft still has not identified all of them as privileged, so be careful when assigning these roles in your organization: assigned users may have more power than you think! 💥


Entra Roles Allowing To Abuse Entra ID Federation for Persistence and Privilege Escalation was originally published in Tenable TechBlog on Medium, where people are continuing the conversation by highlighting and responding to this story.

Code for Reading Windows Serialized Certificates

Problem description

On a Windows machine, we can find users’ certificates stored in files in C:\Users\<USER>\AppData\Roaming\Microsoft\SystemCertificates\My\Certificates (i.e. “%APPDATA%\Microsoft\SystemCertificates\My\Certificates”). These files have seemingly random names (i.e. “3B86DFC25CFB1B47EB4CBF53FD4028239D0C690E”) and no extension. What is their format? How to open them in code? With which Windows APIs? 🤔

Let me spoil you with the answers right away, including code samples, and I’ll describe after what I tried and what I learned 💡

Answer: “serialized certificates” that can be opened using the CryptQueryObject() function

These files are “serialized certificates”. Surprisingly, even with this knowledge which wasn’t easy to discover, I did not find any Windows CryptoAPI function to directly open them!

Until I found CryptQueryObject: a very handy function that can open crypto objects with different formats. We can specify with the “dwExpectedContentTypeFlags” parameter the format(s) we expect, or accept all formats, and see what it detects. It returns notably:

  • pdwContentType: equal to “CERT_QUERY_CONTENT_SERIALIZED_CERT” in this case meaning that “the content is a serialized single certificate.”
  • ppvContext: pointer to a CERT_CONTEXT structure, in this case of a serialized certificate, which contains in particular:
  • pCertInfo: many metadata on the certificate with a CERT_INFO structure
  • pbCertEncoded: the certificate itself, so what we would expect to find in a classic .crt file

Simplified example usage:

CERT_CONTEXT* certContext = NULL;
if (!CryptQueryObject(
CERT_QUERY_OBJECT_FILE,
L"C:\\Users\\localuser1\\AppData\\Roaming\\Microsoft\\SystemCertificates\\My\\Certificates\\3B86DFC25CFB1B47EB4CBF53FD4028239D0C690E",
CERT_QUERY_CONTENT_FLAG_ALL,
CERT_QUERY_FORMAT_FLAG_ALL,
0,
NULL,
NULL,
NULL,
NULL,
NULL,
(const void**)&certContext
) || certContext == NULL)
{
if (certContext) CertFreeCertificateContext(certContext);
return false;
}

Alternative with the CertAddSerializedElementToStore() function

There’s also an alternative. By searching for CryptoAPI functions related to “serialized certificates” we can find this function: CertAddSerializedElementToStore. It can deal with such certificates but only to load them into a store… So, the idea is to:

  1. create a temporary store in memory, using CertOpenStore with “CERT_STORE_PROV_MEMORY” and “CERT_STORE_CREATE_NEW_FLAG
  2. load the serialized certificate into this temp store, using CertAddSerializedElementToStore
  3. this function returns the desired CERT_CONTEXT structure of the certificate (like above) in “ppvContext

It works properly and we get the same results, but it’s longer and less efficient I think.

How did I find that they are “serialized certificates”?

I found a comment online saying that we can open them in Windows by assigning them the “.sst” extension, which then allows to open them with a double-click. We can see in the explorer that this extension corresponds to “Microsoft Serialized Certificate Store”.

Knowing this, I found the CertOpenStore CryptoAPI function that seemed capable of opening those “Microsoft Serialized Certificate Store” files, but it refused to open this file…

I didn’t understand why, so I created a certificate store in memory and used the CertSaveStore function to export it as a serialized certificate store. And indeed, its content did not have exactly the same format. There was some header at the beginning, before the content with the same format as the one I had in the files I wanted to analyze. My guess was that this header was the certificate store header, and the rest was actually just the serialized certificate saved in the store! And this guess was correct based on the results I got afterwards 😉

Of course I also tried first to load these files with other more common extensions, like .crt, .pfx, .p12, etc. but none worked.

Why not use CertEnumCertificatesInStore?

My initial need was to enumerate the certificates for all users on the machine (provided my code is running privileged of course) so I tried first to use CertOpenStore targeting the “CERT_SYSTEM_STORE_USERS” system store. But when enumerating the certificates, with CertEnumCertificatesInStore, it did not return these certificates that I knew existed since I could see them in the certificates manager (certmgr.msc) when logged in as each user.

I discovered this issue when using Benjamin @gentilkiwi Delpy’s “mimikatz” tool. Of course Benjamin loves certificates and so he included an entire “crypto” module in his famous tool. (Yeah, it’s a good reminder that it has many other usages than just dumping credentials! 😉). The “crypto::certificates” command, which uses CertEnumCertificatesInStore, could not find any certificate in the “My” certificate store of another user accessed through the “CERT_SYSTEM_STORE_USERS” system store and as admin of course:

Even though there was indeed a certificate to see:

Actually, I could find the certificates when running as each user, and targeting the “CERT_SYSTEM_STORE_CURRENT_USER” system store:

So, it confirmed that the “CERT_SYSTEM_STORE_USERS” system store has a limitation. The only online confirmation I found is an 18 years old 😯 newsgroup post from a then Microsoft employee:

CERT_SYSTEM_STORE_USERS opens the registry stroes. so you can NOT use MY store with it.

What I noticed too is that, when using “CERT_SYSTEM_STORE_USERS”, it only goes looking for certificates into the registry only, and there’s none in this case. So these certificates, that are on disk only, are missed when using “CERT_SYSTEM_STORE_USERS”:

Whereas, it looks for certificates in the registry and on disk when using “CERT_SYSTEM_STORE_CURRENT_USER”:

Alternatives for parsing these certificates without the CryptoAPI

In particular, Benjamin @gentilkiwi Delpy kindly answered my question, and told me that there is the “crypto::system” mimikatz command which allows to parse these certificates, like this:

The code shows that he actually implemented the entire parsing himself without relying on Windows APIs! This is very interesting to discover how it works, and it can also be helpful for research, but I preferred to stick to the official CryptoAPI functions, or at least Windows APIs, to open these certificates. However, this alternative is worth mentioning!

Edit: it was brought to my attention that this article “Extracting Certificates From the Windows Registry” may cover the same topic, but I did not double-check their results. I also preferred to use an official Windows API instead of a custom parsing.


Code for Reading Windows Serialized Certificates was originally published in Tenable TechBlog on Medium, where people are continuing the conversation by highlighting and responding to this story.

SMB “Access is denied” Caused by Anti-NTLM Relay Protection

Summary

We investigated a situation where an SMB client could not connect to an SMB server. The SMB server returned an “Access Denied” during the NTLM authentication, even though the credentials were correct and there were no restrictions on both the server-side share and client-side (notably UNC Hardened Access). The only unusual thing is that the SMB server was accessed through a NAT mapping (DNAT to be precise): the client was connecting to an IP which was not the real server’s IP. This can happen in some VPN network setups. Also, we have seen this situation at some organizations (even without a VPN in the equation) where they request to connect to machines, such as domain controllers, through a unique Virtual IP (VIP) which allows load-balancing.

💡 As cybersecurity experts, this immediately made us think that this setup was in fact similar to an NTLM relay (aka SMB relay) attack, even though the intent was not malicious. And perhaps there could be a security hardening mechanism on the server side blocking this.

And indeed we were correct: the server had the “Microsoft network server: Server SPN target name validation level” policy (i.e. SmbServerNameHardeningLevel registry key) enabled which blocked this scenario. Here is the policy description from Microsoft:

This policy setting controls the level of validation that a server with shared folders or printers performs on the service principal name (SPN) that is provided by the client device when the client device establishes a session by using the Server Message Block (SMB) protocol. The level of validation can help prevent a class of attacks against SMB services (referred to as SMB relay attacks). This setting affects both SMB1 and SMB2.

➡️ This situation could also occur in your regular SMB environments, so follow along to see how to troubleshoot this, how it is configured, how it works and what we suggest to do in this case.

Observation

Here’s an example in this screenshot (sorry for the French UI machine on the right!):

The SMB client, on the left (IP 10.10.10.20), is trying to connect to the SMB server on the right (IP 10.0.0.11 and FQDN dcfr.lab.lan), except it’s through the IP of a TCP relay (created with socat on Linux), at the bottom (IP 10.0.0.100) which simulates the NAT situation seen initially in our investigation.

So, the SMB server sees an incoming authentication, where the SMB client has declared (in the “Target Name” attribute on the left) it is expecting to authenticate to the IP of the TCP relay (10.0.0.100), which is different than the real server’s IP (10.0.0.11).

💥 Therefore, it detects the mismatch considered as an attack attempt, and denies the authentication right away, as we can see with the “Access is denied” error message and “STATUS_ACCESS_DENIED” in the SMB network capture.

With the same setup and server configuration, if the client connects directly to the server’s IP (10.0.0.11) without the relay, all is matching and it works:

How to troubleshoot?

551 “SMB Session Authentication Failure” event

The first hint in identifying this issue is that it generates a 551 “SMB Session Authentication Failure” event in the SMBServer event log (as seen in the first screenshot above).

5168 “SPN check for SMB/SMB2 failed” event

There is also a 5168 Security event “SPN check for SMB/SMB2 failed”, where we clearly see the IP address that was sent (the SPN, in red) Vs. what was expected (the semicolon-separated list, in green), sorry again for the French UI:

Note that for the 5168 event to be generated, the “Audit File Share” audit policy must be enabled for Failure at least. You can check with:

auditpol.exe /get /SubCategory:"Detailed File Share"

We can also have the same 5168 event generated “because of NTLMv1 or LM protocols usage” since they don’t carry the required SPN attribute for the server to do its check.

Policy

✅ We can also check if the “Microsoft network server: Server SPN target name validation level” policy is enabled (for those following in French: “Serveur réseau Microsoft: niveau de validation du nom de la cible de serveur SPN”).

The corresponding registry key is SmbServerNameHardeningLevel found in “HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters”

We can query it with:

reg query HKLM\System\CurrentControlSet\Services\LanManServer\Parameters\ /v SmbServerNameHardeningLevel

Or using this dedicated PowerShell cmdlet:

Get-SmbServerConfiguration | fl *hard*

See below for the explanation of the possible values.

How to configure the policy?

⚙️ The “Microsoft network server: Server SPN target name validation level” policy has three possible values:

  • 0[default] = “Off”
    “The SPN is not required or validated by the SMB server from a SMB client.”
  • 1 = “Accept if provided by client”
    “The SMB server will accept and validate the SPN provided by the SMB client and allow a session to be established if it matches the SMB server’s list of SPN’s for itself. If the SPN does NOT match, the session request for that SMB client will be denied.”
  • 2 = “Required from client”
    “The SMB client MUST send a SPN name in session setup, and the SPN name provided MUST match the SMB server that is being requested to establish a connection. If no SPN is provided by the client, or the SPN provided does not match, the session is denied.”

In our testing, we observed access denied errors in such a relay/NAT situation, with either the values of 1 or 2, because the Windows SMB client knows to provide the expected SPN. However, setting the registry key to 0 disables the protection and indeed it made the connection possible even through the relay.

How does this protection work?

Protocol support

Perhaps you have noticed something strange: here we can see an “SPN” in the context of an NTLM authentication… Whereas usually SPN only appears within the context of Kerberos! 🤔

The NTLM specification, [MS-NLMP] clearly uses this term:

MsvAvTargetName: The SPN of the target server.

Also, as described in the 5168 event:

It often happens because of NTLMv1 or LM protocols usage from client side when “Microsoft Network Server: Server SPN target name validation level” group policy set to “Require from client” on server side. SPN only sent to server when NTLMv2 or Kerberos protocols are used, and after that SPN can be validated.

Indeed, NTLMv1 and LM protocols don’t have the required fields to carry the SPN expected and provided by the client.

Of course, this security mechanism works with Kerberos since service tickets embed an SPN.

Protection against NTLM relaying

📄 NTLM relay attacks, sometimes called SMB relay attacks, have been well-known for many years. I recommend these great articles if you want to learn more: https://en.hackndo.com/ntlm-relay/ and https://www.thehacker.recipes/ad/movement/ntlm/relay

During such an attack, the client authenticates to the attacker’s machine, which relays it to another machine (like in a Man-in-the-Middle attack), which is the attacker’s real target. But thanks to this additional SPN attribute, the client declares the server it’s expecting to authenticate to, which would be the attacker’s IP, and when the target server receives the relayed authentication it can detect that there’s a mismatch (the declared IP isn’t its own) and denies the authentication. Of course, it works with hostnames and FQDNs instead of IPs.

This protection is also explained in this section of the same article: https://en.hackndo.com/ntlm-relay/#service-binding

Offensive security perspective

An SMB client can be modified to send a correct target name, for example, using the impacket library as described in this article. But this doesn’t make this protection useless in the context of an NTLM relay attack, as the attacker cannot modify the SMB client used by the victim.

🔒 Moreover, this SPN attribute cannot be removed nor modified during an NTLM relay attack because it belongs to the attributes list (AV_PAIR), which is protected by the MIC as described in many articles, including this recent one from Synacktiv about the NTLM EPA protection.

What do we recommend?

🛡️ Of course, as cybersecurity experts, we do not recommend to remove this hardening feature that is usually enabled for good reason! Many cybersecurity agencies encourage evaluating this policy and enabling it where possible, as described in many security standards that Tenable products allow to audit.

As described previously, we could also create our own SMB client to send a crafted, but correct, SPN value, but obviously this solution is not possible in most cases…

  1. The easiest solution, when possible, is to connect to the server directly, using its real IP (i.e., without NAT).
  2. Otherwise, there is a registry key which allows for declaring of a list of alternative names and IPs allowed through this mechanism. It is the SrvAllowedServerNames key, which must be created in “HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters” with type REG_MULTI_SZ. This is described in this Microsoft support article “Description of the update that implements Extended Protection for Authentication in the Server service” and in this answer on ServerFault.
    We confirm it works (with both values enabling the policy):

SMB “Access is denied” Caused by Anti-NTLM Relay Protection was originally published in Tenable TechBlog on Medium, where people are continuing the conversation by highlighting and responding to this story.

Decrypt Kerberos/NTLM “encrypted stub data” in Wireshark

I often use Wireshark to analyze Windows and Active Directory network protocols, especially those juicy RPC 😉 But I’m often interrupted in my enthusiasm by the payload dissected as “encrypted stub data”:

Can we decrypt this “encrypted stub data?” 🤔

The answer is: yes, we can! 💪 We can also decrypt Kerberos exchanges, TGTs and service tickets, etc! And same for NTLM/NTLMSSP, as I will show you near the end. Read along to learn how to decrypt DCE/RPC in Wireshark.

Wait, is that magic?

Wireshark is very powerful, as we know, but how can it decrypt data? Actually there’s no magic required because we’ll just give it the keys it needs.

The key depends on the chosen algorithm (RC4, AES128, AES256…) during the Kerberos exchange, and they derive from the password (this is simplified but you didn’t come here to read the Kerberos RFC, right? 🤓).

My preferred method to get the Kerberos keys is to use mimikatz DCSync for the target user:

You’ll directly notice the AES256, AES128, and DES keys at the bottom, but what about the RC4 key? As you may have guessed, it’s simply the NT hash 😉

Just remember that modern Windows environments will likely use AES256 so that’s what we’ll target.

Keep tabs on the keys

Kerberos keys are commonly stored in “keytab” files, especially on Linux systems. By the way, if you find a keytab during a pentest, don’t forget to extract its keys because you’ll be able to create a silver ticket against the service, as I once did (see below ️⬇️️), or access other services with this identity.

Clément Notin on Twitter: "#Pentest success story:1. Steal .keytab file from a Linux server for a webapp using Kerberos authentication🕵️2. Extract Kerberos service encryption key using https://t.co/itX7S337o03. Create silver ticket using #mimikatz🥝 and pass-the-ticket4. Browse the target5. Profit!😉 pic.twitter.com/yI9yfoXDrb / Twitter"

Pentest success story:1. Steal .keytab file from a Linux server for a webapp using Kerberos authentication🕵️2. Extract Kerberos service encryption key using https://t.co/itX7S337o03. Create silver ticket using #mimikatz🥝 and pass-the-ticket4. Browse the target5. Profit!😉 pic.twitter.com/yI9yfoXDrb

So it’s no surprise that Wireshark expects its keys in a keytab too. It’s a binary format which can contain several keys, for different encryption algorithms, and potentially for different users.

Wireshark wiki describes how to create the keytab file, using various tools like ktutil. But the one I found the most convenient is keytab.py, by Dirk-jan @_dirkjan Mollema, who wrote it to decrypt Kerberos in his research on Active Directory forest trusts. I especially like that it doesn’t ask for the cleartext password, just the raw keys, contrary to most other tools.

First, download keytab.py (you don’t even need the entire repo). Additionally, install impacket if you have not already done so.

Then, open the script and edit lines 112 to 118 and add all the keys you have (in hexadecimal format) with the number corresponding to their type. For example, as we said, most of the time AES256 is used, corresponding to type 18.

The more keys you have, the better 🎉 If you are hesitant, you can even include the RC4 and AES256 keys for the same user. As Dirk-jan comments in the code, you can include the “krbtgt” key, “user” keys (belonging to the client user), “service” keys (belonging to the service user), and even “trust” keys (if you want to decrypt referral tickets in inter-realm Kerberos authentications). You can also add “computer account” keys to decrypt machines’ Kerberos communications (machine accounts in AD are users after all! Just don’t forget the dollar at the end when requesting their keys with DCSync). You don’t need to worry about the corresponding username or domain name in the keytab; it doesn’t matter for Wireshark.

Finally, run the script and pass the output filename as argument:

$ python keytab.py keytab.kt

Back to Wireshark

Configuration

Now that you have the keytab, open the Wireshark Preferences window, and under Protocols, look for “KRB5”.

Check “Try to decrypt Kerberos blobs” and Browse to the location of the keytab file you just generated.

Decrypt Kerberos

Now you can try opening some Kerberos exchanges. Everything that is properly decrypted will be highlighted in light blue. Here are a couple examples:

AS-REQ with the decrypted timestamp
AS-REP with the decrypted PAC (containing the user’s privileges, see [MS-PAC])
TGS-REP with its two parts, including the service ticket, both containing the same session key

⚠️ If you notice parts highlighted in yellow it means that the decryption failed. Perhaps the corresponding key is missing in the keytab, or its value for the selected algorithm was not provided (check the “etype” field to see which algorithm is used). For example:

👩‍🎓 Surprise test about Kerberos theory: can you guess whose key I provided here, and whose key is missing?

Answer: We observe that Wireshark can decrypt the first part which is the TGT encrypted with the KDC key, but it cannot decrypt the second part which is encrypted with the client’s key. Therefore, here the keytab only contains the krbtgt key.

Decrypt DCE/RPC, LDAP…

Do you remember how this all began? I wanted to decrypt DCERPC payloads, not the Kerberos protocol itself!

And… it works too! 💥

Quick reminder first, the same color rule applies: blue means that decryption is ok, and yellow means errors. If you see some yellow during the authentication phase of the protocol (here the Bind step) the rest will certainly cannot be decrypted:

Here are some examples where it works, notice how the “encrypted stub data” is now replaced with “decrypted stub data” 🏆

It also works with other protocols, like LDAP:

workstation checking if its LAPS password is expired, and thus due for renewal

Tip to refresh the keytab

A modified keytab file does not take effect immediately in Wireshark. Either you have to open the Preferences, disable Kerberos decryption, confirm, then re-open it to re-enable it, which is slow and annoying… Or the fastest I’ve found is to save the capture, close Wireshark and re-open the capture file.

NTLM decryption

What about NTLM? Can we do the same decryption if NTLMSSP authentication is used? The answer is yes! 🙂

In the Preferences, scroll to the “NTLMSSP” protocol, and type the cleartext password in the “NT Password” field. This is described in the Wireshark NTLMSSP wiki page where I have added some examples. Some limitations contrary to Kerberos: you need the cleartext password and it must be ASCII only (this limitation is mentioned in the source code) so it is not applicable to machine account passwords, and you can only provide one at a time, contrary to the keytab which can hold keys for several users.

Update: actually, it is possible to decrypt using NTLM hash(es)! This feature is not documented, and not possible through the UI, but by looking at the code we can see that it is indeed possible as described in this CTF writeup: Insomni’Hack Teaser 2023 — Autopsy.
How to provide the NT hash(es)? Using a keytab too! It’s a bit confusing to use a Kerberos option to decrypt NTLMSSP but it works. If you remember earlier, I said that the RC4 key to put in a keytab is identical to the NT hash. So, you have to create a keytab entry, as explained previously, using the RC4-HMAC type (etype 23) and with the NT hash. Enable it in the Wireshark KRB5 options, same as before, and your NTLM encrypted trafic will be in clear-text if the hash is correct.

Conclusion

I hope these tips will help you in your journey to examine “encrypted stub data” payloads using Wireshark. This is something that we often do at Tenable when doing research on Active Directory, and I hope it will benefit you too!

Protocols become increasingly encrypted by default, which is a very good thing… Therefore, packet capture analysis, without decryption capabilities, will become less and less useful, and I’m thankful to see those tools including such features. Do you know other protocols that Wireshark can decrypt? Or perhaps with other tools?


Decrypt Kerberos/NTLM “encrypted stub data” in Wireshark was originally published in Tenable TechBlog on Medium, where people are continuing the conversation by highlighting and responding to this story.

❌
❌