Site icon API Security Blog

MagicWeb: NOBELIUM’s post-compromise trick to authenticate as anyone

Microsoft security researchers have discovered a post-compromise capability we’re calling MagicWeb, which is used by a threat actor we track as NOBELIUM to maintain persistent access to compromised environments. NOBELIUM remains highly active, executing multiple campaigns in parallel targeting government organizations, non-governmental organizations (NGOs), intergovernmental organizations (IGOs), and think tanks across the US, Europe, and Central Asia. The Microsoft Threat Intelligence Center (MSTIC) assesses that MagicWeb was likely deployed during an ongoing compromise and was leveraged by NOBELIUM possibly to maintain access during strategic remediation steps that could preempt eviction.

NOBELIUM has used abuse of identities and credentialed access as a method for maintaining persistence, and a specialized capability like MagicWeb is not novel for the actor: in September 2021, Microsoft disclosed a post-exploitation capability named [FoggyWeb]() with methods and intent similar to MagicWeb. FoggyWeb was capable of exfiltrating the configuration database of compromised AD FS servers, decrypting [token-signing certificates]() and [token-decryption certificates](), and downloading and executing additional malware components. MagicWeb goes beyond the collection capabilities of FoggyWeb by facilitating covert access directly. MagicWeb is a malicious DLL that allows manipulation of the claims passed in tokens generated by an Active Directory Federated Services (AD FS) server. It manipulates the user authentication certificates used for authentication, not the signing certificates used in attacks like Golden SAML.

NOBELIUM was able to deploy MagicWeb by first gaining access to highly privileged credentials and moving laterally to gain administrative privileges to an AD FS system. This is not a supply chain attack. The attacker had admin access to the AD FS system and replaced a legitimate DLL with their own malicious DLL, causing malware to be loaded by AD FS instead of the legitimate binary. The backdoor was discovered by Microsoft’s Detection and Response Team (DART) in coordination with MSTIC and Microsoft 365 Defender Research during an ongoing incident response investigation. Microsoft is sharing this information with consent from the client. At the time of this investigation, MagicWeb appears to be highly targeted.

Like domain controllers, AD FS servers can authenticate users and should therefore be treated with the same high level of security. Customers can defend against MagicWeb and other backdoors by implementing a holistic security strategy including the [AD FS hardening guidance](). In the case of this specific discovery, MagicWeb is one step of a much larger intrusion chain that presents unique detection and prevention scenarios.

With all critical infrastructure such as AD FS, it is important to ensure attackers do not gain administrative access. Once attackers gain administrative access, they have many options for further system compromise, activity obfuscation, and persistence. We recommend that any such infrastructure is isolated, accessible only by dedicated admin accounts, and regularly monitored for any changes. Other security measures that can prevent this and other attacks include credential hygiene to prevent lateral movement. AD FS is an on-premises server, and as with all on-premises servers, deployments can get out of date and/or go unpatched, and they can be impacted by local environment compromises and lateral movement. For these reasons, [migration to a cloud-based identity solution such as Azure Active Directory]() for federated authentication is recommended for the robust security it provides. See the mitigation section below for more information. Though we assess the capability to be in limited use, Microsoft anticipates that other actors could adopt similar methodologies and therefore recommends customers review hardening and mitigation guidance provided in this blog.

## How MagicWeb subverts authentication

MagicWeb is a post-compromise malware that can only be deployed by a threat actor after gaining highly privileged access to an environment and moving laterally to an AD FS server. To achieve their goal of maintaining persistent access to an environment by validating authentication for any user account on the AD FS server, NOBELIUM created a backdoored DLL by copying the legitimate _Microsoft.IdentityServer.Diagnostics.dll_ file used in AD FS operations. The legitimate version of this file is [catalog signed]() by Microsoft and is normally loaded by the AD FS server at startup to provide debugging capabilities. NOBELIUM’s backdoored version of the file is unsigned. The threat actor’s highly privileged access that allowed them to access the AD FS server meant they could have performed any number of actions in the environment, but they specifically chose to target an AD FS server to facilitate their goals of persistence and information theft during their operations.

After gaining administrative access to an AD FS server via elevation of privilege and lateral movement, the loading of NOBELIUM’s malicious _Microsoft.IdentityServer.Diagnostics.dll_ into the AD FS process is possible by editing _C:WindowsAD FSMicrosoft.IdentityServer.Servicehost.exe.config_ to specify a different public token, which controls what loads into the AD FS process when it is started. Because AD FS is a .NET application, it loads the DLLs specified in the config file from the [Global Assembly Cache]() (GAC). By changing the token in the configuration, the adversary directed AD FS to load in the malicious DLL. The interception and manipulation of claims by MagicWeb enables the actor to generate tokens that allow the adversary to bypass AD FS policies (role policies, device policies, and network policies) and sign in as any user with any claims, including multifactor authentication (MFA).

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig1-microsoft-identityserver-servicehost-exe.png)Figure 1. _C:WindowsAD FSMicrosoft.IdentityServer.Servicehost.exe.config_ being set to load _Microsoft.IdentityServer.Diagnostics.dll_ ![Screenshot of a section of a configuration file with the PublicKeyToken partially redacted.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig2-nobelium-public-token.png)Figure 2. NOBELIUM uses a different public token than the legitimate _Microsoft.IdentityServer.Diagnostics.dll_, telling AD FS to look for a different file in the GAC ![Partial screenshot of a configuration file showing MagicWeb’s malicious PublicKeyToken (partially redacted) and a legitimate one.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig3-magicweb-publickeytoken.png)Figure 3. Close up from _Microsoft.IdentityServer.Servicehost.exe.config_ showing MagicWeb’s malicious _PublicKeyToken _compared to the _PublicKeyToken _of the legitimate version of the DLL ![Screenshot of Windows File Explorer showing the Microsoft.IdentityServer.Diagnostics. directory with two folders. The folder name related to the malicious file is partially redacted.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig4-gac-directories-infected-magicweb.png)Figure 4. The directories in the GAC on a server infected with MagicWeb; the malicious _Microsoft.IdentityServer.Diagnostics.dll_ file and the legitimate one are located in different directories

To understand how NOBELIUM can subvert the AD FS process with the MagicWeb malware, it’s important to understand how AD FS claims work. AD FS extends the ability to use single sign-on functionality available within a single security or enterprise boundary to internet-facing applications to provide customers, partners, and suppliers a streamlined user experience while accessing an organization’s web-based applications. AD FS relies on [claims-based authentication]() to validate the identity of the user and their authorization claims. These claims are packaged into a token that can be used for authentication. MagicWeb injects itself into the claims process to perform malicious actions outside the normal roles of an AD FS server.

![Diagram containing icons and arrows summarizing how AD FS claims work.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig5-how-ad-fs-claims-work.png)Figure 5. How the AD FS claims pipeline issues a token for a user entering a federated application

Security Assertion Markup Language (SAML) uses x509 certificates to establish trust relationships between identity providers and services and to sign and decrypt tokens. These x509 certificates contain enhanced key usage (EKU) values that specify what applications the certificate should be used for. For instance, an EKU containing an Object Identifier (OID) value of 1.3.6.1.4.1.311.20.2.2 would allow for the use of a SmartCard logon. Organizations can create custom OIDs to further narrow certificate usage.

MagicWeb’s authentication bypass comes from passing a non-standard Enhanced Key Usage OID that is hardcoded in the MagicWeb malware during an authentication request for a specified User Principal Name. When this unique hard coded OID value is encountered, MagicWeb will cause the authentication request to bypass all standard AD FS processes (including checks for MFA) and validate the user’s claims. MagicWeb is manipulating the user authentication certificates used in SAML sign-ins, not the signing certificates for a SAML claim used in attacks like Golden SAML.

![Screenshot of a user certificate’s Details tab with the OID partially redacted.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig6-user-certificated-created-by-magicweb.png)Figure 6. Example of a user certificate accepted by MagicWeb; the highlighted numbers under “Unknown Key Usage” is one of two OIDs hardcoded into MagicWeb ![Screenshot of a user certificate’s Certification Path tab.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig7-sample-user-certificate-generated-via-magicweb.png)Figure 7. Example of a user certificate chain, which shows an invalid digital signature but still works for authentication

NOBELIUM uses unique tradecraft per target, so it’s highly likely that the OIDs and public tokens are unique per target as well. We’ve redacted these OIDs and tokens in this report. Please see the hunting guidance section for information on how to look for variants related to this attack.

## How to mitigate this threat

NOBELIUM’s ability to deploy MagicWeb hinged on having access to highly privileged credentials that had administrative access to the AD FS servers, giving them the ability to perform whatever malicious activities they wanted to on the systems they had access to.

It’s critical to treat your AD FS servers as a [Tier 0]() asset, protecting them with the same protections you would apply to a domain controller or other critical security infrastructure. AD FS servers provide authentication to configured relying parties, so an attacker who gains administrative access to an AD FS server can achieve total control of authentication to configured relying parties (include Azure AD tenants configured to use the AD FS server). Practicing credential hygiene is critical for protecting and preventing the exposure of highly privileged administrator accounts. This especially applies on more easily compromised systems like workstations with controls like [logon restrictions]() and preventing lateral movement to these systems with controls like the Windows Firewall.

Migration to Azure Active Directory (Azure AD) authentication is recommended to reduce the risk of on-premises compromises moving laterally to your authentication servers. Customers can use the following references on migration:

* [Use the activity report to move AD FS apps to Azure AD]()
* [Move application authentication to Azure AD]()

## Advanced hunting queries

### Recommended hunting guidance

* Have Inventory Certificate Issuance policies in your Public Key Infrastructure (PKI) environment, including all EKU attributes used in the environment and compare to known OID values.
* Hunt across Windows Event Logs by enabling AD FS [verbose logging]() and collect [AD FS event logs]() specifically looking for **Event ID 501**, which specifies all the EKU attributes on a claim. Hunt across these logs to look for EKU values which your PKI infrastructure isn’t configured to issue.
* Look for portable executable files in the GAC or AD FS directories on your systems that aren’t signed by Microsoft and inspect these files or [submit them for analysis]().
* Perform an audit of your exclusion settings to be sure that the AD FS and GAC are included in scans. Many organizations exclude the AD FS directories from security software scanning because of performance degradation concerns.

### Microsoft Sentinel

Microsoft Sentinel customers who have [enabled verbose mode logging]() for ADFS can use this query to look for suspicious OIDs: .

let OIDList = SecurityEvent| where TimeGenerated >= ago(1d)
| where EventSourceName == ‘AD FS Auditing’| where EventID == 501| where EventData has ‘/eku’| extend OIDs = extract_all(@”([d+.]+)”, EventData)
| mv-expand OIDs| extend OID = tostring(OIDs)
| extend OIDLength = strlen(OID)
| project TimeGenerated, Computer, EventSourceName, EventID, OID, OIDLength, EventData;
OIDList| where TimeGenerated >= ago(1h)
| join kind=leftanti (
OIDList| where TimeGenerated between (ago(1d) .. ago(1h))
| summarize by OID) on OID

### Searching for unsigned files in the GAC

The legitimate _Microsoft.IdentityServer.Diagnostics.dll_ is [catalog signed]() by Microsoft. Catalog signing is a method Windows uses for validating code integrity different from [Authenticode](), and is used for offline validation rather than runtime enforcement of running only signed code. The catalog signing on this file means the file may appear to be unsigned on the file properties pane and in file integrity checkers, security tools, and online malware repositories. The scripts below allow you to look for unsigned binaries and understand both catalog-signed binaries and Authenticode-signed binaries.

**Surface unsigned DLLs in GAC using Microsoft 365 Defender**

This query surfaces unsigned DLLs in the GAC folder created within the last 60 days.

DeviceFileEvents
| where Timestamp between( ago(60d)..now() )
| where FolderPath has @”C:WindowsMicrosoft.NETassemblyGAC_MSILMicrosoft.IdentityServer.”
and FileName endswith “.dll”
| join (
DeviceFileCertificateInfo
| where not(IsSigned)
) on SHA1

**Enumerate non-Microsoft signed DLLs in the GAC using PowerShell**

Below is an example script that could be used to enumerate non-Microsoft signed DLLs in the relevant GAC folder, where _servers.txt_ is a list of servers you wish to scan. Because the legitimate _Microsoft.IdentityServer.Diagnostics.dll_ is catalog signed, signing won’t appear when viewing file properties, but it will show in PowerShell querying and on load of the DLL.

$servers = get-content -Path (path to file)servers.txt
Foreach ($server in $servers) {
Write-Output “Processing server: $server”
Invoke-Command -ComputerName $server {Get-ChildItem -Filter “*.dll” -Recurse “C:WindowsMicrosoft.NETassemblyGAC_MSIL” | get-authenticodesignature | ft}
}

## Detections

### Microsoft Defender Antivirus

Microsoft Defender Antivirus provides detection for this threat under the following malware name:

* Trojan:MSIL/MagicWeb.A!dha

### Microsoft Defender for Endpoint

Microsoft Defender for Endpoint customers may see the following alert as an indication of possible attack:

* ADFS persistent backdoor detected

## Indicators of compromise (IOCs)

Microsoft isn’t sharing IOCs on this NOBELIUM activity at this time. However, NOBELIUM frequently customizes infrastructure and capabilities per campaign, minimizing operational risk should their campaign specific attributes be discovered. If MagicWeb is identified in your environment, it’s unlikely to match any static IOCs from other targets such as a SHA-256 value. It’s recommended to use the hunting guidance provided above to investigate your environment.

## Technical analysis of MagicWeb

NOBELIUM has modified the legitimate _Microsoft.IdentityServer.Diagnostics.dll_ by adding malicious code to the TraceLog class from the _Microsoft.IdentityServer.Diagnostics_ namespace/type.

The header section of the TraceLog class from the **_legitimate_**_ Microsoft.IdentityServer.Diagnostics.dll_ is shown below:

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig8-tracelog-class.png)Figure 8. The header section of the TraceLog class of _Microsoft.IdentityServer.Diagnostics _namespace/type from the legitimate _Microsoft.IdentityServer.Diagnostics.dll_

Meanwhile, the header section of the TraceLog class from NOBELIUM’s **_backdoored_**version of _Microsoft.IdentityServer.Diagnostics.dll_ is shown below:

![Screenshot of a section of a configuration file with the TraceLog() class highlighted.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig9-tracelog-class-header-section.png)Figure 9. The header section of the TraceLog class of _Microsoft.IdentityServer.Diagnostics _namespace from NOBELIUM’s backdoored version of _Microsoft.IdentityServer.Diagnostics.dll_

In the backdoored version of the code, as shown above, NOBELIUM has added a static constructor for the TraceLog class. A [static constructor]() is used to initialize any static data, or to perform a particular action that needs to be performed only once. It’s called automatically before the first instance is created or any static members are referenced.

The malicious static constructor gets executed once before the first instance of the TraceLog class is created. Given that new instances of the TraceLog class is created in various locations in this DLL, the execution of the malicious static constructor is guaranteed to occur as soon as the DLL is loaded for the first time (which would be upon startup of the AD FS server after the malicious changes to _Microsoft.IdentityServer.Servicehost.exe.config _described above).

NOBELIUM’s malicious static constructor contains a reference to the _Initialize()_ method from a class named _AuthLog_**.**

![Screenshot of a section of a configuration file with the Initialize() method highlighted.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig10-reference-initialize-method.png)Figure 10. Reference to the _Initialize()_ method from a class named _AuthLog_ in the malicious static constructor

The _AuthLog_ class is a brand-new and malicious class that’s been added to the DLL by NOBELIUM.

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig11-initialize-method-authlog-class.png)Figure 11. The _Initialize()_ method of the _AuthLog_ class

As shown above, the _Initialize()_ method references a class named _RuntimeHelper_, yet another class added to the DLL by the actor. The primary purpose of the _RuntimeHelper_ class and its _OverloadMethod()_ method is to hook legitimate AD FS related methods at runtime. By hooking the legitimate AD FS methods, the backdoor is capable of intercepting calls to the legitimate methods to instead invoke its own custom methods.

The screenshot above shows the following legitimate AD FS methods being hooked by MagicWeb:

**Target assembly/DLL**| **Target type**| **Target method to hook**| **Malicious hook method (actor introduced)**
—|—|—|—
_Microsoft.IdentityServer.IdentityModel.dll_| _Microsoft.IdentityModel.X509CertificateChain_| _Build_| _BeginBuild_
_Microsoft.IdentityServer.WebHost.dll_| _Microsoft.IdentityServer.WebHost.WrappedHttpListenerRequest_| _GetClientCertificate_| _BeginGetClientCertificate_
_Microsoft.IdentityServer.WebHost.dll_| _Microsoft.IdentityServer.WebHost.Proxy.ProxyConfigurationData_| _EndpointConfiguration_| _BeginEndpointConfiguration_
_Microsoft.IdentityServer.Service.dll_| _Microsoft.IdentityServer.Service.IssuancePipeline.PolicyEngine_| _ProcessClaims_| _BeginProcessClaims_

### Hook method: _BeginBuild()_

MagicWeb’s _BeginBuild()_ method is used to hook the legitimate target method _Build()_ (from _Microsoft.IdentityServer.IdentityModel.dll_).

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig12-magicweb-begin-build-method.png)Figure 12. MagicWeb’s _BeginBuild()_ method

The_ BeginBuild() _method first calls the MagicWeb’s helper method _ValidateX509Extensions()_.

If the helper method _ValidateX509Extensions() _returns true, _BeginBuild()_ returns true.

If _ValidateX509Extensions()_ returns false, or an exception is thrown by calling _ValidateX509Extensions()_, _BeginBuild() _invokes and returns the value returned by the legitimate _Build()_ method from _Microsoft.IdentityServer.IdentityModel.dll_.

This means that before the legitimate target method _Build()_ from the legitimate _Microsoft.IdentityServer.IdentityModel.dll_ gets an opportunity to inspect/build a certificate, MagicWeb’s hook method first inspects the certificate and returns true if the helper method _ValidateX509Extensions()_ returns true.

This allows the attacker to subvert the normal certificate inspection/build process by introducing a custom certificate inspection/build method that’s invoked before the legitimate _Build()_ method is invoked.

### Helper Method: _ValidateX509Extensions()_

MagicWeb’s helper method _ValidateX509Extensions()_ is called by _BeginBuild()_ and other methods.

![Screenshot of a section of a configuration file with partially redacted hash values.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig13-helper-method-ValidateX509Extensions.png)Figure 13. Helper method _ValidateX509Extensions()_

_ValidateX509Extensions()_ returns false if the X509 certificate passed to the method is null or the Microsoft Cryptographic API certificate context handle/pointer isn’t set.

Next, the method enumerates the extensions in the X509 certificate passed to the method. If an enumerated extension is of type _X509EnhancedKeyUsageExtension_, the method iterates the OIDs of the extension, calculating the MD5 hash of each OID (using a custom hash computation helper method _ComputeHash()_ that leverages the .NET _MD5_ class).

If the MD5 hash value of the OID matches one of the two following hardcoded MD5 values, the method returns true (this methodology is used to check if one of the two OID values below are present in the extension):

* _67F5BD28A842A1C9[REDACTED]_ (MD5 hash value corresponding to the OID value _1.3.6.1.4.1.311.21.8.868518.12957973.4869258.12250419.[REDACTED].[REDACTED].[REDACTED].[REDACTED]_)
* _6E3466296D2F63D[REDACTED]_ (MD5 hash value corresponding to the OID value _1.3.6.1.4.1.311.21.8.868518.12957973.4869258.12250419.[REDACTED].[REDACTED].[REDACTED].[REDACTED]_)

If none of the OID values are present, the method returns false.

This helper method returns true if the certificate passed to the method contains one of the two magic OID values listed above.

### Hook method: _BeginGetClientCertificate()_

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig14-BeginGetClientCertificate-hooking-legitimate-target-method.png)Figure 14. MagicWeb’s _BeginGetClientCertificate()_ method, used to hook the legitimate target method _GetClientCertificate()_ (from _Microsoft.IdentityServer.WebHost.dll_)

To retrieve the client’s X509 certificate, this method first calls the legitimate _GetClientCertificate()_ method from _Microsoft.IdentityServer.WebHost.dll_. Next, the hook method calls the helper method _ValidateX509Extensions()_ to determine whether the client certificate contains one of the two “magic” OID values. If the client certificate contains one of the two OID values, the hook method:

* Obtains the __adapter_ field from the current object
* Obtains the __request_ field from the __adapter_ object
* Sets the value of the _m_ClientCertificateError_ field (from the __request_ object) to 0

This means that regardless of what the legitimate method _GetClientCertificate()_ (from _Microsoft.IdentityServer.WebHost.dll_) sets the _m_ClientCertificateError_ field to, if a client certificate contains one of the magic OID values, the hook method overwrites or sets the _m_ClientCertificateError_ field to 0.

By using this technique, the hook method appears to be influencing the normal behavior of the application to treat or accept a non-valid client certificate as a valid certificate.

### Hook method: _BeginProcessClaims()_

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig15-BeginProcessClaims-magicweb.png)Figure 15. The _BeginProcessClaims()_ method of MagicWeb, used to hook the legitimate target method _ProcessClaims() _(from _Microsoft.IdentityServer.Service.dll_)

The hook method first indirectly invokes the legitimate _ProcessClaims()_ method by invoking the _ProcessClaims()_ method of the _AuthLog_ class.

On line 198 in figure 16, the hook method calls MagicWeb’s helper method _GetClaims()_, passing in the __processed__ identity object returned by invoking the legitimate _ProcessClaims()_ method.

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig16-getclaims-helper-method.png)Figure 16. The _GetClaims()_ helper method

As shown above, the _GetClaims()_ method accepts an identity object as a parameter. The method then initializes three variables named _type_, _type2_, and _type3_ with values obtained from the _RuntimeHelper_’s static field/array named _types_:

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig17-initialized-values.png)Figure 17. The three variables initialized with values

The _types_ field contains the following values:

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig18-values-in-types-field.png)Figure 18. Values in the _types_ field

The _assemblyByName2_ variable above contains an assembly object representing the legitimate assembly _Microsoft.IdentityServer.IdentityModel.dll_ (if not already loaded, the _RuntimeHelper_ class loads the assembly into the current application domain). By calling the _GetType()_ method, _RunHelper_ initializes the member of the _types_ field/array with .NET types from the _Microsoft.IdentityServer.IdentityModel.dll_ assembly.

Returning to the _GetClaims()_ method and the initialization of _type_, _type2_, and _type3_ the variables _type_, _type2_, and _type3_ get initialized with the following type objects from _Microsoft.IdentityServer.IdentityModel.dll_:

* type: _Microsoft.IdentityModel.Claims.IClaimsIdentity_ type object
* type2: _Microsoft.IdentityModel.Claims.ClaimCollection_ type object
* type3: _Microsoft.IdentityModel.Claims.Claim_ type object

Next, the _GetClaims()_ method retrieves the _Claims_ property of the _Microsoft.IdentityModel.Claims.IclaimsIdentity_ identity object. It also retrieves the number of claims (of type _Microsoft.IdentityModel.Claims.ClaimCollection_) present in the _Claims_ property:

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig19-getclaims-retrieving-claims-property.png)Figure 19. _GetClaims()_ retrieving the Claims property

_GetClaims()_ then enumerates the claims (of type _Microsoft.IdentityModel.Claims.Claim_), retrieving the string containing each claim and the corresponding claim type:

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig20-getclaims-enumerating-claims.png)Figure 20. _GetClaims()_ enumerating the claims, retrieving the strings, and storing in list

As shown above, the claim string and claim type string are then stored in a list named _list_. This list of claims and their corresponding claim types is then returned to the caller of the _GetClaims()_ method, _BeginProcessClaims()_.

Returning to the _BeginProcessClaims()_ method, after retrieving the claims using the _GetClaims()_ method, the hook method _BeginProcessClaims()_ searches the claims list for presence of a claim with claim type of _https://schemas.microsoft.com/claims/authnmethodsreferences:_

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig21-BeginProcessClaims-searching-claims-list.png)Figure 21. _BeginProcessClaims()_ searching the claims list for a specific claim

As shown on line 198 above, the claim(s) of type _https://schemas.microsoft.com/claims/authnmethodsreferences_ (if any) is stored in a list named _list_. If claim of type _https://schemas.microsoft.com/claims/authnmethodsreferences_ is present and its value is set to _https://schemas.microsoft.com/claims/multipleauthn_, the hook method returns the _IclaimsIdentity_ object returned by the legitimate target method _ProcessClaims()_ (from _Microsoft.IdentityServer.Service.dll_) on line 191 of the hook method.

This behavior ensures that if MFA is already satisfied, then the hook method simply acts as a pass-through method and doesn’t affect the normal behavior of the claim processing pipeline.

If a claim of type _https://schemas.microsoft.com/claims/authnmethodsreferences_ is _not _present or its value is _not _set to _https://schemas.microsoft.com/claims/multipleauthn_, the hook method proceeds to perform additional checks on the __unprocessed_ _claims (that is, the claims contained in the unprocessed identity object _identity_ passed to the hook method). Once again, the hook method obtains a list of claims by calling the _GetClaims()_ helper method. As mentioned above, instead of calling the _GetClaims()_ helper method with the processed identity object returned by invoking the legitimate _ProcessClaims()_ method (stored in the _result_ variable on line 191), the hook method calls the _GetClaims()_ helper method with the unprocessed identity object _identity_ passed to the hook method:

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig22-hook-method-calling-GetClaims.png)Figure 22. The hook method calling _GetClaims()_

On line 204, the hook method enumerates the value of each claim and uses the _ComputeHash()_ helper method to calculate the MD5 hash value of each claim value (from the __unprocessed __identity object). It then checks if the MD5 value of any of the claims equals the MD5 hash value _6E3466296D2F63DE[REDACTED]_. This hash value is the only element of a hardcoded hash list named _oidMFAHashes_ (that is, this list can be expanded to include other hash values of interest):

![Screenshot of a section of a configuration file with a partially redacted hash value.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig23-hardcoded-hash-list-containing-md5-hash.png)Figure 23. Hardcoded hash list containing the MD5 hash value of a magic OID valuea

If none of the claims have a value with MD5 hash value of _6E3466296D2F63DE[REDACTED]_, on line 206, the method simply returns the __processed __identity object returned by the legitimate target method _ProcessClaims()_ (from _Microsoft.IdentityServer.Service.dll_) on line 191 of the hook method. As previously discussed, the hash value _6E3466296D2F63DE[REDACTED]_ corresponds to the OID value _1.3.6.1.4.1.311.21.8.868518.12957973.4869258.12250419.[REDACTED].[REDACTED].[REDACTED].[REDACTED]_.

Hence, the hook method enumerates the claims and if a claim with value _1.3.6.1.4.1.311.21.8.868518.12957973.4869258.12250419.[REDACTED].[REDACTED].[REDACTED].[REDACTED]_ isn’t present on the claim list, the hook method simply acts as a pass-through method and doesn’t affect the normal behavior of claim processing pipeline.

If by this point in the execution cycle the hook method hasn’t returned yet, it means one of the claims contains the OID value _1.3.6.1.4.1.311.21.8.868518.12957973.4869258.12250419.[REDACTED].[REDACTED].[REDACTED].[REDACTED]_ (otherwise, according to the logic described in the paragraph above, the hook method would’ve returned).

Proceeding with confirmation that one of the claims contains the OID value _1.3.6.1.4.1.311.21.8.868518.12957973.4869258.12250419.[REDACTED].[REDACTED].[REDACTED].[REDACTED]_, the hook method proceeds to the section that represents the main purpose of MagicWeb, to perform claim injection.

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig24-main-section-of-code-responsible-for-claims-injection.png)Figure 24. Main section of the code responsible for the claim injection process

Before describing the code responsible for the claim injection process, it’s important to revisit what’s already stored in the _list_ and _claims_ variables:

* _list_: As mentioned before, the hook method invokes the legitimate method _ProcessClaims()_ to process the incoming identity object. The processed identity object (stored in _result_ on line 191) is then passed to the _GetClaims()_ helper method to obtain a list of claim type/value pairs extracted from the processed identity object (line 198). After obtaining the claim type/value pairs, the claim(s) of type _https://schemas.microsoft.com/claims/authnmethodsreferences_ (if any) are stored in a list named _l__ist_ (line 198).
![Screenshot of a section of a configuration file with a partially redacted hash value.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig25-list-variable.png)Figure 25. The _list_ variable

_claims_: As mentioned above, this variable is used to store a list of claim type/value pairs extracted from the unprocessed identity object:

![Screenshot of a line in a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig26-claims-variable.png)Figure 26. The _claims _variable

With this information in mind (and the fact that one of the claims contains the OID value _1.3.6.1.4.1.311.21.8.868518.12957973.4869258.12250419.__[REDACTED]__.__[REDACTED]__.__[REDACTED]__.__[REDACTED]_), once again here’s the first part of the claim injection code:

![Screenshot of a section of a configuration file with specific lines highlighted.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig27-part-of-claim-injection-code.png)Figure 27. Part of the claim injection code

As shown above, if _list_ is empty (that is, the processed identity object contained no claim type/value pairs of type _https://schemas.microsoft.com/claims/authnmethodsreferences_), the hook method instead turns to _claims_ (containing the list of all claim type/value pairs extracted from the unprocessed identity object) and searches for claim type/value pairs of type _https://schemas.microsoft.com/claims/authnmethodsreferences_ in the _claims_ list. If the _claims_ list contains one or more claim type/value pairs of type _https://schemas.microsoft.com/claims/authnmethodsreferences_, the hook method uses the claim information to add an identical claim of type _https://schemas.microsoft.com/claims/authnmethodsreferences_ to the processed identity object (line 213 above).

Using this method, if after passing the identity object to the legitimate _ProcessClaims()_ method, no claim of type _https://schemas.microsoft.com/claims/authnmethodsreferences_ is returned by the legitimate method, the hook method manually adds a fraudulent claim of type _https://schemas.microsoft.com/claims/authnmethodsreferences_ to the list of claims returned to the caller of the hooked legitimate method _ProcessClaims()_.

As shown above, to add the fraudulent claim to the list of claims, the hook method calls a helper method named _AddClaim()_.

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig28-helper-method.png)Figure 28. The helper method

Like the code in the helper method _GetClaims()_, _AddClaims()_ initializes two variables with the following type objects:

* _type_: _Microsoft.IdentityModel.Claims.IClaimsIdentity_ type object
* _type2_: _Microsoft.IdentityModel.Claims.ClaimCollection_ type object

On line 235, _AddClaims()_ gets the constructor for type _Microsoft.IdentityModel.Claims.Claim_ and invokes the constructor (passing in the claim type and value from the caller of _AddClaim()_) to instantiate a new _Claim_ object.

![Screenshot of a line in a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig29-legitimate-internal-constructor.png)Figure 29. The legitimate internal constructor from _Microsoft.IdentityModel.Claims.Claim_

The _legitimate _internal constructor from _Microsoft.IdentityModel.Claims.Claim_, retrieved and invoked by _AddClaim()_, invokes the internal constructor _Claim_ (overloaded method) with the following method parameters:

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig30-internal-constructor-claim.png)Figure 30. The internal constructor Claim

After instantiating a new _Claim_ object, _AddClaim()_ uses the _Add()_ method from type _Microsoft.IdentityModel.Claims.ClaimCollection_ to add the new claim to the identity object passed to _AddClaim()_ by its caller (in this case, the new claim is added to the _identity_ object containing the list of claims returned by the call to the legitimate method _ProcessClaims()_).

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig31-legitimate-method-add.png)Figure 31. The legitimate method _Add()_ from type _Microsoft.IdentityModel.Claims.ClaimCollection_, invoked by _AddClaim()_ (line 245)

Revisiting the claim injection code in the hook method _BeginProcessClaims()_ (and recalling the fact that one of the claims contains the OID value _1.3.6.1.4.1.311.21.8.868518.12957973.4869258.12250419.[REDACTED].[REDACTED].[REDACTED].[REDACTED]_), here’s the second part of the claim injection code:

![Screenshot of a section of a configuration file with specific lines highlighted.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig32-second-part-claim-injection.png)Figure 32. Second part of the claim injection code

Recall that _list_ contains claim type/value pairs of type _https://schemas.microsoft.com/claims/authnmethodsreferences_ extracted from the processed identity object. If none of the claims in _list_ have the value _https://schemas.microsoft.com/claims/multipleauthn_, the hook method proceeds to call _AddClaim()_ to add a fraudulent claim of type _https://schemas.microsoft.com/claims/authnmethodsreferences_ and value _https://schemas.microsoft.com/claims/multipleauthn_ to the list of claims returned to the caller of the hooked legitimate method _ProcessClaims()_.

Using the fraudulent claim injection techniques described above, if a claim with the Magic OID value _1.3.6.1.4.1.311.21.8.868518.12957973.4869258.12250419.__[REDACTED]__.__[REDACTED]__.__[REDACTED]__.__[REDACTED]_ is presented to AD FS, regardless of how the legitimate hooked method _ProcessClaims()_ handles the claim, the _BeginProcessClaims()_ hook function ensures that a claim with value _https://schemas.microsoft.com/claims/multipleauthn_ is returned to the caller of the legitimate hooked method _ProcessClaims()_.

### Hook method:** **_BeginEndpointConfiguration()_

The backdoor _BeginEndpointConfiguration()_ method, used to hook the legitimate target method _EndpointConfiguration()_ (from _Microsoft.IdentityServer.WebHost.dll_) is shown below:

![Screenshot of a section of a configuration file.](https://www.microsoft.com/security/blog/uploads/securityprod/2022/08/fig33-BeginEndpointConfiguration-method.png)Figure 33. _BeginEndpointConfiguration()_ method

The enumType variable is initialized with _RuntimeHelper.types[0]_ which is a _Microsoft.IdentityServer.WebHost.Proxy.CertificateValidation_ type object. The _PropertyInfo_ variables _propertyInfo_, _propertyInfo2_, and _propertyInfo3_ are initialized with property objects retrieved from ‘properties’ field/array of _RuntimeHelper_:

* _propertyInfo_: _CertificateValidation_ property from type _Microsoft.IdentityServer.WebHost.Proxy.ProxyEndpoint_ of _Microsoft.IdentityServer.WebHost.dll_
* _propertyInfo2_: Path property from type _Microsoft.IdentityServer.WebHost.Proxy.ProxyEndpoint_ of _Microsoft.IdentityServer.WebHost.dll_
* _propertyInfo3: _Endpoints property from type _Microsoft.IdentityServer.WebHost.Proxy.ProxyEndpointConfiguration_ of _Microsoft.IdentityServer.WebHost.dll_

Next, the hook method retrieves the value of the _Endpoint_ property of the _value_ object that the legitimate _EndpointConfiguration()_ method was called with. The _Endpoint_ property holds a collection of _ProxyEndpoint_ objects. The hook method enumerates the _ProxyEndpoint_ objects and for each object, it checks if the value of the _CertificateValidation_ enum is set to ‘1’ which signifies ‘[SSL]()’. If the _CertificateValidation_ enum for a _ProxyEndpoint_ object is set to ‘1’/’SSL’, on line 165, the hook method overwrites the value of the _CertificateValidation_ enum with ‘0’ which signifies ‘None’. To ensure the change is reflected, the hook method then overwrites the _Endpoint_ property of the _value_ object with the updated _Endpoint_ property containing the overwritten _CertificateValidation_ enum values (that is, ‘SSL’ overwritten with ‘None’).

Behaving as a true hook method, on line 179, the method calls the legitimate _EndpointConfiguration()_ method but with the modified ‘value’ object. Hence, when the legitimate _EndpointConfiguration()_ method is invoked during the normal operation of AD FS, this hook method intercepts the call and, before passing the object to the legitimate_ EndpointConfiguration()_ method was invoked with, it overwrites the _CertificateValidation_ value of each _ProxyEndpoint_ object and only then it calls the legitimate _EndpointConfiguration()_ method but now with modified _CertificateValidation_ value(s), changed from ‘SSL’ to ‘None’.

The purpose of overwriting _CertificationValidation_ value to ‘None’ (wherever it’s ‘SSL’) is to allow WAP to pass the request with the specific malicious certificate to AD FS for further authentication processing. According to _Microsoft.IdentityServer.ProxyService/TLSClientReqeustHandler_, WAP stops sending the current request from client to AD FS if _CertificateValidation_ is ‘1’ (‘SSL’) and the client certificate has an error during validation.

## References

* [“I am AD FS and so can you: Attacking Active Directory Federated Services”](), Austin Baker and Douglas Bienstock, Troopers 2019
* [Understanding Key Active Directory Federation Services Concepts](), Microsoft documentation

The post [MagicWeb: NOBELIUM’s post-compromise trick to authenticate as anyone]() appeared first on [Microsoft Security Blog]().Read More

Exit mobile version