Normal view

There are new articles available, click to refresh the page.
Before yesterdayMain stream

NoArgs - Tool Designed To Dynamically Spoof And Conceal Process Arguments While Staying Undetected

By: Zion3R
16 April 2024 at 12:30


NoArgs is a tool designed to dynamically spoof and conceal process arguments while staying undetected. It achieves this by hooking into Windows APIs to dynamically manipulate the Windows internals on the go. This allows NoArgs to alter process arguments discreetly.


Default Cmd:


Windows Event Logs:


Using NoArgs:


Windows Event Logs:


Functionality Overview

The tool primarily operates by intercepting process creation calls made by the Windows API function CreateProcessW. When a process is initiated, this function is responsible for spawning the new process, along with any specified command-line arguments. The tool intervenes in this process creation flow, ensuring that the arguments are either hidden or manipulated before the new process is launched.

Hooking Mechanism

Hooking into CreateProcessW is achieved through Detours, a popular library for intercepting and redirecting Win32 API functions. Detours allows for the redirection of function calls to custom implementations while preserving the original functionality. By hooking into CreateProcessW, the tool is able to intercept the process creation requests and execute its custom logic before allowing the process to be spawned.

Process Environment Block (PEB) Manipulation

The Process Environment Block (PEB) is a data structure utilized by Windows to store information about a process's environment and execution state. The tool leverages the PEB to manipulate the command-line arguments of the newly created processes. By modifying the command-line information stored within the PEB, the tool can alter or conceal the arguments passed to the process.

Demo: Running Mimikatz and passing it the arguments:

Process Hacker View:


All the arguemnts are hidden dynamically

Process Monitor View:


Technical Implementation

  1. Injection into Command Prompt (cmd): The tool injects its code into the Command Prompt process, embedding it as Position Independent Code (PIC). This enables seamless integration into cmd's memory space, ensuring covert operation without reliance on specific memory addresses. (Only for The Obfuscated Executable in the releases page)

  2. Windows API Hooking: Detours are utilized to intercept calls to the CreateProcessW function. By redirecting the execution flow to a custom implementation, the tool can execute its logic before the original Windows API function.

  3. Custom Process Creation Function: Upon intercepting a CreateProcessW call, the custom function is executed, creating the new process and manipulating its arguments as necessary.

  4. PEB Modification: Within the custom process creation function, the Process Environment Block (PEB) of the newly created process is accessed and modified to achieve the goal of manipulating or hiding the process arguments.

  5. Execution Redirection: Upon completion of the manipulations, the execution seamlessly returns to Command Prompt (cmd) without any interruptions. This dynamic redirection ensures that subsequent commands entered undergo manipulation discreetly, evading detection and logging mechanisms that relay on getting the process details from the PEB.

Installation and Usage:

Option 1: Compile NoArgs DLL:

  • You will need microsoft/Detours">Microsoft Detours installed.

  • Compile the DLL.

  • Inject the compiled DLL into any cmd instance to manipulate newly created process arguments dynamically.

Option 2: Download the compiled executable (ready-to-go) from the releases page.

Refrences:

  • https://en.wikipedia.org/wiki/Microsoft_Detours
  • https://github.com/microsoft/Detours
  • https://blog.xpnsec.com/how-to-argue-like-cobalt-strike/
  • https://www.ired.team/offensive-security/code-injection-process-injection/how-to-hook-windows-api-using-c++


Cloud_Enum - Multi-cloud OSINT Tool. Enumerate Public Resources In AWS, Azure, And Google Cloud

By: Zion3R
29 March 2024 at 11:30


Multi-cloud OSINT tool. Enumerate public resources in AWS, Azure, and Google Cloud.

Currently enumerates the following:

Amazon Web Services: - Open / Protected S3 Buckets - awsapps (WorkMail, WorkDocs, Connect, etc.)

Microsoft Azure: - Storage Accounts - Open Blob Storage Containers - Hosted Databases - Virtual Machines - Web Apps

Google Cloud Platform - Open / Protected GCP Buckets - Open / Protected Firebase Realtime Databases - Google App Engine sites - Cloud Functions (enumerates project/regions with existing functions, then brute forces actual function names) - Open Firebase Apps


See it in action in Codingo's video demo here.


Usage

Setup

Several non-standard libaries are required to support threaded HTTP requests and dns lookups. You'll need to install the requirements as follows:

pip3 install -r ./requirements.txt

Running

The only required argument is at least one keyword. You can use the built-in fuzzing strings, but you will get better results if you supply your own with -m and/or -b.

You can provide multiple keywords by specifying the -k argument multiple times.

Keywords are mutated automatically using strings from enum_tools/fuzz.txt or a file you provide with the -m flag. Services that require a second-level of brute forcing (Azure Containers and GCP Functions) will also use fuzz.txt by default or a file you provide with the -b flag.

Let's say you were researching "somecompany" whose website is "somecompany.io" that makes a product called "blockchaindoohickey". You could run the tool like this:

./cloud_enum.py -k somecompany -k somecompany.io -k blockchaindoohickey

HTTP scraping and DNS lookups use 5 threads each by default. You can try increasing this, but eventually the cloud providers will rate limit you. Here is an example to increase to 10.

./cloud_enum.py -k keyword -t 10

IMPORTANT: Some resources (Azure Containers, GCP Functions) are discovered per-region. To save time scanning, there is a "REGIONS" variable defined in cloudenum/azure_regions.py and cloudenum/gcp_regions.py that is set by default to use only 1 region. You may want to look at these files and edit them to be relevant to your own work.

Complete Usage Details

usage: cloud_enum.py [-h] -k KEYWORD [-m MUTATIONS] [-b BRUTE]

Multi-cloud enumeration utility. All hail OSINT!

optional arguments:
-h, --help show this help message and exit
-k KEYWORD, --keyword KEYWORD
Keyword. Can use argument multiple times.
-kf KEYFILE, --keyfile KEYFILE
Input file with a single keyword per line.
-m MUTATIONS, --mutations MUTATIONS
Mutations. Default: enum_tools/fuzz.txt
-b BRUTE, --brute BRUTE
List to brute-force Azure container names. Default: enum_tools/fuzz.txt
-t THREADS, --threads THREADS
Threads for HTTP brute-force. Default = 5
-ns NAMESERVER, --nameserver NAMESERVER
DNS server to use in brute-force.
-l LOGFILE, --logfile LOGFILE
Will APPEND found items to specified file.
-f FORMAT, --format FORMAT
Format for log file (text,json,csv - defaults to text)
--disable-aws Disable Amazon checks.
--disable-azure Disable Azure checks.
--disable-gcp Disable Google checks.
-qs, --quickscan Disable all mutations and second-level scans

Thanks

So far, I have borrowed from: - Some of the permutations from GCPBucketBrute



Top things that you might not be doing (yet) in Entra Conditional Access – Advanced Edition

18 March 2024 at 08:00
Top things you might not be doing (yet) in Entra ID Conditional Access - Advanced Edition

Introduction

In the first post of the top things that you might not be doing (yet) in Entra Conditional Access, we focused on basic but essential security controls that I recommend you checking out if you do not have them implemented already. In this second part, we’ll go over more advanced security controls within Conditional Access that, in my experience, are frequently overlooked in environments during security assessments. However, they can help you better safeguarding your identities.

Similar to my previous blog post, the list of controls provided here is not exhaustive. The relevance of each control may vary depending on your specific environment. Moreover, you should not rely on those only, but instead investigate whether they would bring any value in your environment. I also encourage you to check out other Conditional Access controls available to make sure your identities are correctly protected.

This article focusses on features that are available in Entra ID Premium P1 and P2 licenses. Therefore, if none of those licenses are available, check my previous blog post on how to protect identities in Entra ID Free: https://blog.nviso.eu/2023/05/02/enforce-zero-trust-in-microsoft-365-part-1-setting-the-basics/. Note that other licenses could also be required depending on the control.

Additionally, should you need any introduction to what Entra Conditional Access is and which security controls are available, feel free to have a look at this post: https://blog.nviso.eu/2023/05/24/enforce-zero-trust-in-microsoft-365-part-3-introduction-to-conditional-access/.

Finally, if you have missed part 1, feel free to check it out: https://blog.nviso.eu/2024/02/27/top-things-that-you-might-not-be-doing-yet-in-entra-conditional-access/.

Entra Conditional Access security controls

Make sure all Operating Systems are covered in your current Conditional Access design

License requirement: Entra ID Premium P1

When performing Entra Conditional Access assessments, we usually see policies to enforce controls on Windows, and sometimes Android and iOS devices. However, other platforms such as MacOS, Windows Phone, and Linux are sometimes forgotten. This can represent a significant gap in your overall security defense as access from those platforms is not restricted by default. You could use all the Conditional Access policy features, but if you do not include them, all your effort will be in vain.

Indeed, it is well known from attackers that “nonstandard” platforms are sometimes forgotten in Conditional Access. By trying to access your environment using them, they might be able to simply bypass your Conditional Access (CA) policies. It is therefore necessary to make sure that your security controls are applied across all operating systems.

The next points will shed some light on controls that you can implement to support all platforms.

Don’t be afraid of blocking access, but only in a considered and reasonable way 🙂

License requirement: Entra ID Premium P1

Based on our numerous assessments over the years, we have observed that ‘Block’ policies are typically not implemented in Conditional Access. While those policies can definitely have an adverse impact on your organization and end users, specific actions, device platforms, or client applications (see part 1), should be blocked.

For example, if you do not support Linux in your environment, why not simply block it? Moreover, if Linux is only required for some users, Conditional Access allows you to be very granular by targeting users, devices, locations, etc. Therefore, platforms can be blocked for most use cases, and you can still allow specific flows based on your requirements. This principle can be extended to (guest) user access to applications. Should guest users have access to all your applications? No? Then, block it. Such control effectively decreases the overall attack surface of your environment.

Conditional Access policy to block access to all cloud applications from Linux.
Example: Conditional Access policy to block access to all cloud applications from Linux.

I highly recommend you giving a thought to ‘Block’ policies. Moreover, they could be extended to many other scenarios on top of the device platforms and (guest) user access to cloud apps.

Before moving on to the next point, I want to highlight that such policies can be very powerful. So powerful that they could lock you out of your own environment. To avoid that, please, always exclude emergency / break-the-glass accounts. In addition, never rollout Conditional Access policies in production before proper testing. The report-only policy mode can be of great help for that. Moreover, the What If tool is also a very good tool that you should be using to assess the correctness of your policies. Once the potential impact and the policy configuration have been carefully reviewed, gradually roll out policies by waves over a period of a few weeks with different pilot groups.

Use App Protection Policies to reduce the risk of mobile devices

License requirement: Entra ID Premium P1 and Microsoft Intune

If access from mobile devices, i.e., Android and iOS, is required for end user productivity for example, App Protection Policies (APPs) can help you preventing data loss on devices that you may not fully manage. Note that App Protection Policies are also now available for Windows devices but are still in preview at the time of writing (beginning of March 2024).

In short, App Protection Policies are a set of rules that ensures that data access through mobile apps is secure and managed appropriately, even on personal devices. APPs can enforce the use of Microsoft-managed applications, such as Microsoft apps, enforce data encryption, require authentication, restrict actions between managed and unmanaged applications, wipe the data from managed applications, etc.

For that purpose, the following Grant control can be configured:

Enforce App Protection Policies in Conditional Access.
Example: Enforce App Protection Policies in Conditional Access.

Of course, to be effective, App Protection Policies should be created in Intune and assigned to users. Because of that, Microsoft Intune licenses are required for users in scope of that control.

Moreover, together with the Exchange Online and SharePoint Online app enforced restrictions capabilities, you can allow, restrict, or block access from third-party browsers on unmanaged devices.

Require Authentication Strengths instead of standard multi-factor authentication

License requirement: Entra ID Premium P1

Authentication Strength policies in Entra Identity Conditional Access enable administrators to mandate certain authentication methods, such as FIDO2 Security Keys, Windows Hello, Microsoft Authenticator, and passwordless authentication. Please note that the authentication methods available to users will be determined by either the new authentication method policies or the legacy MFA policy.

By configuring Authentication Strengths policies and integrating them in Conditional Access policies, you can further restrict (external) user access to sensitive applications or content in your organization. Built-in policies are also available by default:

Authentication strengths policies in Entra ID.
Built-in authentication strengths policies in Entra ID.

One common use case for Authentication Strength policies is to ensure that user accounts with privileged access are protected by requiring phishing-resistant MFA authentication, thus restricting access to authorized users only. In Conditional Access, this goal can be achieved through multiple methods:

  1. Secure Privileged Identity Management role activation with Conditional Access policies (see next point for more details);
  2. Include privileged Entra ID roles in Conditional Access, by selecting directory roles in the policy assignments;
  3. Integrate protected actions into Conditional Access policies to enforce step-up authentication when users perform specific privileged and high-impact actions (see next point for more details).

Other use cases include enforcing stricter authentication requirements when connecting from outside a trusted location, when a user is flagged with a risk in Identity Protection, or when accessing sensitive documents in SharePoint Online.

Finally, as mentioned above, external users (only those authenticating with Microsoft Entra ID, at the time of writing) can be required to satisfy Authentication Strengths policies. The behavior will depend on the status of the cross-tenant access settings, as explained in my previous blog post.

Use Authentication Context to protect specific actions and applications

License requirement: Entra ID Premium P1

Authentication Contexts in Conditional Access allow to extend the locations or actions covered by Conditional Access policies. Indeed, they can be associated with applications, SharePoint Online sites or documents, or even specific privileged and high impact actions in Entra ID.

Before diving into how they can be used, we will quickly go over how they can be created. Authentication Context is a feature of Microsoft Entra Conditional Access and can therefore be managed from the Conditional Access service. Before being able to use them, they need to be created and published to applications:

Add an authentication context in Microsoft Entra Conditional Access.
Add an authentication context in Microsoft Entra Conditional Access.

Once they have been created and published, we can use them in Conditional Access policies. Let’s take a closer look at the different scenarios described above:

  1. Integrate Authentication Contexts in Sensitivity Labels to require step-up authentication or enforce restrictions when accessing sensitive content:

In this first example, the Super-Secret sensitivity label has been configured to require step-up authentication when accessing documents with that label assigned:

Enforce step-up authentication in Sensitivity Labels.
Enforce step-up authentication in Sensitivity Labels.

If we configure the below CA policy with the target resource set to the ‘Sensitive documents’ Authentication Context, users will have to satisfy the phishing-resistant MFA requirements, unless it has already been satisfied, when accessing documents labeled with the Super-Secret label:

Conditional Access policy to require phishing-resistant MFA when accessing sensitive documents (i.e., documents labeled as Super-Secret in our example).
Example: Conditional Access policy to require phishing-resistant MFA when accessing sensitive documents (i.e., documents labeled as Super-Secret in our example).
  • Integrate Authentication Context with Privileged Identity Management roles to enforce additional restrictions on role activation (PIM requires Entra Premium P2 licenses):

Role settings in Entra Privileged Identity Management can be changed to require Authentication Context on role activation. That way, administrators can ensure that high privileged roles are protected against abuse and only available to authorized users themselves:

PIM role setting to require Microsoft Entra Conditional Access authentication context on activation.
PIM role setting to require Microsoft Entra Conditional Access authentication context on activation.

When such control is configured in PIM, users will not be prompted to perform MFA twice if the specified MFA requirement has been previously met during the sign-in process. On the other hand, they will be prompted with MFA if it hasn’t been met before.

Similar to the previous point, the same principle applies to the creation of the Conditional Access policy. The custom PIM Authentication Context should be set as the target resource, and the conditions and access controls configured to meet your security requirements.

Important note: when changing the configuration of high privileged roles, which allow to modify the configuration of Microsoft Entra PIM, make sure you are not locking yourself out of the environment by having at least one active assignment configured.

  • Integrate Entra ID Protected Actions with Conditional Access policies:

Finally, by integrating Entra Identity Protected Actions with Conditional Access, administrators can introduce an extra layer of security when users attempt specific actions, such as modifying Conditional Access policies. Once again, make sure you are not locking yourself out here.

With Protected Actions, you can require strong authentication, enforce a shorter session timeout or filter for specific devices. To create a Protected Action, administrators first need to create an Authentication Context, which will then be assigned to a set of actions in the ‘Entra ID Roles and administrators’-page:

Link protected actions in Entra ID to authentication context.
Link Protected Actions in Entra ID to Authentication Context.

In this example, the ‘Protected Actions’ Authentication Context has been linked to permissions that allow updating, creating, and deleting Entra Conditional Access policies.

Then, in a Conditional Access policy, set the target resource to the ‘Protection Actions’ Authentication Context and define the conditions as well as the access controls.

Once in effect, administrators will be required to meet the configured authentication requirements and/or conditions each time they attempt to modify Conditional Access policies:

Step-up authentication when performing an Entra ID protected actions.
Step-up authentication required when performing an Entra ID protected actions.

Use Device Filters in Conditional Access policies conditions

License requirement: Entra ID Premium P1

Last but not least, the ‘Filter for devices’-condition in Entra Conditional Access is a powerful tool that can be used for multiple purposes. Indeed, by using this condition, it is possible to target specific devices based on their ID, name, Ownership, compliance or join state, model, operating system, custom attributes, etc.

Besides the common scenarios of using the device filter condition to target compliant, non-compliant, registered, or joined devices, it can be used to restrict or block access based on more advanced conditions. For instance, you might require that only devices with certain operating system versions, specific device IDs, or device names that follow a particular pattern are allowed to access specific applications. Custom attributes can also be useful for more granularity, if needed.

The following filter will target devices meeting the following criteria:

  • The display name of the device should contain ‘ADM’;
  • The device should be seen as compliant, in Microsoft Intune, for instance;
  • The device state should be Microsoft Entra joined;
  • And the ExtensionAttribute4 should contain ‘anyvalue’. Extension Attributes for Entra ID registered devices can be added and customized using the Microsoft Graph REST API.
Device filter condition in Entra Conditional Access policies.
Example: Device filter condition in Entra Conditional Access policies.

More information about the different operators and properties can be found in the ‘Resources’-section below.

Bonus: Restrict authentication flows

License requirement: Entra ID Premium P1

The ability to restrict authentication flows in Microsoft Entra Conditional Access, which is still in preview, has been introduced end of February (when I was writing this blog post). I included it to make sure that you are aware of this new feature. However, I do not recommend implementing it in production before it is released in General Availability (at least without proper investigation and testing!).

This functionality has been introduced as a new condition in Microsoft Entra Conditional Access policies and allows to restrict device code flow and authentication transfer.

Firstly, the device code flow has been introduced to facilitate user sign-in on input-constrained devices, referred to as ‘device A.’ With this flow, users can authenticate on ‘device A’ by using a secondary device, referred to as ‘device B.’ They do this by visiting the URL: https://login.microsoftonline.com/common/oauth2/deviceauth. Once the user successfully signs in on ‘device B,’ ‘device A’ will receive the necessary access and refresh tokens.

The flow can be represented as follows:

Device code flow authentication.
Device code flow authentication.

However, this functionality has been, and still is, abused by attackers attempting to trick users into entering the device code and their credentials.

Therefore, Conditional Access policies could now be used to block device code flow, or restrict it to managed devices only. This measure helps ensure that phishing attempts are unlikely to succeed unless the attackers possess a managed device.

Conditional Access policy to block the use of device code flow.
Example: Conditional Access policy to block the use of device code flow.

Moreover, device code flow authentication attempts are visible in the Entra ID Sign-in Logs:

Device code flow authentication attempt.
Device code flow authentication attempt.
Identify device code flow sign-in activities with KQL.
Identify device code flow sign-in activities with KQL.

Secondly, authentication transfer enables users to transfer their authenticated state from one device to another, for instance, by scanning a QR code with their mobile phone from a desktop application. This functionality allows to reduce the number of times users have to authenticate across the different platforms. However, by doing so, users aren’t required to perform MFA again on their mobile phone if they have already performed MFA on their laptop.

Like device code flow authentication, authentication transfer can be blocked using a Conditional Access policy. To do so, simply select ‘Authentication transfer’ under Transfer methods.

Finally, authentication transfer can also be detected in the Entra ID Sign-in logs. Indeed, ‘QR code’ is set as the authentication method in the authentication details.

Evaluate Conditional Access policies

License requirement: Entra ID Premium P1

As a final note, I wanted to highlight the What If tool in Entra Conditional Access. It allows administrators to understand the result of the CA policies in their environment. For that purpose, administrators can select target users, applications, any available conditions, etc., to make sure that existing CA policies have the expected behavior. It also helps troubleshooting the configuration by gaining visibility into the policies that apply to users under specific conditions. The What If tool can be accessed in Entra ID > Conditional Access > Policies:

What if tool in Entra Conditional Access.
What if tool in Entra Conditional Access.

Moreover, the DCToolbox PowerShell module, which is an amazing toolbox for various Microsoft 365 security tasks, developed by Daniel Chronlund, also allows you to evaluate your current Conditional Access policies for a specific scenario. For that purpose, you can use the Invoke-DCConditionalAccessSimulation function and the tool will fetch all existing CA policies and evaluates them against the scenario that you have provided as arguments. You can find the DCToolbox PowerShell module on GitHub here: https://github.com/DanielChronlund/DCToolbox.

I highly recommend using one of these tools to evaluate your newly created or existing Conditional Access policies. Also note that proper testing and validation with different pilot phases and progressive rollouts is essential to avoid impacting end users when creating new policies.

Finally, as a general best practice, Conditional Access policies, and potential exceptions, should be properly documented. For that purpose, the DCToolbox tool allows you to export the current configuration of your Conditional Access policies in an Excel file, for example.

Conclusion

In this second blog post about Entra Conditional Access settings and configurations, we went over important principles that might help you increase the overall security posture of your environment. As for the first part, the settings and configuration items that I have highlighted could be considered when designing or reviewing your Entra Conditional Access implementation. This list is non-exhaustive and has been made based on my experience reviewing and implementing Conditional Access policies in different environments. Also, it is important to rigorously evaluate any policies before rolling them out in production and to make sure that other controls have also been properly configured in your cloud environment. Conditional Access policies are a great way to safeguard your identities and critical resources, but are not the only layer of defense that you should be relying on.

At NVISO, we have built an expertise reviewing cloud environments and have designed and implemented Entra Conditional Access on numerous occasions. If you want to know more about how we can help you in the journey of building or strengthening your Conditional Access setup, among others, feel free to connect on LinkedIn or visit our website at https://www.nviso.eu.

Resources

You can contact me on LinkedIn should you have any questions or remarks. My contact details can be found below.

Additionally, if you want to get a deeper understanding of some of the topics discussed in the blog post, all the resources that I have used can be found below:

About the author

Guillaume Bossiroy

Guillaume Bossiroy

Guillaume is a Senior Security Consultant in the Cloud Security Team. His main focus is on Microsoft Azure and Microsoft 365 security where he has gained extensive knowledge during many engagements, from designing and implementing Entra ID Conditional Access policies to deploying Microsoft 365 Defender security products.

Additionally, Guillaume is also interested into DevSecOps and has obtained the GIAC Cloud Security Automation (GCSA) certification.

Exploiting Reversing (ER) series: article 02 | Windows kernel drivers – part 02

3 January 2024 at 17:10

The second article (85 pages) in the Exploiting Reversing (ER) series, a step-by-step vulnerability research series on Windows, macOS, hypervisors and browsers, is available for reading on:

(PDF): https://exploitreversing.com/wp-content/uploads/2024/05/exploit_reversing_02-2.pdf

Happy New Year with happiness, harmony, peace and health to experience all the good times close to your families and friends.

The best thing about this life are the people.

Have an excellent and keep reversing!

Alexandre Borges

(JANUARY/03/2024)

Most common Active Directory misconfigurations and default settings that put your organization at risk

26 October 2023 at 07:00

Introduction

In this blog post, we will go over the most recurring (and critical) findings that we discovered when auditing the Active Directory environment of different companies, explain why these configurations can be dangerous, how they can be abused by attackers and how they can be mitigated or remediated.

First, let’s start with a small introduction on what Active Directory is.
Active Directory (AD) is a service that allows organizations to manage users, computers and other resources within a network. It centralizes authentication and authorization mechanisms for Windows devices and applications, making it easier for administrators to control access to network resources, enforce security policies, manage device configuration, etc.

Setting up an AD environment can be simple as it can be difficult depending on the organization’s size and requirements. In any case, AD comes with default settings and configurations that can be considered as dangerous and that may not comply with the security policies of your company. Administrators should be aware of these default configurations and take action to secure their environment by implementing best practices and security measures that align with their organization’s needs and risk appetite.

However, it may be difficult to identify these insecure configurations as they are not always well known to administrators. Moreover, new vulnerabilities may be identified later, as in the case of Active Directory Certificate Services (ADCS) where default templates can be abused to escalate privileges.

In the past two years, we reviewed AD environments of about 40 companies. When reviewing these environments, we noticed that some findings were quite recurrent. Some of these misconfigurations (or default settings) can have a significant impact on the security posture of a company and allow attackers to gain access to privileged accounts or to compromise the entire domain.

Let’s look at the 6 most common misconfigurations that could be abused by attackers to gain access to other systems or to compromise the environment.

Misconfigurations

Administrator accounts are allowed for delegation

In Active Directory, accounts can be delegated by default. This means that an application can act on behalf of a user (Kerberos delegation), impersonate a user anywhere within the forest (unconstrained delegation), or only impersonate the user to a specific service on a specific computer (constrained delegation).

If a delegation has been configured and if an attacker has access to the delegated system or account, they could try to impersonate an administrator account and move laterally or compromise the domain.

We found that, in almost all organizations audited, there was at least one privileged account for which the “This account is sensitive and cannot be delegated” setting was not enabled.

To abuse this default configuration, we first need to enumerate delegations. This can be done by using the Active-Directory PowerShell module:

Get-ADUser -LdapFilter "(&(userAccountControl:1.2.840.113556.1.4.803:=16777216)(msDS-AllowedToDelegateTo=*))"
Figure 1: Output of the above "Get-ADUser" command
Figure 1: Output of the above command

Thanks to the above command, we know that a constrained delegation has been configured on the IIS account. We can now check the other properties of the IIS account:

Get-ADUser iis -Properties msDS-AllowedToDelegateTo
Figure 2: Output of the Get-ADUser iis -Properties msDS-AllowedToDelegateTo command
Figure 2: Output of the Get-ADUser iis -Properties msDS-AllowedToDelegateTo command

In this case, we can see that a constrained delegation has been configured on the IIS account to access the CIFS service of the WinServ-2022 server (Figure 2).

If we try to access the server using our low-privileged account, Bob, we get an error (Figure 3). This is expected because our account is not allowed to access this server.

Figure 3: Error message when trying to access the WinServ-2022 server with Bob
Figure 3: Error message when trying to access the WinServ-2022 server with Bob

As the IIS account is a service account, we can try to kerberoast the IIS account using Rubeus, for example (Figure 4). A kerberoast attack is a technique that attempts to retrieve the hash of an Active Directory account that has a Service Principal Name (also known as a service account). Note that in this example, we use the “rc4opsec” argument to only kerberoast service account that supports RC4 encryption, which is the default setting (we will go more in details in the “AES encryption not enforced on service accounts” section).

Figure 4: Kerberoasting of the IIS account
Figure 4: Kerberoasting of the IIS account

In this case, we were able to get the hash of the IIS account and crack the password using “John the Ripper”, which is “Password123”.

Figure 5: Generating the AES256 hash of the password
Figure 5: Generating the AES256 hash of the password

After generating the AES256 representation of the password, we can now use Rubeus to request an HTTP ticket to impersonate the domain administrator and gain access to the WinServ-2022 system. In this example, the HTTP ticket will allow us to run command on the WinServ-2022 server:

Figure 6: Generating an HTTP to impersonate the Administrator of the domain and gain access to WinServ-2022
Figure 6: Generating an HTTP to impersonate the Administrator of the domain and gain access to WinServ-2022

As mentioned before, we are allowed to impersonate the Administrator account because the “This account is sensitive and cannot be delegated” setting is not enforced by default.

After requesting and injecting the ticket that is used to impersonate the Administrator account in memory, we can access WinServ-2022 with the Administrator account:

Figure 7: Accessing WinServ-2022 and running command as the Domain Administrator
Figure 7: Accessing WinServ-2022 and running command as the Domain Administrator

This demonstrates that by compromising a poorly configured service account, any user can gain access to another system with domain administrator privileges. This could have been avoided by enabling the “This account is sensitive and cannot be delegated” setting on privileged accounts (e.g., Domain Admins, etc.), because the Administrator credentials would not be forwarded to another computer for authentication purposes.

The following dsquery command can be used to identify any user where the setting is not enabled:

dsquery * DC=LAB,DC=LOCAL -filter "(&(objectclass=user)(objectcategory=person)(!useraccountcontrol:1.2.840.113556.1.4.803:=1048576))"
Figure 8: Output of the above "dsquery" command
Figure 8: Output of the dsquery command

In this example, if this setting was enabled, the attacker would not have been able to gain access to WinServ-2022 as Administrator:

Figure 9: Enabling the flag for the Administrator account
Figure 9: Enabling the flag for the Administrator account
Figure 10: The attack fails when the flag is enabled
Figure 10: The attack fails when the flag is enabled

Another option is to add the accounts to the Protected Users group. The Protected Users is a group introduced in Windows Server 2012 R2. The goal of this group is to protect administrators against credential theft by not caching credentials in insecure ways. Adding accounts to this group will not only prevent any type of Kerberos delegations, but will also prevent:

  • CredSSO and Wdigest from being used;
  • NTLM authentication;
  • Kerberos from using RC4 or DES keys;
  • Renewal of TGT beyond a 4-hour lifetime.

Microsoft recommends adding a few users to this group first to avoid blocking all administrators in case of a problem. However, it is useless to add computers and service accounts to this group because credentials will always be present on the host machine.

Note that after adding administrators to this group, some organizations have experienced difficulties connecting to servers using RDP (Remote Desktop Protocol). This is because only the Fully Qualified Domain Name (FQDN) is supported when connecting to servers via RDP when the user has been added to the Protected Users group. In fact, when using an IP address to connect to a server with RDP, NTLM authentication is used instead of Kerberos. However, when the FQDN is used, Kerberos authentication will be used.

AES encryption not enforced on service accounts

When a user requests access to a service in Active Directory, a service ticket is created. This service ticket is encrypted using a specific encryption type and sent to the user. The user can then present this encrypted ticket to the server to access the service. There are different encryption types available, such as DES, RC4 and AES. The encryption type is defined by the msDS-SupportedEncryptionTypes attribute. By default, the attribute is not set and the domain controller will encrypt the ticket with RC4 to ensure compatibility. This could allow an attacker to perform a kerberoasting attack, as previously demonstrated.

This means that if AES encryption is not enabled on service accounts and RC4 is not specifically disabled, an attacker could try to request a Kerberos ticket for a specific SPN (Service Principal Name, which is used to associate a service to a specific account) and brute force its password. Then, if someone can retrieve the cleartext password, they will be able to impersonate the account and access all systems/assets to which the service account has access.

If weak encryption types are allowed, an attacker can try to kerberoast a service account without generating too much suspicious activity in the logs, and gain access to other systems within the environment as described above in the “Administrator accounts are allowed for delegation” section.

To identify the value of the msDS-SupportedEncryptionTypes attribute for all service accounts, the following dsquery command can be used:

dsquery * "DC=lab,DC=local" -filter "(&(objectcategory=user)(servicePrincipalName=*))" -attr msDS-SupportedEncryptionTypes samaccountname distinguishedName -limit 0 | FIND /i /v "KRBTGT" | SORT

It is important to note that if the value is blank or equal to 0, it will be interpreted as RC4_HMAC_MD5.

The msDS-SupportedEncryptionTypes attribute on service accounts should be modified to only allow AES instead of legacy protocols such as RC4 or DES. However, for backward compatibility or to validate everything is functional, the value of the attribute can be set to 28. This means that RC4, AES-128, and AES-256 will be allowed. Note that all clients should support AES encryption if systems are not running Windows 2000, Windows XP or Windows Server 2003.

Finally, after making sure everything is working as expected, the value can be modified to 24 to only allow AES-128 and AES-256, as shown on the following screenshot (Figure 11), or to 16 to only allow AES-256.

Figure 11: Output of the above "dsquery" command
Figure 11: Output of the dsquery command

Alternatively, you can edit the options of the account and check the following boxes (Figure 12). This will update the msDS-SupportedEncryptionTypes attribute.

Figure 12: Editing the account options to support Kerberos AES 128 and 256 encryption
Figure 12: Editing the account options to support Kerberos AES 128 and 256 encryption

If the attribute was set to 16 (meaning that only AES-256 is supported), we would not have been able to kerberoast the IIS account using the rc4opsec argument, as shown in Figure 13.

Figure 13: Comparison when the msDS-SupportedEncryptionTypes is set and not set
Figure 13: Comparison when the msDS-SupportedEncryptionTypes is set and not set

Moreover, if the rc4opsec argument is not used and the service account only allows AES encryption types, a 4769 event will be generated on the domain controller with the encryption type used (Figure 14). In this case, the encryption type is 0x12 (DES_CBC_MD5 and AES 256) which is not expected as the attribute is set to 0x10 (only AES-256).

Figure 14: Log showing the encryption type used
Figure 14: Log showing the encryption type used

A Blue team can use these events to identify kerberoasting activities on service accounts.

Finally, deprecated and insecure encryption types can be disabled via a GPO, as follows:

Figure 15: GPO allowing the secure encryption types and disabling the deprecated and insecure ones
Figure 15: GPO allowing the secure encryption types and disabling the deprecated and insecure ones

If an attacker tries to request an RC4 ticket for an account where only AES encryption types are allowed, the kerberoast attack will fail:

Figure 16: Kerberoast attack failing when the account only supports AES encryption types
Figure 16: Kerberoast attack failing when the account only supports AES encryption types

Note that the /usetgtdeleg parameter is used to request RC4 ticket for AES accounts.

Print spooler is enabled on Domain Controllers

According to Microsoft, the print spooler is an executable that manages the printing process by retrieving the location of the correct printer driver, loading the driver, scheduling the print job, etc.

In the past few years, the print spooler service has been affected by several zero-day vulnerabilities (such as PrintNightmare) allowing low privileged users to escalate their privilege, as the service is running with system level privileges. Many exploits are available, but we will not focus on these vulnerabilities.

The print spooler service can also be abused to gain access to the key of the kingdom, the hash of the KRBTGT account. By gaining access to the hash of this account, attackers will be able to forge Golden Tickets, meaning that they will gain almost unlimited access to the Active Directory domain (domain controllers, devices, files, etc.). An attacker can also perform a Skeleton Key attack to create persistence in the domain, as an example. This malware will inject itself inside the LSASS process and create a master password that will work for any account in the domain.

Indeed, when an unconstrained delegation has been configured on a server and when the print spooler service is running on at least one domain controller, it is possible to get the credentials of the domain controller where the service is running.

During our audits, we identified that more than 25% of organizations had configured unconstrained delegation on one or multiple machine accounts. In addition, the print spooler service was running on at least one domain controller in 75% of organizations.

Let’s see how an attacker could abuse these dangerous configurations.

First, we must find where an unconstrained delegation has been configured. This can be done using the Get-DomainComputer command from PowerView as follows:

Figure 17: List of computers where an unconstrained delegation has been configured
Figure 17: List of computers where an unconstrained delegation has been configured

Note that unconstrained delegation is enabled by default and required on domain controllers. In this example, WIN-7I6M16HF63I is the Domain Controller (DC).

We have already compromised the WinServ-2022 server where an unconstrained delegation has been configured. Moreover, the print spooler service is running by default on domain controllers. All the conditions are met to try to retrieve the hash of the KRBTGT account, so let’s give it a try!

We can use Rubeus on WinServ-2022 to extract all Ticket Granting Tickets (TGTs) and display any newly captured TGTs:

Figure 18: Using Rubeus to extract all captured TGTs
Figure 18: Using Rubeus to extract all captured TGTs

On our low privilege machine, we can use MS-RPRN, as an example, to force the domain controller to connect to WinServ-2022.

Figure 19: Forcing the DC to authenticated to WinServ-2022
Figure 19: Forcing the DC to authenticated to WinServ-2022

As expected, we captured a new TGT (Figure 20). The response from the DC contains the domain controller’s computer account Kerberos ticket.

Figure 20: Capturing the TGT from the DC using Rubeus
Figure 20: Capturing the TGT from the DC using Rubeus

We can now import this TGT to impersonate the DC:

Figure 21: Importing the TGT to impersonate the DC
Figure 21: Importing the TGT to impersonate the DC

Once the ticket has been imported, we can perform a DCSync attack using SharpKatz to get the KRBTGT hash.

Figure 22: DCSync attack using SharpKatz
Figure 22: DCSync attack using SharpKatz

We now have the hash of the KRBTGT account (Figure 22), which means that we successfully compromised the domain.

Thanks to the print spooler service running by default on DCs, we were able to trigger the service and make it authenticate to the WinServ-2022 service.

To mitigate this vulnerability, Microsoft recommends disabling the print spooler service on all domain controllers as a security best practice.

One way to identify domain controllers where the print spooler service is running is by using PingCastle, as shown in Figure 23. In this case, only the spooler module was executed and we can see that the service is active on the DC.

Figure 23: PingCastle scan returning all domain controllers where the Print Spooler service is running
Figure 23: PingCastle scan returning all domain controllers where the Print Spooler service is running

As mentioned above, the recommendation is to disable the print spooler service on domain controllers. This can be done using a GPO that will disable the service:

Figure 24: GPO to disable the Print Spooler service
Figure 24: GPO to disable the Print Spooler service

If the print spooler service was disabled, an attacker would not have been able to force the domain controller to connect to WinServ-2022.

Figure 25: Error message when the Print Spooler is disabled
Figure 25: Error message when the Print Spooler is disabled

Users can create machine accounts

First of all, let’s define what a machine account in Active Directory is. A machine account (or computer account) is an Active Directory object that represents a computer or a device connected to the domain. Like user accounts, machine accounts have different attributes that store information about the device, can be a member of security groups, can have Group Policies applied, etc.

By default, in Active Directory, everyone can create up to 10 machine accounts in the domain. This is due to the ms-DS-MachineAccountQuota attribute. According to the Microsoft documentation, this attribute is “the number of computer accounts that a user is allowed to create in the domain”.

This setting is defined in the Default Domain Controllers Policy.

Figure 26: Default value of the "Add workstation to domain" setting in the Default Domain Controllers Policy
Figure 26: Default value of the “Add workstation to domain” setting in the Default Domain Controllers Policy

Moreover, the current value of ms-DS-MachineAccountQuota can be found using this PowerShell command:

Get-ADObject ((Get-ADDomain).distinguishedname) -Properties ms-DS-MachineAccountQuota
Figure 27: Output of the above command
Figure 27: Output of the above command

In this example, the Default Domain Controller Policy Group Policy Object (GPO) and the attribute have not been modified and Authenticated users can create up to 10 computer accounts (Figure 26 and Figure 27).

To create a new machine account, the PowerMad module, written by Kevin Robertson, can be used as follows:

Figure 28: Creation of a new machine account using PowerMad
Figure 28: Creation of a new machine account using PowerMad

As expected, after creating 10 machine accounts, the user will no longer be able to create new machine accounts:

Figure 29: Error message when reaching the MachineAccountQuota limit
Figure 29: Error message when reaching the MachineAccountQuota limit

There is no attribute indicating the number of accounts already created by one specific user. However, the mS-DS-CreatorSID attribute of computer objects is used to determine how many computer accounts have been created by a specific user.

This information can be retrieved by using the Get-MachineAccountCreator command from the PowerMad module:

Figure 30: List of all machines accounts and their creator
Figure 30: List of all machines accounts and their creator

It is also possible to check who created a specific machine account by using the Active Directory PowerShell module:

Get-ADComputer MyComputer -Properties mS-DS-CreatorSID | Select-Object -Expandproperty mS-DS-CreatorSID | Select-Object -ExpandProperty Value | Foreach-Object {Get-ADUser -Filter {SID -eq $_}}
Figure 31: Information about the creator of the "MyComputer" machine account
Figure 31: Information about the creator of the “MyComputer” machine account

The user who created the machine account will be granted write access to different attributes such as msDS-AllowedToActOnBehalfOfOtherIdentity, ServicePrincipalNames, DnsHostName, and so on.

Tools like KrbRelayUp leverage this default setting to escalate privileges to NT\SYSTEM on a local system. An attacker can also change the msDS-AllowedToActOnBehalfOfOtherIdentity to abuse Resource-Based Constrained Delegation, for example.

If a Public Key Infrastructure (PKI) is present in the domain, an attacker can take advantage of the default Machine certificate template to perform a DCSync attack and dump hashes of all users and computers. Let’s take a look at how an attacker can proceed to retrieve the hashes.

After creating a new machine account, an attacker can modify the ServicePrincipalNames and the DnsHostName attributes. First, we remove the service principal names containing the initial DnsHostName and then we set the DnsHostname attribute to the domain controller FQDN, as follows:

Figure 32: Default values of the new machine account attributes
Figure 32: Default values of the new machine account attributes
Figure 33: Modification of the DNSHostName attribute of the machine account to the DC FQDN
Figure 33: Modification of the DNSHostName attribute of the machine account to the DC FQDN

After that, an attacker can request a certificate for the machine account using the Machine template and they will get a certificate for the domain controller. This will allow the attacker to retrieve the NT hash of the domain controller machine account.

Figure 34: Retrieval of the NT hash of the domain controller machine account
Figure 34: Retrieval of the NT hash of the domain controller machine account

The hash can then be used to perform a DCSync attack:

Figure 35: DCsync attack using secretsdump.py
Figure 35: DCsync attack using secretsdump.py

By creating a new computer object, editing its properties and abusing the default Machine template, we were able to dump the hashes of all users. The hashes can then be used to perform a “Pass-the-Hash” attack and move laterally to other systems.

This could have been avoided if some mitigation measures had been put in place.

First, computer objects created using the PowerMad tool will be stored in the Computers container as opposed to other computer objects created by IT administrators. Indeed, they should be put in specific OUs as Group Policies can’t be applied on the container. This can be used to identify any objects created by malicious users.

Moreover, it is recommended to create a new group (or a new account) that will be granted the required permissions to create new machine accounts. This way, only members of this group will be allowed to create new computer objects and malicious users will not be able to perform the attack.

This can be done by modifying the Default Domain Controller Policy. To do so, go to Computer configuration > Policies > Windows Settings > Security Settings > User Right Assignment > Add workstations to domain: Remove the ‘Authenticated Users’ group and add the new group or account previously created.

Authenticated users will no longer be able to create new machine accounts, as shown in Figure 36.

Figure 36: Error message when a user tries to create a new machine account (after removing the permission of the Authenticated Users group)
Figure 36: Error message when a user tries to create a new machine account (after removing the permission of the Authenticated Users group)

Unchanged GPOs are not reprocessed on Domain Controllers

All domain joined systems refresh and apply applicable group policies at specific intervals.

For security policy settings (https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/security-policy-settings), the Group Policy engine works differently and these settings are automatically re-applied every 16 hours even if the GPO has not been changed.

However, by default, most GPO settings are only applied when they are new or when they have been changed since the last time the client requested them. This could allow an attacker to modify a registry key that is normally managed through a GPO to disable specific security measures, for example.

In the following example, a company enforces the Windows Defender Real-Time Protection through a GPO:

Figure 37: GPO to enable Windows Defender Real-Time Protection
Figure 37: GPO to enable Windows Defender Real-Time Protection

If a user tries to download malicious files, Windows Defender will immediately quarantine the files:

Figure 38: Windows Defender alert when downloading a malicious file
Figure 38: Windows Defender alert when downloading a malicious file

If a user can modify the Windows Defender Real-Time Protection registry key, they will be able to download and run malicious tools on the system. In this case, by setting the value to 1, the user disables the Real-Time Protection feature:

Figure 39: Modification of the DisableRealtimeMonitoring registry key
Figure 39: Modification of the DisableRealtimeMonitoring registry key

As expected, the Real-Time Protection is now disabled and the user can download malicious files:

Figure 40: Comparison when downloading a malicious file with Real-Time Protection enabled and disabled
Figure 40: Comparison when downloading a malicious file with Real-Time Protection enabled and disabled

To mitigate this vulnerability, it is recommended to ensure that registry and security policy settings defined in GPOs are always enforced and re-applied on systems even if the GPO has not changed. This way, any unauthorized changes made locally will be overridden after 5 minutes to 16 hours.

In the Default Domain Controller policy, under Computer Configuration > Administrative Templates > System > Group Policy, configure the following two settings as follows:

  1. Configure security policy processing:
    • Process even if the Group Policy objects have not changed: Enabled
    • Do not apply during periodic background processing: Disabled
  2. Configure registry policy processing:
    • Process even if the Group Policy objects have not changed: Enabled
    • Do not apply during periodic background processing: Disabled

The following settings can also be re-applied even if they have not been changed:

  • Internet Explorer Maintenance
  • IP Security
  • Recovery Policy
  • Wireless Policy
  • Disk Quota
  • Scripts
  • Folder Redirection
  • Software Installation
  • Wired Policy

Moreover, enabling auditing for registry operations can help your organization identify suspicious changes.

To audit registry key modification, the “Audit object access” policy needs to be enabled using a GPO (Figure 41).

Figure 41: GPO for auditing registry key modifications
Figure 41: GPO for auditing registry key modifications

After that, auditing also needs to be enabled on the registry keys that you want to monitor (Figure 42).

Figure 42: Enable auditing on the registry keys in Regedit
Figure 42: Enable auditing on the registry keys in Regedit

In this case, each time the value of a registry key under Windows Defender is modified, an event will be generated in the Event Viewer and can be used by the Blue team to identify suspicious activities.

Modification to registry keys can now be detected by looking at different event IDs (4656, 4657, 4660 and 4663).

In our example, we can see that the value of the DisableRealTimeMonitoring registry key was changed to 1 instead of 0:

Figure 43: Log showing that the value of the registry key has been modified
Figure 43: Log showing that the value of the registry key has been modified

Password policy and least privilege

This section includes recommendations related to the password policy of service accounts and the KRBTGT account.

The recommendations included in this section should be adapted to your company policy, specific use cases and risk tolerance.

Service accounts

During the audits, we noticed that most of the time, there is no password policy for service accounts, allowing administrators to set weak passwords that can be easily brute forced. In a few cases, the password for service accounts was even included in their description.

As shown in the “Administrator accounts are allowed for delegation” section, we cracked the IIS account password because weak passwords are allowed as there is no password policy enforced for service accounts. This could have been prevented by configuring a proper password policy.

For example, Microsoft recommends using passwords of at least 25 characters for service accounts and implementing a process for changing them regularly. Moreover, it is also recommended to use a dedicated Organizational Unit to manage this kind of accounts, making it easier to administrators to manage security settings applied to these accounts.

Finally, we also noticed that some organizations tend to use personal administrator accounts as service accounts. This means that if someone achieves to compromise a service account used by an administrator, they will have all privileges associated to this account. As a best practice, service accounts should only be granted the permissions they need.

KRBTGT account

The KRBTGT account is a default account that exists in all Active Directory domains. Its main purpose is to act as the Key Distribution Center (KDC) service account, which handles all Kerberos requests in the domain. As mentioned above, if an attacker achieves to compromise this account, they will be able to forge Golden Tickets and gain access to domain resources.

We noticed that many organizations do not change the KRBTGT password on a regular basis. Based on 25 audits, we found that the KRBTGT password is changed every 1855 days on average, and two organizations did not change the password for more than 5500 days, that’s over 15 years!

This means that an attacker, who was able to compromise the KRBTGT hash and has not been detected yet, can maintain his access for 5 years on average (if they have not created a backdoor yet).

It is recommended to change the password of the KRBTGT account regularly, for example every 6 months or every year.

Note that the password must be changed twice because the password history value for this account is set to 2. This means that the two most recent passwords will be valid for all already existing tickets. Before changing the password for the second time, best practices recommend waiting at least 24 hours to avoid invalidating existing Kerberos tickets and requiring everyone and everything (computers, servers, service accounts, etc.) to re-authenticate.

However, if you suspect that the KRBTGT account has been compromised by an attacker, the password should also be reset. This will prevent anyone who has access to its hash from generating Golden Tickets, for example.

It is important to keep in mind that changing the KRBTGT password will not ensure the security of your organization. If someone managed to get its hash once, they will probably be able to compromise it a second time if no other security measures are implemented.

Conclusion

In this blog post, we went over the most common misconfigurations and default settings discovered when doing Active Directory assessments of different environments. These configurations can have a significant impact on the security of your organization and allow attackers to gain access to the key of your kingdom.

Therefore, it is important to know your environment. Moreover, there should be a security baseline which should always be followed and reviewed regularly.

  • Is this configuration still required?
  • Is there any potential risk, any new vulnerabilities associated to this service?
  • Is there a more secure approach?

These are some of the questions IT administrators must repeatedly ask themselves to maintain a certain security posture.

Moreover, some tools allow you to perform automatic auditing of your AD environment and identify settings that could put your organization at risk:

  • PingCastle: It scans your environment to identify security vulnerabilities and weaknesses. It includes checks for stale objects (legacy protocols, never expiring password, etc.), privileges accounts (Kerberoastable admin accounts, delegations, etc.) and anomalies (print spooler, ADCS, audit policy, etc.).
  • BloodHound: It allows you to visualize Active Directory attack paths. It can be used to identify potential security vulnerabilities that could be exploited by an attacker with Domain Users privileges to elevate their privileges to Domain Admins, as an example.
  • Testimo: It is a PowerShell Module created by EvotecIT that helps you identify security issues as well as other operational issues. It can also generate HTML reports showing the commands executed, their output, a description and links to external resources.

While PingCastle and Testimo are more defender oriented, BloodHound is more attacker oriented.

In addition to performing regular scans, IT administrators should always keep an eye on newly discovered vulnerabilities, as a configuration that is considered safe can be the cause of a disaster a few years later. Indeed, it is important to note that no tool can guarantee complete security for your AD environment.

NVISO can help you identify and remediate vulnerabilities and weaknesses in your environment by performing an adversary emulation assessment which simulate real-world threats, as an example. These assessments will help you improve your security posture and protect your organization from potential threats.

To learn more about how we can help you, feel free to reach out or to check our website.

Bastien Bossiroy

Bastien Bossiroy

Bastien is a Senior Security Consultant at NVISO where he is part of the Software Security and Assessment team. He focuses mainly on web applications testing and Active Directory environments auditing.

During his free time, Bastien enjoys testing different Active Directory configurations to understand how they work and how specific settings or misconfigurations can impact the security of the environment.

Preventing Type Confusion with CastGuard

18 October 2023 at 08:00

Built into the Microsoft C++ compiler and runtime, CastGuard is a pivotal security enhancement designed to significantly reduce the number of exploitable Type Confusion vulnerabilities in applications. Joe Bialek gave a talk about CastGuard at BHUSA2022 (slides) that explains the overall goals of the feature, how it was developed, and how it works at a high level. This article offers a journey into my discovery CastGuard – delving into a technical evaluation of its mechanics, exploring illustrative examples, and highlighting relevant compiler flags.

While looking into new control flow guard feature support in the Windows PE load config directory a while back, I stumbled across a newly added field called CastGuardOsDeterminedFailureMode, added in Windows 21H2. I had never heard of CastGuard before so, naturally, I wondered what it did.

To give a brief overview, CastGuard is intended to solve Type Confusion problems such as the following:

struct Organism {
    virtual void Speak() { cout << "..."; }
}

struct Animal : public Organism {
    virtual void Speak() { cout << "Uh... hi?"; }
}

struct Dog : public Animal {
    virtual void Speak() { cout << "Woof!"; }
}

struct Cat : public Animal {
    virtual void Speak() { cout << "Meow!"; }
}

void SayMeow(Animal* animal) {
    static_cast<Cat*>(animal)->Speak();
}

Animal* dog = new Dog();
SayMeow(dog);

In this application, SayMeow will print “Woof!”, in a classic example of type confusion through an illegal downcast. The compiler is unable to infer that the Dog type being passed to SayMeow is a problem, because the function takes an Animal type, so no contract is broken there. The cast within SayMeow is also valid from the compiler’s perspective, because a Cat is an Animal, so it is entirely valid to downcast if you, the developer who wrote the code, know that the object being passed is in fact a Cat or a descendent type thereof. This is why this bug class is so pernicious – it’s easy to violate the type contract, especially in complex codebases.

Ordinarily this can be solved with dynamic_cast and RTTI, which tags each object with type information, but this has its own problems (see the talk linked above for full details) and it’s non-trivial to replace static_cast with dynamic_cast across a large codebase, especially in the case where your code has to coexist with 3rd party / user code (e.g. in the case of runtime libraries) where you can’t even enforce that RTTI is enabled. Furthermore, RTTI causes significant codegen bloat and performance penalties – a static cast is free (you’re interpreting the memory natively as if it were the type being cast to) whereas a dynamic cast with RTTI requires a handful of stores, loads, jumps, and calls on every cast.

CastGuard acts as an additional layer of protection against type confusion, or, more specifically, against cases where type confusion is the first-order memory vulnerability; it is not designed to protect against cases where an additional memory corruption issue is leveraged first. Its goal is to offer this protection with minimal codegen bloat and performance overhead, without modifying the (near-universally relied upon) ABI for C++ objects.

CastGuard leverages the fact that vftables (aka vtables) uniquely identify types. As long as the types on the left- and right-hand side of the cast have at least one vftable, and both types were declared within the binary being complied, the object types can be consistently and uniquely determined by their vftable address (with one caveat: comdat folding for identical vftables must be disabled in the linker). This allows the vftable pointer to be used as a unique type identifier on each object, avoiding the need for RTTI bloat and expensive runtime checks. Since an object’s vftable pointer is almost certainly being accessed around the same time as any cast involving that object, the memory being accessed is probably already in cache (or is otherwise about to benefit from being cached) so the performance impact of accessing that data is negligible.

Initially, Microsoft explored the idea of creating bitmaps that describe which types’ vftables are compatible with each other, so that each type that was observed to be down-cast to had a bitvector that described which of the other vftables were valid for casting. However, this turns out to be inefficient in a bunch of ways, and they came up with a much more elegant solution.

The type vftables are enumerated during link time code generation (LTCG). A type inheritance hierarchy is produced, and that hierarchy is flattened into a top-down depth-first list of vftables. These are stored contiguously in memory.

To use the above code as an example, if we assume that each vftable is 8 bytes in size, the CastGuard section would end up looking like this:

Offset Name
0x00 __CastGuardVftableStart
0x08 Organism::$vftable@
0x10 Animal::$vftable@
0x18 Dog::$vftable@
0x20 Cat::$vftable@
0x28 __CastGuardVftableEnd

Notice that parent types are always before child types in the table. Siblings can be in any order, but a sibling’s descendants would come immediately after it. For example, if we added a WolfHound class that inherited from Dog, its vftable would appear between Dog::$vftable@ and Cat::$vftable@ in the above table.

At any given static_cast<T> site the compiler knows how many other types inherit from T. Given that child types appear sequentially after the parent type in the CastGuard section, the compiler knows that there are a certain number of child type vftables appearing immediately afterward.

For example, Animal has two child types – Cat and Dog – and both of these types are allowed to be cast to Animal. So, if you do static_cast<Animal>(foo), CastGuard checks to see if foo’s vftable pointer lands within two vftable slots downward of Animal::$vftable@, which in this case would be any offset between 0x10 and 0x20 inclusively, i.e. the vftables of Animal, Dog, and Cat. These are all valid. If you try to cast an Organism object to the Animal type, CastGuard’s check detects this as being invalid because the Organism object vftable pointer is to offset 0x08, which is outside the valid range.

Looking back again at the example code, the cast being done is static_cast<Cat> on a Dog object. The Cat type has no descendants, so the range size of valid vftables is zero. The Cat type’s vftable, Cat::$vftable@, is at offset 0x20, whereas the Dog object vftable pointer points to offset 0x18, so it therefore fails the CastGuard range check. Casting a Cat object to the Cat type works, on the other hand, because a Cat object’s vftable pointer points to  0x20, which is within a 0 byte range of Cat::$vftable@.

This check is optimised even further by computing the valid range size at compile time, instead of storing the count of descendent types and multiplying that by the CastGuard vftable alignment size on every check. At each static cast site, the compiler simply subtracts the left-hand side type’s vftable address from the right-hand side object’s vftable pointer, and checks to see if it is less than or equal to the valid range. This not only reduces the computational complexity of each check, but it also means that the alignment of vftables within the CastGuard section can be arbitrarily decided by the linker on a per-build basis, based on the maximum vftable size being stored, without needing to include any additional metadata or codegen. In fact, the vftables don’t even need to be padded to all have the same alignment, as long as the compiler computes the valid range based on the sum of the vftable sizes of the child types.

I mentioned earlier that CastGuard only protects casts for types within the same binary. The CastGuard range check described above will always fail if a type from another binary is cast to a type from the current binary, because the vftable pointers will be out of range. This is obviously unacceptable – it’d break almost every program that uses types from a DLL – so CastGuard includes an extra compatibility check. This is where the __CastGuardVftableStart and __CastGuardVftableEnd symbols come in. If the vftable for an object being cast lands outside of the CastGuard section range, the check fails open and allows the cast because it is outside the scope of protection offered by the CastGuard feature.

This approach is much faster than dynamic casting with RTTI and adds very little extra bloat in the compiled binary (caveat: see the talk for details on where they had to optimise this a bit further for things like CRTP). As such, CastGuard is suitable to be enabled everywhere, including in performance-critical paths where dynamic casting would be far too expensive.

Pretty cool, right? I thought so too.

Let’s now go back to the original reason for me discovering CastGuard in the first place: the CastGuardOsDeterminedFailureMode field that was added to the PE load config structure in 21H2. It’s pretty clear that this field has something to do with CastGuard (the name rather gives it away) but it isn’t clear what the field actually does.

My first approach to figure this out was to enumerate every single PE file on my computer (and a Windows 11 Pro VM), parse it, and look for nonzero values in the CastGuardOsDeterminedFailureMode field. I found a bunch! This field is documented as containing a virtual address (VA). I wrote some code to parse out the CastGuardOsDeterminedFailureMode field from the load config, attempt to resolve the VA to an offset, then read the data at that offset.

I found three overall classes of PE file through this scan method:

  • PE files where the CastGuardOsDeterminedFailureMode field is zero.
  • PE files where the CastGuardOsDeterminedFailureMode field contains a valid VA which points to eight zero bytes in the .rdata section.
  • PE files where the CastGuardOsDeterminedFailureMode field contains what looks like a valid VA, but is in fact an invalid VA.

The third type of result is a bit confusing. The VA looks valid at first glance – it starts with the same few nibbles as other valid VAs – but it doesn’t point within any of the sections. At first I thought my VA translation code was broken, but I confirmed that the VAs were indeed invalid when translated by other tools such as CFF Explorer and PE-Bear. We’ll come back to this later.

I loaded a few of the binaries with valid VAs into Ghidra and applied debugging symbols. I found that these binaries contained a symbol named __castguard_check_failure_os_handled_fptr in the .rdata section, and that the CastGuardOsDeterminedFailureMode VA pointed to the address of this symbol. I additionally found that the binaries included a fast-fail code called FAST_FAIL_CAST_GUARD (65) which is used when the process fast-fails due to a CastGuard range check failure. However, I couldn’t find the __CastGuardVftableStart or __CastGuardVftableEnd symbols for the CastGuard vftable region that had been mentioned in Joe’s talk.

Searching for these symbol names online led me to pieces of vcruntime source code included in SDKs as part of Visual Studio. The relevant source file is guard_support.c and it can be found in the following path:

[VisualStudio]/VC/Tools/MSVC/[version]/crt/src/vcruntime/guard_support.c

It appears that the CastGuard feature was added somewhere around version 14.28.29333, and minor changes have been made in later versions.

Comments in this file explain how the table alignment works. As of 14.34.31933, the start of the CastGuard section is aligned to a size of 16*sizeof(void*), i.e. 128-byte aligned on 64-bit platforms and 64-byte aligned on 32-bit platforms.

There are three parts to the table, and they are allocated as .rdata subsections: .rdata$CastGuardVftablesA, .rdata$CastGuardVftablesB, and .rdata$CastGuardVftablesC.

Parts A and C store the __CastGuardVftablesStart and __CastGuardVftablesEnd symbols. Both of these are defined as a CastGuardVftables struct type that contains a padding field of the alignment size. This means that the first vftable in the CastGuard section is placed at __CastGuardVftablesStart + sizeof(struct CastGuardVftables).

Part B is generated automatically by the compiler. It contains the vftables, and these are automatically aligned to whatever size makes sense during compilation. If no vftables are generated, part B is essentially missing, and you end up with __CastGuardVftablesEnd placed 64/128 bytes after __CastGuardVftablesStart.

The guard_support.c code does not contain the CastGuard checks themselves; these are emitted as part of the compiler itself rather than being represented in a public source file. However, guard_support.c does contain the failure routines and the AppCompat check routine.

When a CastGuard check at a static_cast site fails, it calls into one of four failure routines:

  1. __castguard_check_failure_nop – does nothing.
  2. __castguard_check_failure_debugbreak – raises a breakpoint by calling __debugbreak()
  3. __castguard_check_failure_fastfail – fast-fails using __fastfail(FAST_FAIL_CAST_GUARD)
  4. __castguard_check_failure_os_handled – calls an OS handler function

Rather than calling the AppCompat check routine at every static_cast site, the check is instead deferred until a CastGuard check fails. Each of the check failure routines above, with the exception of nop, first calls into the AppCompat check routine to see if the failure should be ignored.

The AppCompat check routine is implemented in __castguard_compat_check, and it looks like this:

static
inline
BOOL
__cdecl __castguard_compat_check(PVOID rhsVftablePtr)
{
    ULONG_PTR realVftableRangeStart = (ULONG_PTR)&__CastGuardVftablesStart + sizeof(struct CastGuardVftables);
    ULONG_PTR realVftableRangeEnd = (ULONG_PTR)&__CastGuardVftablesEnd;
    ULONG_PTR vftableRangeSize = realVftableRangeEnd - realVftableRangeStart;

    return (ULONG_PTR)rhsVftablePtr - realVftableRangeStart <= vftableRangeSize;
}

This routine is responsible for checking whether the right-hand side (object being cast) vftable pointer is pointing somewhere between the first vftable in the CastGuard section and __CastGuardVftablesEnd. If it is, the AppCompat check returns true (i.e. this is a valid case that CastGuard should protect against), otherwise it returns false.

In the case of __castguard_check_failure_os_handled, the handler code looks like this:

extern
inline
void __cdecl __castguard_check_failure_os_handled(PVOID rhsVftablePtr)
{
    if (__castguard_compat_check(rhsVftablePtr))
    {
        __castguard_check_failure_os_handled_wrapper(rhsVftablePtr);
    }

    return;
}

If the AppCompat routine says that the failed check should be honoured, it calls an OS handler wrapper. The wrapper function looks like this:

static inline void
__declspec(guard(nocf))
__cdecl __castguard_check_failure_os_handled_wrapper(PVOID rhsVftablePtr)
{
    // This function is opted out of CFG because the OS handled function pointer
    // is allocated within ".00cfg" section. This section benefits from the same
    // level of protection as a CFG pointer would.

    if (__castguard_check_failure_os_handled_fptr != NULL)
    {
        __castguard_check_failure_os_handled_fptr(rhsVftablePtr);
    }
    return;
}

The __castguard_check_failure_os_handled_fptr function pointer being referred to here is the symbol that CastGuardOsDeterminedFailureMode points to in the load config table – the exact one I was trying to figure out the purpose of!

That function pointer is defined as:

__declspec(allocate(".00cfg"))
DECLSPEC_SELECTANY
VOID (* volatile __castguard_check_failure_os_handled_fptr)(PVOID rhsVftablePtr) = NULL;

The declspec is important here – it places __castguard_check_failure_os_handled_fptr in the same section as CFG/XFG pointers, which means (as the code comment above points out) that the OS handler function pointer is protected in the same way as the CFG/XFG pointers. Control flow from the CastGuard check site to the check failure function to the AppCompat check function can be protected by control flow guard, but flow from the failure routine to the OS handled function pointer cannot because its value is (presumably always) unknown at compile time. This is why the wrapper function above is required, with guard(nocf) applied – it disables CFG for the flow from the check failure function to the OS handler function, since CFG would likely disallow the indirect call, but since the pointer itself is protected it doesn’t actually matter.

This indicates that CastGuardOsDeterminedFailureMode is intended to be used to specify the location of the __castguard_check_failure_os_handled_fptr symbol, which in turn points to an OS handler function that is called when a check failure occurs.

None of this is documented but, given that Joe’s BHUSA2022 talk included an anecdote about Microsoft starting the CastGuard feature off in a report-only mode, I can only presume that CastGuardOsDeterminedFailureMode was designed to provide the binaries with this reporting feature.

At this point we still have a couple of open questions, though. First, how does the compiler pick between the four different failure handlers? Second, how are the CastGuard checks themselves implemented? And third, why do a lot of the binaries have invalid VAs in CastGuardOsDeterminedFailureMode?

To answer the first question, we have to take a look at c2.dll in the MSVC compiler, which is where CastGuard is implemented under the hood. This DLL contains a class called CastGuard which, unsurprisingly, is responsible for most of the heavy lifting. One of the functions in this class, called InsertCastGuardCompatCheck, refers to a field of some unknown object in thread-local storage and picks which of the four check functions to insert a call to based on that value:

Value Call
1 __castguard_check_failure_fastfail
2 __castguard_check_failure_debugbreak
3 __castguard_check_failure_os_handled
4 __castguard_check_failure_nop

From prior reverse engineering expeditions into the MSVC compiler, I remembered that config flags passed to the compiler are typically stored in a big structure in TLS. From there I was able to find the hidden compiler flags that enable CastGuard and control its behaviour.

Hidden flags can be passed to each stage of the compiler using a special /d command line argument. The format of the argument is /dN… where N specifies which DLL the hidden flag should be passed to (1 for the front-end compiler, c1.dll, or 2 for the code generator, c2.dll). The flag is then appended to the argument.

The known hidden compiler flags for CastGuard are:

Flag Description
/d2CastGuard- Disables CastGuard.
/d2CastGuard Enables CastGuard.
/d2CastGuardFailureMode:fastfail Sets the failure mode to fast-fail.
/d2CastGuardFailureMode:nop Sets the failure mode to nop.
/d2CastGuardFailureMode:os_handled Sets the failure mode to OS handled.
/d2CastGuardFailureMode:debugbreak Sets the failure mode to debug break.
/d2CastGuardOption:dump_layout_info Dumps the CastGuard layout info in the build output.
/d2CastGuardOption:force_type_system Forces type system analysis, even if the binary is too big for fast analysis.
This is intended to be used with the linker, rather than the compiler, so warning C5066 is raised if you pass it.
/d2CastGuardTestFlags:# Sets various test flags for the CastGuard implementation, as a bitwise numeric value. Hex numbers are valid.

So now we know how the different failure modes are set: at build time, with a compiler flag.

If we rebuild the example code with some extra compiler flags, we can try CastGuard out:

/d2CastGuard /d2CastGuardFailureMode:debugbreak /d2CastGuardOption:dump_layout_info

The compiler then prints layout information for CastGuard:

1>***** CastGuard Region ******
1>Offset:0x00000 RTTIBias:0x8 Size:0x010 Alignment:0x08 VftableName:??_7Dog@@6B@
1>
1>
1>***** CastGuard Compatibility Info ******
1>

When executed, the static cast in SayMeow has a CastGuard check applied and raises a debug break in __castguard_check_failure_debugbreak.

We can also learn a little more about CastGuard from the warnings and errors that are known to be associated with it, by looking at the string tables in the compiler binaries:

  • C5064: “CastGuard has been disabled because the binary is too big for fast type system analysis and compiler throughput will be degraded. To override this behavior and force enable the type system so CastGuard can be used, specify the flag /d2:-CastGuardOption:force_type_system to the linker.”
  • C5065: “The CastGuard subsystem could not be enabled.”
  • C5066: “CastGuardOption:force_type_system should not be passed to the compiler, it should only be passed to the linker via /d2:-CastGuardOption:force_type_system. Passing this flag to the compiler directly will force the type system for all binaries this ltcg module is linked in to.”
  • C5067: “CastGuard is not compatible with d2notypeopt”
  • C5068: “CastGuard is not compatible with incremental linking”
  • C5069: “CastGuard cannot initialize the type system. An object is being used that was built with a compiler that did not include the necessary vftable type information (I_VFTABLETIS) which prevents the type system from loading. Object: %s”
  • C5070: “CastGuard cannot initialize the type system. An object is being used that was built with a compiler that did not include the necessary type information (I_TIS) which prevents the type system from loading. Object: %s”
  • C5071: “CastGuard cannot initialize the type system. An error occurred while trying to read the type information from the debug il. Object: %s”

Digging even further into the implementation, it appears that Microsoft added a new C++ attribute called nocastguard, which can be used to exclude a type from CastGuard checks. Based on my experimentation, this attribute is applied to types (applying the attribute to an argument or variable causes a compiler crash!) and disables checks when a static cast is performed to that type.

Changing our example code to the following causes the CastGuard check to be eliminated, and the type confusion bug returns:

struct [[msvc::nocastguard]] Cat : Animal {
    virtual void Speak() { std::cout << "Meow!\n"; }
};

If nocastguard is applied to the Dog or Animal type instead, the CastGuard check returns and the type confusion bug is prevented. This indicates that, at least in this unreleased implementation, the attribute is specifically used to prevent CastGuard checks on casts to the target type.

This newly CastGuard-enabled development environment makes it easy to experiment and disassemble the binary and see what the code looks like. In the simplest version of our example program, the result is actually quite amusing: the program does nothing except initialise a Dog object and immediately unconditionally call the failure routine in main. This is because the CastGuard check is injected into the IL during the optimisation phase. You can see this in practice: turning off optimisations causes the CastGuard pass to be skipped entirely. Since the check is part of the IL, it is subject to optimisation passes. The optimiser sees that the check essentially boils down to if (Cat::$vftable@ != Dog::$vftable@) { fail; }, whose expression is always true, which results in the branch being taken and the entire rest of the code being eliminated. Since SayMeow is only called once, it gets inlined, and the entire program ends up as a call to the CastGuard failure routine. This implies that it could technically be possible for a future release to identify such a scenario at build time and raise an error or warning.

To study things a little better, let’s expand the program in a way that introduces uncertainty and tricks the compiler into not optimising the routines. (Note: we can’t turn off optimisations to avoid all the inlining and elimination because that also turns off CastGuard.)

int main()
{
    for (int i = 0; i < 20; i++)
    {
        int idx = rand() % 3;
        Animal* animal = nullptr;
        switch (idx)
        {
        case 0:
            std::cout << "Making an animal...\n";
            animal = new Animal();
            break;
        case 1:
            std::cout << "Making a dog...\n";
            animal = new Dog();
            break;
        default:
            std::cout << "Making a cat...\n";
            animal = new Cat();
            break;
        }
        SayMeow(animal);
    }
}

This results in a program with an entirely normal looking main function, with no references to CastGuard routines. SayMeow looks like the following:

void SayMeow(Animal *animal)
{
    if (animal != nullptr && *animal != Cat::$vftable@)
    {
        __castguard_check_failure_debugbreak((void*)*animal);
    }
    animal->Speak();
}

This is pretty much expected: *animal dereferences the passed pointer to get to the vftable for the object, and, since the Cat type has no descendent types, the range check just turns into a straight equality check.

To make things more interesting, let’s add a WolfHound type that inherits from Dog, and a function called SayWoof that works just like SayMeow but with a cast to Dog instead of Cat. We’ll also update main so that it can create an Animal, Cat, Dog, or WolfHound.

Upon building this new program, the compiler dumps the CastGuard layout:

***** CastGuard Region ******
Offset:0x00000 RTTIBias:0x8 Size:0x010 Alignment:0x08 VftableName:??_7Animal@@6B@
Offset:0x00010 RTTIBias:0x8 Size:0x010 Alignment:0x08 VftableName:??_7Dog@@6B@
Offset:0x00020 RTTIBias:0x8 Size:0x010 Alignment:0x08 VftableName:??_7WolfHound@@6B@
Offset:0x00030 RTTIBias:0x8 Size:0x010 Alignment:0x08 VftableName:??_7Cat@@6B@

***** CastGuard Compatibility Info ******
Vftable:??_7Dog@@6B@ RangeCheck ComparisonBaseVftable:??_7Dog@@6B@ Size:0x10 ObjectCreated
    CompatibleVftable: Offset:0x00010 RTTIBias:0x8 Vftable:??_7Dog@@6B@
    CompatibleVftable: Offset:0x00020 RTTIBias:0x8 Vftable:??_7WolfHound@@6B@

We can see that the WolfHound vftable is placed immediately after the Dog vftable, and that the Dog type is compatible with the Dog and WolfHound types. We can also see that the size of the range check is 0x10, which makes sense because WolfHound‘s vftable comes 0x10 bytes after Dog‘s vftable.

The CastGuard check in SayWoof now ends up looking something like this:

void SayWoof(Animal* animal)
{
    if (animal != nullptr)
    {
        if (*animal - Dog::$vftable@ > 0x10)
        {
            __castguard_check_failure_debugbreak((void*)*animal);
        }
    }
    animal->Speak();
}

Let’s enumerate the possible flows here:

  • If the type being passed is Dog, then *animal is equal to Dog::$vftable@, which makes *animal - Dog::$vftable@ equal zero, so the check passes.
  • If the type being passed is WolfHound, then *animal is equal to WolfHound::$vftable@, which is positioned 0x10 bytes before Dog::$vftable@. As such, *animal - Dog::$vftable@ will equal 0x10, and the check passes.
  • If the type being passed is Cat, then *animal is equal to Cat::$vftable@, which makes *animal - Dog::$vftable@ equal 0x20, and the check fails.
  • If the type being passed is Animal, then *animal is equal to Animal::$vftable@. Since Animal::$vftable@ is positioned before Dog::$vftable@ in the table, the result of the unsigned subtraction will wrap, causing the result to be greater than 0x10, and the check fails.

This shows CastGuard in action quite nicely!

For completeness, let’s go back and wrap up a small loose end relating to the hidden compiler flags: test flags. The /d2CastGuardTestFlags option takes a hexadecimal number value representing a set of bitwise flags. The test flags value is written to a symbol called CastGuardTestFlags inside c2.dll, and this value is used in roughly ten different locations in the code as of version 14.34.31933.

In the process of reverse engineering this code, I discovered that four separate check approaches are implemented – RangeCheck (0x01, the default), ROLCheck (0x02), ConstantBitmapCheck (0x03), and BitmapCheck (0x04) – presumably following the sequence of approaches and optimisations that were mentioned in the talk.

Here’s what I was able to figure out about these flags:

Flag Value Notes
0x01 Switches the check type to ROLCheck (0x02), as long as neither 0x02 nor 0x40 are also set.
0x02 Switches the check type to ConstantBitmapCheck (0x03), as long as 0x40 is not also set.
0x04 Appears to enable an alternative strategy for selecting the most appropriate vftable for a type with multiple inheritance.
0x08 Forces CastGuard::IsCastGuardCheckNeeded to default to true instead of false when no condition explicitly prevents a check, which appears to force the generation of CastGuard checks even if a codegen pass was not performed.
0x10 Forces generation of metadata for all types in the inheritance tree. Types that are never part of a cast check, either as a cast target or valid source type, do not normally end up as part of the CastGuard section. For example, Organism is ignored by CastGuard in our example programs because it never ends up being relevant at a static cast site. When this flag is enabled, all types in the inheritance tree are treated as relevant, and their vftables are placed into the CastGuard section. A type which is never part of a static cast, and whose parent and child types (if there are any) are never part of a static cast, are still kept separate and don’t end up in the CastGuard section.
0x20 Exact behaviour is unclear, but it seems to force the CastGuard subsystem to be enabled in a situation where error C5065 would be otherwise raised, and forces the TypeSystem::Builder::ProcessILRecord function to continue working even if an internal boolean named OneModuleEnablesCastGuard is false.
0x40 Switches the check type to BitmapCheck (0x04) and, if /d2CastGuardOption:dump_layout_info is also set, prints the bitmap in the build output.

The three alternative check patterns function exactly as was explained in the BHUSA2022 talk, so I won’t go into them any further.

Unless I missed anything, we appear to be down to just one final question: why am I seeing invalid VAs in CastGuardOsDeterminedFailureMode on a bunch of Windows executables?

At first I thought that there might be some kind of masking going on, with certain bits guaranteed to be zero in the VA due to alignment requirements, with those bit positions being reused to set or indicate the failure mode or check type. This doesn’t make much sense, though, and I can find no supporting evidence. It appears that this is a bug from an earlier implementation of CastGuard, when Microsoft were trialling rolling out notify-only protection on certain components. I couldn’t concretely confirm this theory, but I did manage to have a quick chat with someone who worked on the feature, and they were as surprised to see the invalid VAs as I was.

It takes time to get these compiler-level bug class mitigations implemented correctly. The analysis in this article was originally performed in February 2023, but CastGuard remains unofficial and undocumented as of October 2023. Given the unfathomable quantity of existing code that interacts with COM interfaces, all of which might be affected by this feature, and the politically fractious intersection between C++ language standards and implementation-specific language features, it isn’t particularly surprising that it’s taking Microsoft a while to roll this mitigation out.

The post Preventing Type Confusion with CastGuard appeared first on LRQA Nettitude Labs.

Enforce Zero Trust in Microsoft 365 – Part 3: Introduction to Conditional Access

24 May 2023 at 07:00
Enforce Zero Trust in Microsoft 365 - Part 3: Introduction to Conditional Access

This blog post is the third blog post of a series dedicated to Zero Trust security in Microsoft 365.

In the first two blog posts, we set the basics by going over the free features of Azure AD that can be implemented in an organization that starts its Zero Trust journey in Microsoft 365. We went over the Security Defaults, the per-user MFA settings and some Azure AD settings that allowed us to improve our default security posture when we create a Microsoft 365 environment.

Previous blog posts:

Introduction

In this blog post, we will see what Azure AD Conditional Access is, how it can be used to further improve security and introduce its integration capabilities with other services.

As a reminder, our organization has just started with Microsoft 365. However, we have decided to go for Microsoft 365 for our production environment. Therefore, we want to have a look at a more advanced feature, Azure AD Conditional Access policies. This feature requires an Azure AD Premium P1 license which comes as a standalone license or which is also included in some Microsoft 365 licenses (Microsoft 365 E3/A3/G3/F1/F3, Enterprise Mobility & Security E3, Microsoft 365 Business Premium, and higher licenses). Note that one license should be assigned to each user in scope of any Conditional Access policies.

Azure AD Conditional Access allows to take identity-driven signals to make decisions and enforce policies. They can be seen as if-then statements. For instance, if a user wants to access SharePoint Online, which is a Microsoft cloud application that can be integrated in such policies, the user, more specifically, the user’s request, is required to meet specific requirements, defined in those policies. Let’s now see what the capabilities of those policies are.

Conditional Access

This part will be more theoretical to make sure everyone has the basics. Therefore, if you are already familiar to Azure AD Conditional Access Policies, you can directly jump to the next section for the implementation where we go over some prerequisites and important actions that need to be done to avoid troubles when setting up those policies based on our hands-on experience.

Conditional Access signals

As we have seen, signals will be considered to make a decision. It is possible to configure the following signals:

  • User, group membership or workload identities (also known as service principals or managed identities in Azure): It is possible to target or exclude specific users, groups, or workload identities from a Conditional Access policy;
  • Cloud apps or actions: Specific cloud applications such as Office 365, the Microsoft Azure Management, Microsoft Teams applications, etc. can be targeted by a policy. Moreover, specific user actions like registering security information (registering to MFA or Self-Service Password Reset) or joining devices can be included as well. Finally, authentication context can also be included. Authentication contexts are a bit different as they can be used to protect specific sensitive resources accessed by users or user actions in the environment. We will discuss authentication contexts in details in later blog post;
  • Conditions: With an Azure AD Premium P1 license, specific conditions can be set. This includes:
    • The device platforms: Android, iPhone, Windows Phone, Windows, macOS and Linux;
    • The locations: Conditional Access works with Named Locations which can include country/countries or IP address(es) that can be seen as trusted or untrusted;
    • The client apps: client apps which support modern authentication: Browser and Mobile apps and desktop clients; and legacy authentication clients: Exchange ActiveSync clients and other clients;
    • Filter for devices: allows to target or exclude devices based on their attributes such as compliance status in the device management solution, if the device is managed in Microsoft Endpoint Manager or on-premises, or registered in Azure AD, as well as custom attributes that have been set on devices;
    • Note that these conditions need to be all matched for the policy to apply. If a condition such as the location is excluded and match an attempt to access an application, the policy will not apply. Finally, if multiple policies matched, they will all apply, and access controls will be combined (the most restrictive action will be applied in case of conflicts).

Conditional Access access controls

Then, we have the access controls which are divided into two main categories, the “grant” and the “session” controls. These access controls define the “then do this” part of the Conditional Access policy (if all conditions have matched as mentioned previously). They can be used to allow or block access, require MFA, require the device to be compliant or managed as well as other more specific controls.

Grant controls

  • Block access: if all conditions have matched, then block access;
  • Grant access: if all conditions have matched, then grant access and optionally apply one or more of the following controls:
    • No controls are checked: Single-Factor Authentication is allowed, and no other access controls are required;
    • Require Multi-Factor Authentications;
    • Require authentication strength: allows to specify which authentication method is required for accessing the application;
    • Require device to be marked as compliant: this control requires devices to be compliant in Intune. If the device is not compliant, the user will be prompted to make the device compliant;
    • Require Hybrid Azure AD joined devices: this control requires devices to be hybrid Azure AD joined meaning that devices must be joined from an on-premises Active Directory. This should be used if devices are properly managed on-premises with Group Policy Objects or Microsoft Endpoint Configuration Manager, formerly SCCM, for example;
    • Require approved client apps: approved client apps are defined by Microsoft and represent applications that supports modern authentication;
    • Require app protection policy: app protection policies can be configured in Microsoft Intune as part of Mobile Application Management. This control does not require mobile devices to be enrolled in Intune and therefore work with bring-your-own-device (BYOD) scenarios;
    • Require password change;
    • For multiple controls (when multiple of the aforementioned controls are selected):
      • Require all the selected controls;
      • Require one of the selected controls.

Session controls

  • Use app enforced restrictions: app enforced restrictions require Azure AD to pass device information to the selected cloud app to know if a connection is from a compliant or domain-joined device to adapt the user experience. This control only works with Office 365, SharePoint Online and Exchange Online. We will see later how this control can be used;
  • Use Conditional Access App Control: this is the topic of a later blog post, but it allows to enforce specific controls for different cloud apps with Microsoft Defender for Cloud Apps;
  • Sign-in frequency: this control defines how often users are required to sign in again every (x hours or days). The default period is 90 days;
  • Persistent browser session: when a persistent session is allowed, users remain signed in even after closing and reopening their browser window;
  • Customize continuous access evaluation: continuous access evaluation (CAE) allows access tokens to be revoked based on specific critical events in near real time. This control can be used to disable CAE. Indeed, CAE is enabled by default in most cases (CAE migration);
  • Disable resilience defaults: when enabled, which is the case by default, this setting allows to extend access to existing session while enforcing Conditional Access policies. If the policy can’t be evaluated, access is determined by resilience settings. On the other hand, if disabled, access is denied once the session expires;
  • Require token protection for sign-in sessions: this new capability has been designed to reduce attacks using token theft (stealing a token, hijacking or replay attack) by creating a cryptographically secure tie between the token and the device it is issued to. At the time of writing, token protection is in preview and only supports desktop applications accessing Exchange Online and SharePoint Online on Windows devices. Other scenarios will be blocked. More information can be found here.

Conditional Access implementation

Before getting started with the implementation of Conditional Access policies, there are a few important considerations. Indeed, the following points might determine if our Zero Trust journey is a success or a failure in certain circumstances.

Per-user MFA settings

If you decided to go for the per-user MFA settings during the first blog post, you might consider the following:

  • As mentioned before, Conditional Access policies can be used to enforce a sign-in frequency. However, this can also be achieved using the ‘remember multi-authentication’ setting. If both settings are configured, the sign-in frequency enforced on end users will be a mix of both configuration and will therefore lead to prompting users unexpectedly;
  • If trusted IPs, which require an Azure AD Premium P1 license, have been configured in the per-user MFA settings, they will conflict with named locations in Azure AD Conditional Access. Named locations allow you to define locations based on countries or IP address ranges that can then be used to allow or block access in policies. Besides that, if possible, named locations should be used because they allow more fine-grained configurations as they do not automatically apply to all users and in all scenarios;
  • Finally, before enforcing MFA with Conditional Access policies, all users should have their MFA status set to disabled.

Security Defaults

Moreover, if you opted for the Security Defaults, it needs to be disabled as they can’t be used together.

How and where to start?

Now that we have some concepts about Conditional Access and some considerations for the implementation, we can start with planning the implementation of our policies. First, we need to ensure that we know what we want to achieve and what the current situation is. In our case, we first want to enforce MFA for all users to prevent brute force and protect against simple phishing attacks.

However, there might be some user accounts used as services accounts in our environment, such as the on-premises directory synchronization account for hybrid deployments, which can’t perform multi-factor authentication. Therefore, we recommend identifying these accounts and excluding them from the Conditional Access policy. However, because MFA would not be enforced on these accounts, they are inherently less secure and prone to brute force attacks. For that purpose, Named Locations could be used to only allow these service accounts to login from a defined trusted location such as the on-premises network (this now requires an additional license for each workload identity that you want to protect: Microsoft Entra Workload Identities license). Except for the directory synchronization account, we do not recommend the use of user accounts as service accounts. Other solutions are provided by Microsoft to manage applications in Azure in a more secure way.

Our first policy could be configured as follows (note that using a naming convention for Conditional Access policies is a best practice as it eases management):

1. Assign the policy to all users (which includes all tenant members as well as external users) and exclude service accounts (emergency/break-the-glass accounts might also need to be excluded):

Conditional Access policy assignments
Assignments

2. Enforce the policy for all cloud applications:

Cloud applications
Cloud applications

3. Require MFA and enforce a sign-in frequency of 7 days:

Access controls
Access controls

4. Configure the policy in report-only first

Report-only mode
Report-only mode

We always recommend configuring Conditional Access policies in report-only mode before enabling them. The report-only feature will generate logs the same way as if the policies were enabled. This will allow us to assess any potential impact on service accounts, on users, etc. After a few weeks, if no impact has been discovered, the policy can be switched to ‘On’. Note that there might be some cases where you may want to shorten or even skip this validation period.

These logs can be easily access in the ‘Insights and reporting‘ panel in Conditional Access:

Conditional Access Insights and reporting
Conditional Access Insights and reporting

Conclusion

In this third blog post, we learned about Conditional Access policies by going over a quick introduction on Conditional Access signals and access controls. Then, we went over some implementation considerations to make sure our Zero Trust journey is a success by preventing unexpected behaviors and any impact on end users. Finally, we implemented our very first Conditional Access policy to require Multi-Factor Authentication on all users except on selected service accounts (which is not the best approach as explained above).

If you are interested to know how NVISO can help you planning your Conditional Access policies deployment and/or support you during the implementation, feel free to reach out or to check our website.

In my next blog post, we will see which policies can be created to enforce additional access controls without requiring user devices to be managed in Intune to further protect our environment.

About the author

Guillaume Bossiroy

Guillaume is a Senior Security Consultant in the Cloud Security Team. His main focus is on Microsoft Azure and Microsoft 365 security where he has gained extensive knowledge during many engagements, from designing and implementing Azure AD Conditional Access policies to deploying Microsoft 365 Defender security products.

Additionally, Guillaume is also interested into DevSecOps and has obtained the GIAC Cloud Security Automation (GCSA) certification.

Enforce Zero Trust in Microsoft 365 – Part 2: Protect against external users and applications

12 May 2023 at 07:00
Enforce Zero Trust in Microsoft 365 - Part 2: Protect against external users and applications

In the first blog post of this series, we have seen how strong authentication, i.e., Multi-Factor Authentication (MFA), could be enforced for users using a free Azure Active Directory subscription within the Microsoft 365 environment.

In this blog post, we will continue to harden the configuration of our Azure AD tenant to enforce Zero Trust security without any license requirement. Specifically, we will see how our organization can protect against external users and prevent malicious applications from accessing our tenant.

Previous blog post:

Settings hardening

Because some default settings in Azure Active Directory are not secure and might introduce security issues within our organization, I wanted to quickly go over them and see how they could be used by malicious actors.

Guest users

We haven’t discussed guest users for now. It is because access control for guest users can’t be enforced using an Azure AD free license. However, guest users might be the entry door for attackers to access our Microsoft 365 environment. Indeed, by compromising a user in a partner’s environment, adversaries will directly gain access to our environment because of this implicit trust relationship that is automatically setup when inviting guest users. Therefore, we can either assume that guest users are correctly protected in their home tenant (we will see in a later blog post that even if guest users have the appropriate security controls enforced in their home tenant, these security controls might not be enforced in certain circumstances to access our tenant (i.e., the resource tenant)), or restrict or disable guest user invitations. In any case, the way guest users will be managed is an important consideration for our Zero Trust approach. In our case, we will not simply block guest user invites because we think that collaboration with external parties is an important aspect for our business and will be required. Therefore, we want to take a proactive approach to this problem by setting a solid foundation before it is too late.

First, we want to ensure that no one in the organization, except authorized users, can invite guest users. Indeed, by default, all users in our organization, including guest users, can invite other guest users. This could represent a serious weakness in our Zero Trust approach. Therefore, we will only allow users assigned to specific administrator roles to invite guest users (this includes the Global Administrators, User Administrators and Guest Inviters roles).

Guest invite restrictions are configured in Azure AD. For that purpose, go to the Azure Portal > Azure Active Directory > Users > User Settings > Manage external collaboration settings under External users. Choosing the most restrictive option disables the ability to invite guest users.

Guest invite restrictions in Azure AD
Guest invite restrictions

Moreover, because our organization works with defined partners, users should only be able to collaborate with them. We can therefore further restrict invitations by specifying domains in the collaboration restrictions settings:

Collaboration restrictions
Collaboration restrictions

For those restrictions, a reliant process is required to clearly define who can manage guest users and external domains, especially if you regularly collaborate with different partners.

By default, guest users have extensive permissions. If an attacker takes over a guest account, the information to which the guest user has access, may be used for advanced attacks on our company. For this reason, we want to restrict them as much as possible. It might not be required for guest users to be able to enumerate resources in our Azure Active Directory tenant. This could allow adversaries, that compromised a guest user, to gain information on users within our tenant such as viewing our employees for sending (consent) phishing emails to gain initial access or viewing other partners to deceive them by impersonating our company or an employee. Therefore, we want to limit guest users permissions.

Guest user access restrictions in Azure AD
Guest user access restrictions

With these restrictions implemented for guest users, we have already decreased the potential impact that a compromised guest user could have in our environment. However, remember that with the current configuration, specific access controls, such as strong authentication for guest users, are not enforced to access our tenant. This means that a compromised guest user might still be used to access our environment.

External applications

In Azure Active Directory, applications can be integrated into Azure Active Directory to make them accessible to user. There are many types of applications that can be made accessible through Azure AD such as cloud applications, also known as pre-integrated applications, like Office 365, the Azure Portal, Salesforce, etc., custom applications, and on-premises applications.

Users can consent to applications to allow these applications to access organization data or a protected resource in the tenant on their behalf. Indeed, applications can request API permissions so that they can work properly. These API permissions include accessing a user’s profile, a user’s mailbox content, sending emails, etc. This can also be seen as an entry door for adversaries to gain access to information in our environment. For example, attackers could trick an employee by sending a consent link (consent phishing) to an employee for a malicious application. If the user consents, attackers would have the permissions the user has consented to. Even worse, an administrator might consent to an application for the entire organization. This means that a malicious application could potentially gain access to all directory objects.

Let’s abuse it!

If user consent is allowed in our Azure AD tenant, adversaries could send consent grant phishing to employees. Let’s see how this could be done.

First, because adversaries could access our Azure AD tenant because guest invitation restrictions were initially not configured, they could gather a list of our employees as well as their email address. Then, they used this list to create a phishing campaign for a Microsoft Advertising Certification study guide.

Phishing email
Phishing email

Because one employee was very eager to try out this new limited edition guide, they clicked the link and signed in with their credentials.

Application permissions request
Permission consent

Unfortunately, the employee had administrative permission in our tenant and could therefore grant consent on behalf of the entire organization. Everyone should benefit from this free offer, right?… Not really, no. Indeed, as shown in the above screenshot the application, which is not verified, requires a lot of access such as sending and viewing emails, read and write access to mailbox settings, and read access to notes, files, etc.

Once the user clicks, adversaries can retrieve information about the user as well as from the organization. Additionally, they can access the user’s mailbox, OneDrive files and notes.

For this demonstration, I used 365-Stealer from AlteredSecurity to setup the phishing page and to access users in the directory:

Phished users in 365-Stealer
365-Stealer

How to protect ourselves against consent grant phishing?

There are no bullet proof solutions to protect users from phishing, unless you disable the ability for users to receive emails and messages globally, which is very far from ideal. Indeed, even with Office 365 threat policies, such as anti-phishing policies, and user awareness, malicious actors are always finding new ways of bypassing these polices and tricking users. However, what we can do is disabling the ability to consent for applications in Azure AD.

To restrict user consent for applications, it is possible to disable or restrict applications and permissions that user can consent to. Unless it is required, it is highly recommended to disable user consent. This will be done for our organization tenant to prevent consent grant attacks.

Consent and permissions for users
Consent and permissions for users

This setting can be configured in Azure Portal > Azure Active Directory > Users > User settings > Manage how end users launch and view their applications under Enterprise applications > Consent and permissions.

Besides blocking this functionality, it is also possible to only allow users to consent for permissions classified as low impact. Microsoft provides the ability to define our own classification model for application permissions, ranging from low to high as show below. In that case, administrators can select the Allow user consent for apps from verified publishers, for selected permissions (Recommended) setting in the user consent settings page:

Permission classifications for applications in Azure AD
Permission classifications for applications in Azure AD

Conclusion

In this blog post, we went over different settings in Azure AD that can be restricted to prevent malicious users from being added to our tenant. Moreover, we have seen how application consent settings can be abused through consent grant phishing and how we can protect against it.

I have selected these settings among others because we usually see that they are not restricted in most environments during our security assessments. However, configuring only these settings is not enough to protect your environment against malicious and unauthorized actions. If you would like to know more about how NVISO can help you securing your environment, feel free to reach out or to check our website.

In the next blog post, we will go over Azure AD Conditional Access policies, see how they can be used to further increase the security posture of our environment and implement our Zero Trust security approach.

About the author

Guillaume Bossiroy

Guillaume is a Senior Security Consultant in the Cloud Security Team. His main focus is on Microsoft Azure and Microsoft 365 security where he has gained extensive knowledge during many engagements, from designing and implementing Azure AD Conditional Access policies to deploying Microsoft 365 Defender security products.

Additionally, Guillaume is also interested into DevSecOps and has obtained the GIAC Cloud Security Automation (GCSA) certification.

ETWHash – “He who listens, shall receive”

3 May 2023 at 10:58

ETWHash is a small C# tool used during Red Team engagements, that can consume ETW SMB events and extract NetNTLMv2 hashes for cracking offline, unlike currently documented methods.

github GitHub: https://github.com/nettitude/ETWHash

Microsoft ETW (Event Tracing for Windows) is a logging mechanism integrated into the Windows operating system that enables the generation of diagnostic and tracing messages by applications. These messages can be captured and analysed by security professionals or system administrators for various purposes, including debugging and performance analysis. Although ETW is mainly used for defensive applications, offensive security research took great interest in bypassing the offered visibility. However, as demonstrated in this short article, ETW can also be a great resource for offense, finding providers useful for passive situational awareness.

Instrumenting Your Code with ETW | Microsoft Learn

Numerous resources are available on ETW, detailing its applications in both offensive and defensive contexts. One particularly insightful resource is “Tampering with Windows Event Tracing: Background, Offense, and Defense“. The article provides a comprehensive guide to ETW, which gives all the necessary information to get up to speed.

While researching potential offensive uses for ETW, a presentation by CyberPoint at Ruxcon 2016 revealed a unique approach to utilizing ETW for information leakage and keylogging. The released POC code can be found here. The presentation sparked further interest in exploring ETW’s potential applications during Red Team engagements, leading to the discovery of a few interesting ETW providers.

The following tools are useful in exploring ETW providers.

By utilizing WEPExplorer, all available ETW providers on the test system were listed, and the Microsoft-Windows-SMBServer provider {D48CE617-33A2-4BC3-A5C7-11AA4F29619E} quickly drew attention.

Graphical user interface, text, application, email Description automatically generated

The provider exposes a large number of fields related to SMB operations of the host. An easy way to identify all the available fields of an ETW provider is by viewing the manifest of the ETW provider, which describes all the events that are supported. The manifest can be extracted using Microsoft’s Perfview:

PerfView userCommand DumpRegisteredManifest Microsoft-Windows-SMBServer

Graphical user interface, text, application Description automatically generated

After a few hours inspecting the fields and generating SMB events to understand the logging, the field PACKETBYTES was observed to be updated every time an SMB authentication attempt occurred. The immediate next step was to dump the entire byte array to see what it contained.

Graphical user interface, text, application Description automatically generated

A picture containing text Description automatically generated

The array as it can be seen, contained the null-terminated ASCII “NTLMSSP” string (0x4e544c4d53535000) which is part of the NTLM authentication message headers. If you want to read up more on the NTLM authentication protocol, “The NTLM Authentication Protocol and Security Support Provider” is an excellent resource.

It immediately became evident that the provider was logging all SMB packets, including the full NetNTLMv2 challenge response. Shortly thereafter, a proof-of-concept (POC) was developed that would create a new Trace Session in order to consume the events of the Microsoft-Windows-SMBServer provider, and upon the occurrence of the event 40000, would extract the NetNTLMv2 challenge response hash from the packet bytes.

Text Description automatically generated

Microsoft was contacted via MSRC and confirmed that this is intended behaviour, as it requires administrative privileges on the host.

We believe that ETW is great mechanism already leveraged extensively for defensive purposes, still having untapped potential for offensive usage. Interesting ideas for further exploitation might be:

  • Using ETW as an interprocess transfer channel
  • Using ETW to monitor / identify deceptive technologies
  • Using ETW to have situational awareness of services / processes / network connections / reboots

Maybe we should start listening more to ETW instead of disabling it 😉

The post ETWHash – “He who listens, shall receive” appeared first on LRQA Nettitude Labs.

Enforce Zero Trust in Microsoft 365 – Part 1: Setting the basics

2 May 2023 at 07:00

This first blog post is part of a series of blog posts related to the implementation of Zero Trust approach in Microsoft 365. This series will first cover the basics and then deep dive into the different features such as Azure Active Directory (Azure AD) Conditional Access policies, Microsoft Defender for Cloud Apps policies, Information Protection and Microsoft Endpoint Manager, to only cite a few.

In this first part, we will go over the basics that can be implemented in a Microsoft 365 environment to get started with Zero Trust. For the purpose of the blog post, we will assume that our organization decided to migrate to the cloud. We just started investigating what are the quick wins that can be easily implemented, what are the features that will need to be configured to ensure security of identities and data, and what the more advanced features that could be used to meet specific use cases would be.

Of course, the journey to implement Zero Trust is not an easy one. Some important decisions will need to be made to ensure the relevant features are being used and correctly configured according to your business, compliance, and governance requirements without impacting user productivity. Therefore, the goal of this series of blog posts is to introduce you possible approaches to Zero Trust security in Microsoft 365.

Introduction

However, before starting we need to set the scene by quickly going over some principles.

First, what is a Zero Trust security approach? Well, this security model says that you should never trust anyone and that each request should be verified regardless of where the request originates or what the accessed resource is. In other words, this model will assume that each request comes from an uncontrolled or compromised network. Microsoft provides this nice illustration to represent the primary elements that contribute to Zero Trust in a Microsoft 365 environment:

Zero Trust approach in Microsoft 365
Zero Trust approach in Microsoft 365

We will go over these components as part of this blog post series.

You may wonder why I have decided to discuss Zero Trust in Microsoft 365. Because I think it is one of the most, if not the most, important aspects of a cloud environment. Indeed, with cloud environments, identities are considered as the new perimeter as these identities can be used to access Internet-facing administrative portals and applications from any Internet-connected device. 

Furthermore, even when security controls are enforced, it does not mean that the environment is secure. There were many attacks these past few months/years that allowed attackers to bypass security controls through social engineering, and phishing attacks, for example. Therefore, the goal is more to reduce the potential impact of a security breach on the environment than to prevent attacks from succeeding.

Finally, let’s go over some Microsoft 365 principles. When an organization signs up for a subscription of Microsoft 365, an Azure AD tenant is created as part of the underlying services. For data residency requirements, Microsoft lets you choose the logical region where you want to deploy your instance of Azure AD. This region will determine the location of the data center where your data will be stored. Moreover, Microsoft 365 uses Azure AD to manage user identities. Azure AD offers the possibility to integrate with an on-premises Active Directory Domains Services (AD DS) but also to manage integrated applications. Therefore, you should/must/have to understand that most of the work to set up a Zero Trust approach will be done in Azure AD.

Let’s get started!

Our organization just bought a paid Microsoft 365 subscription which comes with a free subscription to Microsoft Azure AD. The free Azure AD subscription includes some basic features that will allow us to get started with our journey. Let’s go over them!

Security Defaults

The first capability is the Azure AD Security Defaults. The Security Defaults are a great first step to improve the security posture by enforcing specific access controls:

  • Unified Multi-Factor Authentication (MFA) registration: All users in the tenant must register to MFA. With Security Defaults, users can only register for Azure AD Multi-Factory Authentication by using the Microsoft Authenticator app using a push notification. Note that once registered, users will have the possibility to use a verification code (Global Administrator will also have the possibility to register for phone call or SMS as second factor). Another important note is that disabling MFA methods may lead to locking users out of the tenant, including the administrator that configured the setting, if Security Defaults are being used;
  • Protection of administrators: Because users that have privileged access have increased access to an environment, users that have been assigned to specific administrator roles are required to perform MFA each time they sign in;
  • Protection of users: All users in the tenant are required to perform MFA whenever necessary. This is decided by Azure AD based on different factors such as location, device, and role. Note that this does not apply to the Azure AD Connect synchronization account in case of a hybrid deployment;
  • Block the use of Legacy Authentication Protocols: Legacy authentication protocols refer to protocols that do not support Multi-Factor Authentication. Therefore, even if a policy is configured to require MFA, users will be allowed to bypass MFA if such protocols are used. In Microsoft 365, legacy authentication is made from clients that don’t use modern authentication such as Office versions prior to Office 2013 a mail protocols such as IMAP, SMTP, or POP3;
  • Protection of privileged actions: Users that access the Azure Portal, Azure PowerShell or Azure CLI must complete MFA.

These features already allow to increase the security posture by enforcing strong authentication. Therefore, they can be considered a first step for our organization that just started to use Microsoft 365 and is still researching/evaluating/ the different possibilities.

If we want to enable Security Defaults, we go to the Azure Portal > Active Azure Directory > Properties > Manage Security Defaults:

Enable Security Defaults in Azure AD
Enabling Security Defaults

However, there are important deployment considerations to be respected before enabling Security Defaults. Indeed, it is a best practice to have emergency accounts. These accounts are usually assigned the Global Administrator role, the most privileged role in Azure AD/Microsoft 365 and are created to enable access to the environment when normal administrator accounts can’t be used. This could be the case if Azure AD MFA experiences outages. Because of the purpose of such accounts, these users should either be protected with a very strong first authentication method (e.g., strong password stored in secure location such as a physical vault that can only be accessed by a limited set of people under specific circumstances) or use a different second authentication factor than other administrators (e.g., if Azure AD MFA is used for administrator accounts used regularly, a third party MFA provider, such as hardware tokens, can be used). But here is the problem: this is not possible when using Security Defaults.

Per-user MFA settings

Note that the per-user MFA settings, also known as legacy multifactor authentication, will be deprecated on September 30th, 2024.

The second capability with an Azure AD free license is the per-user MFA settings. These settings can be used to require Multi-Factor Authentication for specific users each time they sign in. However, some exceptions are possible by turning on the ‘Remember MFA on trusted devices’. Note that when enabled this setting will allow users to mark their own personal or shared devices as trusted. This is possible, because this setting does not rely on any device management solution. Users will only be asked to reauthenticate every few days or weeks when selecting this option. The interval depends on the configuration.

We usually do not recommend using the ‘Remember MFA on trusted devices’ setting unless you do not want to use Security Defaults and do not have Azure AD Premium licenses. Indeed, this setting allows any user to trust any device, including shared and personal devices, for the specified number of days (between one and 365 days). However, these settings can be configured in the https://account.activedirectory.windowsazure.com portal.

In the user settings, MFA can be enabled for each individual user.

Per-user MFA settings in Azure AD
Per-user MFA users settings

Then, in the service settings, we can allow users to create app passwords for legacy applications that do not support MFA, select authentication methods that are available for all users, and allow or not users to remember Multi-Factor Authentication on trusted devices for a given period of time. Note that the trusted IP addresses feature requires an additional license (Azure AD Premium P1) that we do not have for the moment.

Legacy MFA settings in Azure AD
Per-user MFA service settings

Sum-up

These two features are quite different but allow us to achieve the same goal, to enforce strong authentication, i.e., MFA, for all or some users.

For our organization we will choose the Security Defaults for multiple reasons:

  • The per-user MFA settings can become unmanageable quickly. This is especially true for growingorganization.With more people and a complex environment, exceptions will be required, and it will become difficult to keep track of the configuration and keep a good baseline. Security Defaults, respectively,allow to enforce a standard baseline for all users;
  • By using per user MFA users will be prompted for MFA every time they sign in.. This badly affects user experience and productivity might be impacted;
  • Security Defaults blocks legacy authentication protocols that might be used to bypass MFA in some cases. This prevents identities, including administrators, from being targeted by brute force or password spraying attacks and help mitigating the risk of successful phishing attacks to a certain extent;
  • Multi-Factor Authentication registration is enforced with Security Defaults for all users meaning that all users will be capable of doing MFA if required.

By going that way we need to consider that exclusions are not possible. Therefore, emergency accounts or user accounts used as service accounts (which it is not recommended to have as they are inherently less secure than managed identities or service principals) might be blocked. Nevertheless, as we are just evaluating the Microsoft 365 products, we can accept that the environment and cloud applications are unavailable for a few hours without any major impact on business processes. However, this might be an crucial point in the future.

Finally, it is important to note that these two features do not allow to configure more granular controls as we will see later in this series.

Conclusion

In this first blog post, we have seen different possibilities to enforce access restrictions that can be implemented when an organization just starts its journey in Microsoft 365:

  • Per-user MFA settings: Allow to enforce MFA for specific users but can become quickly unmanageable and does not provide granular controls;
  • Security Defaults: Allow to enforce a strong authentication mechanism and to block legacy authentication protocols that may allow users to bypass MFA. This solution is recommended over the per-user MFA settings. However, note that MFA might not be required in most cases which is not ideal.

In brief, we can see that both solutions have limitations and will not be suitable for most organizations. Indeed, there are still many aspects, such as restricting access based on specific conditions, that are not covered by these capabilities. We will go over additional key features as well as our recommendations for the implementation of a Zero Trust approach in Microsoft 365 in future blog posts.

In the next blog post, we will see how we can protect our environment against external users and applications.

About the author

Guillaume Bossiroy

Guillaume is a Senior Security Consultant in the Cloud Security Team. His main focus is on Microsoft Azure and Microsoft 365 security where he has gained extensive knowledge during many engagements, from designing and implementing Azure AD Conditional Access policies to deploying Microsoft 365 Defender security products.

Additionally, Guillaume is also interested into DevSecOps and has obtained the GIAC Cloud Security Automation (GCSA) certification.

The Rising Trend of OneNote Documents for Malware delivery

30 March 2023 at 23:37

Authored By Anandeshwar Unnikrishnan,Sakshi Jaiswal,Anuradha M 

McAfee Labs has recently observed a new Malware campaign which used malicious OneNote documents to entice users to click on an embedded file to download and execute the Qakbot trojan. 

OneNote is a Microsoft digital notebook application that can be downloaded for free. It is a note-taking app that allows collaboration across organizations while enabling users to embed files and other artifacts. It is installed by default in Microsoft Office 2021 and Microsoft 365.   

Malicious Actors are always trying to find new ways in to infect their victims. Such as their shift to LNK files after Microsoft introduced a policy change disabled office macros by default. Due to a feature that allows users to attach files to OneNote documents it makes them a good alternative to LNK files as distribution vehicle to deploy their malware. This blog contains analysis on how OneNote documents are used malicious and two specific campaigns that made use of OneNote documents to download and execute the Qakbot malware.  

OneNote Campaigns in the wild 

Figure 1 Campaign Heatmap
Figure 1 Campaign Heatmap

Figure 1  shows the geo wise distribution of McAfee customers detecting malicious OneNote files. 

 Based on the telemetry from our endpoints we have identified the following threat families deployed through OneNote documents: 

  • Iceid 
  • Qakbot
  • RedLine
  • AsyncRat
  • Remcos
  • AgentTesla
  • QuasarRAT
  • XWORM
  • Netwire
  • Formbook
  • Doubleback 

Overview Of Malicious OneNote Documents 

A holistic view of the phishing campaigns that weaponize OneNote document is shown in Figure 2 below.  The malicious document is delivered in either zip files or ISO images to the target through phishing emails. We have observed that most of the malicious documents either have Windows batch script that invokes Powershell for dropping the malware on the system or Visual Basic scripts that does the same.

Figure 2 Campaign Overview

The generic theme of the email is invoice or legal related. These types of themes are more likely to be opened by the vicim. An example email body and attachment is shown in Figure 3 and 4. 

Figure 3 Email Body
Figure 4 Attachment

A Deep Dive into OneNote File Format 

File Header 

To understand how the data is laid out in the file, we need to examine it at byte level. Taking a close look at OneNote document gives us an interesting observation as its magic bytes for the header is not a trivial one. Figure 5 shows the first 16 bytes of the document binary. 

Figure 5 OneNote Header

The first 16 bytes need to be interpreted as GUID value {7B5C52E4-D88C-4DA7-AEB1-5378D02996D3}. We can use the official documentation for OneNote specification to make sense of all the bytes and its structuring. Figure 6 shows header information taken from the OneNote specification document. 

Figure 6 OneNote Specification

The Data Stream in OneNote, Say Hello To FileDataStoreObject 

To find the embedded data in a OneNote document, we need to learn more about the FileDataStoreObject which has a GUID value of {BDE316E7-2665-4511-A4C4-8D4D0B7A9EAC}. The structure that holds the data is shown below: 

  • guidHeader (16 bytes) 
  • Size: 16 bytes 
  • Value: {BDE316E7-2665-4511-A4C4-8D4D0B7A9EAC} 
  • cbLength 
  • Size: 8 bytes 
  • Value: Size of the data 
  • unused 
  • Size: 4 bytes 
  • reserved 
  • Size: 8 bytes 
  • FileData 
  • Size: Variable 
  • guidFooter 
  • Size: 16 bytes 
  • Value: {71FBA722-0F79-4A0B-BB13-899256426B24} 

The FileData member of the FileDataStoreObject is the key member that holds the embedded data in the OneNote document. The size can be retrieved from the cbLength member. 

Figure 7 shows the “on disk” representation of the FileDataStoreObject  This is taken from a malicious OneNote document used to spread the Qakbot payload. The guidHeader for the data object is highlighted in yellow and the data is shown in red. As it is evident from the image the data represents a text file which is a script to launch PowerShell.  

Figure 7 Embedded data in Data object

For more information on the OneNote specification, go to reference section  

Artifact Extraction  

Now we have an idea of what the data object is, with this knowledge we can automate the process of extracting embedded artifacts for further analysis from the OneNote document by following the below algorithm. 

  • Search for FileDataStoreObject GUID in the binary. 
  • Interpret the FileDataStoreObject structure  
  • Retrieve cbLength member (size of the data represented by FileDataStoreObject) 
  • Read N bytes (cbLength) after Reserved 8 bytes in FileDataStoreObject. 
  • Dump the bytes read on to disk 
  • Repeat above steps for every FileDataStoreObject present in the binary

Embedded Executable Objects In OneNote  

Execution Of Embedded Entities  

Looking at the runtime characteristics of OneNote Desktop application we have observed that when an embedded file gets executed by the user, it is stored temporarily in the OneNote directory in the User’s Temp location. Each directory with GUID values represents a different document opened in the OneNote application. 

Figure 8 OneNote directory in Temp

By analyzing numerous malicious documents, we have been able to create a “test” OneNote document that executes a batch file that contains the “whoami” command. The image in Figure  9 show the batch file being created in the user’s temp location. 

Figure 9 OneNote drops embedded artifacts in Temp directory

Qakbot Campaign 1: 

This section contains specific details on a Qakbot campaign. In campaign 1, the malware author used phishing emails to deliver malicious OneNote document either as attachment or a URL link to zip file containing the OneNote document. The OneNote contained aHTA file that once executed would make use of  the curl utility to download Qakbot and then execute it. 

Infection Flow: 

Figure 10 Infection Chain
  • Spam email delivers a malicious OneNote file as an attachment or a link to a ZIP file that contains a OneNote file. 
  • OneNote file contains an embedded HTA  attachment and a fake message to lure users to execute the HTA  file 
  • The HTA file uses curl utility to download the Qakbot payload and is executed by rundll32.exe. 

Technical Analysis: 

The OneNote file with the embedded HTA file is shown in the Figure 11. Once this OneNote file is opened, it prompts the user with a fake message to double-click on open to view the attachment. 

Figure 11 OneNote Template

Upon clicking the Open button, it drops the HTA file with the name Open.hta to the %temp% Folder and executes it using mshta.exe. 

Figure 12 Drop file in Temp location

The HTA file contains obfuscated script as shown below: 

Figure 13 Obfuscated HTA script

The HTA file is loaded by MSHTA and creates a registry key in HKEY_CURRENT_USER\SOFTWARE\ with obfuscated content as shown below: 

Figure 14 Registry key creation
  • The obfuscated registry is then read by MSHTA and the obfuscated code is de-obfuscated. The code is then initialized to a new function object as shown in Block1. 
  • Finally, MSHTA calls this function by passing the malicious URL as a parameter and then deletes the registry key as shown in Block 2.

De-obfuscated content from the HTA file is shown below: 

Figure 15 Deobfuscated HTA content
  • Curl is used to download the malicious DLL file in C:\ProgramData Folder with .png extension. The script will then execute the downloaded file with Rundll32.exe with the export function Wind.
Figure 16 Downloaded payload in ProgramData
  • A fake error message is displayed after loading the downloaded payload and MSHTA is terminated.  
Figure 17 Fake error message

Figure 18 shows the process tree of Qakbot: 

Figure 18 Process Chain

IOCs: 

Type  Value  Product  Detected 
Campain 1 – OneNote File  88c24db6c7513f47496d2e4b81331af60a70cf8fb491540424d2a0be0b62f5ea  Total Protection and LiveSafe  VBS/Qakbot.a 
Campain 1 – HTA File  e85f2b92c0c2de054af2147505320e0ce955f08a2ff411a34dce69c28b11b4e4  Total Protection and LiveSafe  VBS/Qakbot.b 
Campain 1 – DLL File  15789B9b6f09ab7a498eebbe7c63b21a6a64356c20b7921e11e01cd7b1b495e3  Total Protection and LiveSafe  Qakbot-FMZ 

Campaign 2: 

Examining Malicious OneNote Documents 

The OneNote document for campaign 2 is shown in Figure 19. At first glance it it appears that there is a ‘Open’ button embedded within the document. The message above the ‘Open’ button instructs the user to “double click” in order to receive the attachment.

Figure 19 Malicious content

A closer look at the document reveals the graphical elements are all images placed in a layered style by the malicious actor. By moving the icons aside, we can see the malicious batch file which when executed downloads the payload from the Internet and executes on the target system. 

Figure 20 Hidden Malicious dropper script
Figure 20 Hidden Malicious dropper script

Execution Of Payload Dropper 

Upon execution of the batch file, Powershell will be invoked and it fetch the Qakbot payload from Internet and execute it on the target system. This section will cover details of dropper script used to deploy QakBot. The Figure 21 Show the process tree after the execution of the script and you can see that powershell.exe was launched by cmd.exe and the parent of cmd.exe is onenote.exe. 

Figure 21 Process chain

The contents of process cmd.exe (7176) are shown below.  

Figure 22 Cmd.exe properties

The base64 decoded batch file is shown in Figure 23This will use powershell to download the payload and then execute it with rundll32.exe

Figure 23 Base64 Decoded instructions in dropper

 IOCS 

Type  Value  Product  Detected 
Campain 2 – Zip File  000fb3799a741d80156c512c792ce09b9c4fbd8db108d63f3fdb0194c122e2a1 

 

Total Protection and LiveSafe  VBS/Qakbot.a 
Campain 2 – OneNote File  2bbfc13c80c7c6e77478ec38d499447288adc78a2e4b3f8da6223db9e3ac2d75  Total Protection and LiveSafe  One/Downloader.a 
Campain 2 – Powershell File  b4dd3e93356329c076c0d2cd5ac30a806daf46006bdb81199355952e9d949424  Total Protection and LiveSafe  PS/Agent.gs 
Campain 2 – OneNoteFile  a870d31caea7f6925f41b581b98c35b162738034d5d86c0c27c5a8d78404e860   Total Protection and LiveSafe  VBS/Qakbot.a 
       

Domains: 

starcomputadoras.com 

Conclusion: 

Malware authors are getting more sophisticated when it comes to hiding their payloads. This Blog highlights the recent Qakbot campaign that delivers its payload which uses the OneNote application as a delivery mechanism. McAfee Customers should keep their systems up-to-date and refrain from clicking links and opening attachments in suspicious emails to stay protected. 

 References: 

https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-onestore/405b958b-4cb7-4bac-81cc-ce0184249670 

https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-onestore/8806fd18-6735-4874-b111-227b83eaac26 

The post The Rising Trend of OneNote Documents for Malware delivery appeared first on McAfee Blog.

Let's Dance in the Cache - Destabilizing Hash Table on Microsoft IIS!

17 August 2022 at 16:00
Hi, this is my fifth time speaking at Black Hat USA and DEFCON. You can get the slide copy and video there: Let’s Dance in the Cache - Destabilizing Hash Table on Microsoft IIS (slides) Let’s Dance in the Cache - Destabilizing Hash Table on Microsoft IIS (video - TBD) As the most fundamental Data Structure in Computer Science, Hash Table is extensively

CVE-2022-30211: Windows L2TP VPN Memory Leak and Use after Free Vulnerability

17 August 2022 at 09:00

Nettitude discovered a Memory Leak turned Use after Free (UaF) bug in the Microsoft implementation of the L2TP VPN protocol. The vulnerability affects most server and desktop versions of Windows, dating back to Windows Server 2008 and Windows 7 respectively. This could result in a Denial of Service (DoS) condition or could potentially be exploited to achieve Remote Code Execution (RCE).

Please see the official Microsoft advisory for full details:

https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-30211

L2TP is a relatively uncommonly used protocol and sits behind an IPSEC authenticated tunnel by default, making the chances of seeing this bug in the wild extremely low. Despite the low likelihood of exploitation, analysis of this bug demonstrates interesting adverse effects of code which was designed to actually mitigate security risk.

L2TP and IPSEC

The default way to interact with an L2TP VPN on Windows Server is by first establishing an IPSEC tunnel to encrypt the traffic. For the purposes of providing a minimalistic proof of concept, I tested against Windows Server with the IPSEC tunnelling layer disabled, interacting directly with the L2TP driver. Please note however, it is still possible to trigger this bug over an IPSEC tunnelled connection.

For curious readers, disabling IPSEC can be achieved by setting the ProhibitIpSec DWORD registry key with a value of 1 under the following registry path:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\RasMan\Parameters\

This will disable IPSEC tunnelling and allow L2TP to be interacted with directly over UDP. Not to discourage a full IPSEC + L2TP solution, but it does make testing the L2TP driver a great deal easier!

Vulnerability Details

The bug in question is a reference increment bug located in the rasl2tp.sys L2TP VPN protocol driver, and relates to how tunnel context structures are reused. Each established tunnel for a connection is allocated a context structure, and a unique tunnel is considered to be the pairing of both a unique tunnel ID and UDP + IP address.

When a client initiates an L2TP StartControlConnectionRequest for a tunnel ID that they have previously used on a source IP and port that the server has already seen, the rasl2tp driver will attempt to reuse a previously allocated structure as long as it is not in an unusable state or already freed. This functionality is handled by the SetupTunnel function when a StartControlConnectionRequest is made with no tunnel or session ID specified in the L2TP Header, and an assigned tunnel ID matching one that has already been used.

Pseudo code for the vulnerable section is as follows:

if ( !lpL2tpHeaderHasTunnelID )
{
   // Tunnel Lookup function uses UDP address information as well as TunnelID to match a previous Tunnel Context structure
   NewTunnel = TunnelCbFromIpAddressAndAssignedTunnelId(lpAdapterCtx, lpSockAddr, lpTunnelId);
   if ( NewTunnel ) // if a match is found a pointer is returned else the return is NULL
   {
      if...
      ReferenceTunnel(NewTunnel, 1); // This is the vulnerable reference count
      KeReleaseSpinLock(&lpAdapterCtx->TunnelLock, lpAdapterCtx->TunnelCurIRQL);
      return NewTunnel;
   }
}

The issue is that the reference count does not have an appropriate dereference anywhere in the code. This means that it is possible for a malicious client to continually send StartControlConnectionRequests to increment the value indefinitely.

This creates two separate vulnerable conditions. Firstly, because the reference count can be far greater than it should be, it is possible for an attacker to abuse the issue to exhaust the memory resources of the server by spoofing numerous IP address and tunnel ID combinations and sending several StartControlConnectionRequests. This would keep the structures alive indefinitely until the server’s resources are exhausted, causing a denial of service. This process can be amplified across many nodes to accelerate the process of consuming server resources and is only limited by the bandwidth capacity of the server. In reality, this process may also be limited by other factors applied to network traffic before the L2TP protocol is handled.

The second vulnerable condition is due to logic in the DereferenceTunnel function responsible for removing tunnel references and initiating the underlying free operation. It is possible to turn this issue into a Use after Free (UaF) vulnerability, which could potentially then be used to achieve Remote Code Execution.

Some pseudo code for the logic that allows this to happen in the DereferenceTunnel function is as follows:

__int64 __fastcall DereferenceTunnel(TunnelCtx *TunnelCtx)
{
   ...

   lpAdapterCtx = TunnelCtx->AdapterCtx;
   lpTunnelCtx = TunnelCtx;
   lpAdapterCtx->TunnelCurIRQL = KeAcquireSpinLockRaiseToDpc(&lpAdapterCtx->TunnelLock);
   RefCount = --lpTunnelCtx->TuneelRefCount;
   if ( !RefCount )
   {
      // This code path properly removes the Tunnel Context from a global linked list and handles state termination
      ...
   }
   KeReleaseSpinLock(&lpAdapterCtx->TunnelLock, lpAdapterCtx->TunnelCurIRQL);
   if ( RefCount > 0 ) // This line is vulnerable to a signed integer overflow
      return (unsigned int)RefCount;
   ...
   lpTunnelCtx->TunnelTag = '0T2L';
   ExFreePoolWithTag(&lpTunnelCtx[-1].TunnelVcListIRQL, 0);
   ...
   return 0i64;
}

The second check of the reference count that would normally cause the function to return uses a signed integer for the reference count variable. This means using the reference increment bug we can cause the reference count value to overflow and become a negative number. This would cause the DereferenceTunnel function to free the target tunnel context structure without removing it from the global linked list.

The global linked list in question is used to store all the active tunnel context structures. When a UDP packet is handled, this global linked list is used to lookup the appropriate tunnel structure. If a freed structure was still present in the list, any UDP packet referencing the freed context structure’s ID would be able to gain access to the freed structure and could be used to further corrupt kernel memory.

Exploitation

Exploitation of this bug outside of just exhausting the memory resources of a target server could take a very long time and I suspect would not realistically be exploitable or viable. Since a reference count can only happen once per UDP packet and each UDP message has to be large enough to contain all prior network stack frames and the required L2TP (and IPSEC) messages, the total required throughput is huge and would almost definitely be detected as a denial of service (DoS) attack long before reaching the required reference count.

Conclusion

This leaves the question of why would a developer allow a reference count to be handled in this way, when it should only ever require a minimum value of 0?

The main reason for allowing a reference count to become a negative number is to account or check for code that over removes references, and would typically result in an unsigned overflow. This kind of programming is a way of mitigating the risk posed by the more likely situation that a reference count is over-decremented. However, a direct result is that the opposite situation then becomes much more exploitable and in this scenario results in a potential for remote code execution (RCE).

Despite this, the mitigation is still generally effective, and the precursors for exploitation of this issue are unlikely to be realistically exploitable. In a way, the intended mitigation works because even though the maximum possible impact is far greater, the likelihood of exploitation is far lower.

Timeline

  • Vulnerability Reported To Microsoft – 20 April 2022
  • Vulnerability Acknowledged – 20 April 2022
  • Patch In Development – 23 June 2022
  • Patch Released – 12 July 2022

The post CVE-2022-30211: Windows L2TP VPN Memory Leak and Use after Free Vulnerability appeared first on Nettitude Labs.

Logging Passwords in Plaintext in Azure Arc

19 July 2022 at 13:03

Microsoft’s Azure Arc is a management platform designed to bridge multi-cloud and similarly mixed environments together in a convenient way.

Tenable Research has discovered that the Jumpstart environments for Arc do not properly use logging utilities common amongst other Azure services. This leads to potentially sensitive information, such as service principal credentials and Arc database credentials, being logged in plaintext. The log files that these credentials are stored in are accessible by any user on the system. Based on this finding, it may be possible that other services are also affected by a similar issue.

Microsoft has patched this issue and updated their documentation to warn users of credential reuse within the Jumpstart environment. Tenable’s advisory can be found here. No bounty was provided for this finding.

The Flaw

The testing environment this issue was discovered in is the ArcBox Fullbox Jumpstart environment. No additional configurations are necessary beyond the defaults.

When ArcBox-Client provisions during first-boot, it runs a PowerShell script that is sent to it via the `Microsoft.Compute.CustomScriptExtension (version 1.10.12) plugin.

Most scripts we’ve come across on other services tend to write ***REDACTED*** in place of anything sensitive when writing to a log file. For example:

<PluginSettings>
<Plugin name="Microsoft.CPlat.Core.RunCommandLinux" version="1.0.3">
<RuntimeSettings seqNo="0">{
"runtimeSettings": [
{
"handlerSettings": {
"protectedSettingsCertThumbprint": "7AF139E055555FAKEINFO555558EC374DAD46370",
"protectedSettings": "*** REDACTED ***",
"publicSettings": {}
}
}
]
}</RuntimeSettings>

In the provisioning script for this host, however, this sanitizing is not done. For example, in “C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension\1.10.12\Status\0.status”, our secrets and credentials are plainly visible to everyone, including low privileged users.

This allows a malicious actor to disclose potentially sensitive information if they were to gain access to this machine. The accounts revealed could allow the attacker to further compromise a customer’s Azure environment if these credentials or accounts are re-used elsewhere.

Conclusion

Obviously, the Arc Jumpstart environment is intended to be used as a demo environment, which ideally lessens the impact of the revealed credentials — provided that users haven’t reused the service principal elsewhere in their environment. That said, it isn’t uncommon for customers to use these types of Jumpstart environments as a starting point to build out their actual production infrastructure.

We do, however, feel it’s worth being aware of this issue in the event that other logging mechanisms exist elsewhere in the Azure ecosystem, which could have more dire consequences if present in a production environment.


Logging Passwords in Plaintext in Azure Arc was originally published in Tenable TechBlog on Medium, where people are continuing the conversation by highlighting and responding to this story.

Microsoft Azure Site Recovery DLL Hijacking

12 July 2022 at 16:58

Azure Site Recovery is a suite of tools aimed at providing disaster recovery services for cloud resources. It provides utilities for replication, data recovery, and failover services during outages.

Tenable Research has discovered that this service is vulnerable to a DLL hijacking attack due to incorrect directory permissions. This allows any low-privileged user to escalate to SYSTEM level privileges on hosts where this service is installed.

Microsoft has assigned this issue CVE-2022–33675 and rated it a severity of Important with a CVSSv3 score 7.8. Tenable’s advisory can be found here. Microsoft’s post regarding this issue can be found here. Additionally, Microsoft is expected to award a $10,000 bug bounty for this finding.

The Flaw

The cxprocessserver service runs automatically and with SYSTEM level privileges. This is the primary service for Azure Site Recovery.

Incorrect permissions on the service’s executable directory (“E:\Program Files (x86)\Microsoft Azure Site Recovery\home\svsystems\transport\”) allow new files to be created by normal users. Please note that while the basic permissions show that “write” access is disabled, the “Special Permissions” still incorrectly grant write access to this directory. This can be verified by viewing the “Effective Access” granted to a given user for the directory in question, as demonstrated in the following screenshot.

This permissions snafu allows for a DLL hijacking/planting attack via several libraries used by the service binary.

Proof of Concept

For brevity, we’ve chosen to leave full exploitation steps out of this post since DLL hijacking techniques are extremely well documented elsewhere.

A malicious DLL was created to demonstrate the successful hijack via procmon.

Under normal circumstances, the loading of ktmw32.dll looks like the following:

With our planted DLL, the following can be observed:

This allows an attacker to elevate from an arbitrary, low-privileged user to SYSTEM. During the disclosure process, Microsoft confirmed this behavior and has created patches accordingly.

Conclusion

DLL hijacking is quite an antiquated technique that we don’t often come across these days. When we do, impact is often quite limited due to lack of security boundaries being crossed. MSRC lists several examples in their blog post discussing how they triage issues that make use of this technique.

In this case, however, we were able to cross a clear security boundary and demonstrated the ability to escalate a user to SYSTEM level permissions, which shows the growing trend of even dated techniques finding a new home in the cloud space due to added complexities in these sorts of environments.

As this vulnerability was discovered in an application used for disaster recovery, we are reminded that had this been discovered by malicious actors, most notably ransomware groups, the impact could have been much wider reaching. Ransomware groups have been known to target backup files and servers to ensure that a victim is forced into paying their ransom and unable to restore from clean backups. We strongly recommend applying the Microsoft supplied patches as soon as possible to ensure your existing deployments are properly secured. Microsoft has taken action to correct this issue, so any new deployments should not be affected by this flaw.


Microsoft Azure Site Recovery DLL Hijacking was originally published in Tenable TechBlog on Medium, where people are continuing the conversation by highlighting and responding to this story.

KDU v1.2 release and the wonderful world of Microsoft incoherency

By: hfiref0x
19 February 2022 at 09:36

It's been a while since last KDU update and thanks to Artem Baranov from Kaspersky my attention is again on it. The new 1.2 release contain eight new providers and set of additional changes that were required for new providers work. Here is list of new providers added, the details on each are following:

  • GMER "antirootkit"
  • Dell BIOS Utility (assigned CVE-2021-21551)
  • Mimikatz "Mimidrv"
  • Process Hacker "KProcessHacker2"
  • Process Explorer "ProcExp152"
  • Dell BIOS Utility (assigned CVE-2021-36276)
  • Cheat Engine
  • ASUS GPU Tweak II/III (EneTech next-gen)
And after describing new providers we will take a tour into wonderful world of Microsoft incoherency with their newest Win10/Win11 drivers blacklist managed by CI.dll

Providers description 

(number is ID in KDU database)

15. GMER "antirootkit"

Pic 1. What could possible go wrong here

GMER "antirootkit", I'm familiar with this software since it birth and introduction by author (Przemyslaw Gmerek) on SysInternals forums during Rustock's first variants most active period. Since it first release it was a mediocre software with limited capabilities to detect or remove anything despite author claims (he still has a dedicated gallery on his long forgotten site). Since I was developing the same toolset during that time I of course reverse-engineered GMER to find out if there is anything interesting in it. It sounds fun but this is exactly how things were going in the 2005-2010 anywhere with tools developed by enthusiasts. Amount of copy-pasted techniques and code from different authors in different tools of this time is tremendous. GMER driver doesn't surprised me and except obvious bugs I didn't found anything else interesting in it, except number of simple ways how to completely make it blind in case of rootkit detection (we later implemented one of in our laboratory rootkit called Unreal so Gmerek was forced to do an emergency update 😅). Remember, it was year 2006 and Windows XP was all around and shiny again after general Vista fuckup. Entire class of this software died around 2011-2013 so I was surprised that GMER actually managed not only survive but move to x64 world. Ohh, better he doesn't. The actual x64 driver made of copy-paste from x86 version with few things adjusted to make it work on x64 and some features that are bound to x86 only completely removed. For some unknown reason it still has a branches of code that doesn't make any sense on x64, that shows how actually author didn't care about final product. Since acquiring by Avast their Avast MBR tool contain exact the same driver from GMER (because it's powered by "GMER technology", this is a fucking rofl yeah). From current perspective this driver is a wormhole and I'm surprised no one actually tried to exploit it for a fancy CVE id, almost just like Trend Micro tool highlighted in one of my previous posts. For KDU usage the most prominent features of GMER are arbitrary kernel virtual memory read and write. This is not a bug, it is intentionally created mess so GMER can read/write kernel memory via it's process. This feature implemented via MDL mapping and accessible with dedicated IOCTL with simple data structure. One important note is that before calling this (or any other IOCTL) you have to talk with GMER driver first to let it know it was "initialized". This is done with a special IOCTL. Note that GMER driver sets exclusive flag when creating it device object, however when application crash driver stays in memory and accessible for everyone.

TL;DR - current GMER is completely useless (and dangerous due to multiple bugs, just look on pic 1 - few seconds before BSOD) in terms of "rootkit detection" usage and represent a security risk by containing Windows security bypasses available without any proper verification of caller nor access checks. 

16. Dell BIOS Utility (assigned CVE-2021-21551)

This one is pretty simple and well described in CVE entry. This is a typical flaw in giveio-type drivers. It has memmove with completely user controlled parameters send by special IOCTL.  Such "features" aren't so rare in the wonderful world of hardware vendors drivers.

17. Mimikatz "Mimidrv"

This is auxiliary driver from Mimikatz tool which is open-source. Mimikatz is a well known tool and a lot of people found it damn useful. Well I'm not one of them. Speaking of mimidrv - it has full source available and by opening this source you will want to close it ASAP to not hurt your eyes with amount of shitcode you will face. It's a complete bugged wormhole which has number of built binaries with different versions all signed with a valid certificate. No wonder Microsoft banned this certificate in their HVCI blocklist which we will discuss later. We are interested here in arbitrary kernel virtual memory read/write IOCTL's, in fact they are almost the same as in GMER. You don't need any special preconditions to start using mimidrv. Here is the details on other features of mimidrv - Mimidrv In Depth: Exploring Mimikatz’s Kernel Driver if you are interested.

18. Process Hacker "KProcessHacker2"

It is famous tool and I remember how it was born. Process Hacker come at SysInternals forum with wj32 in the late 00s in form of open source task manager replacement written in C#. It was immediately criticized for this by forum members and after some reconsiderations wj32 ported it on more suitable programming language (thankfully there wasn't any cancer like Rust popular that days). PH roots from Windows XP era with same design and philosophy. That's how it started and worked just fine until Turla malware group widely popularized BYOVD (Bring Your Own Vulnerable Driver) attacks in 2014-2015. The mentioned PH driver KProcessHacker2 was abused by multiple actors starting from malware and ending up with cheat community. This followed with wave of antivirus detections and game bans. All because of this tool initial design and philosophy from Windows XP era. That is why it was full of wormhole functionality and still have it up-to-date. What is so unique in this driver? It provides a set of IOCTL's which work as Windows API replacements for several key to the Windows security functions. Just a few of them for example: OpenProcess, OpenThread, DuplicateHandle, TerminateThread, TerminateProcess, Set/GetThreadContext, Read/WriteProcessMemory. Natural hackbox isn't it? Earlier versions of PH code (which all nicely written and well documented) even contain remarks where author hopes that this driver client "is not a virus" so wj32 clearly predicted things can go worse 😏 We will go back to PH in the end of this post. For KDU tasks this driver maybe not looking good at first glance (it looks like more suitable for malware usage 😂), but then if you look on the things from a different perspective - hell yeah. Here is why - starting from ancient Windows NT versions up to latest Windows 10 release "System" process keeps handle to physical memory section. It was abused before for physical memory access and later Microsoft banned it from user mode usage by setting object header flag -> kernel only access so you can't open new handle for this section from the user mode. Later MS added protected processes feature which additionally blocked exploitation because you can't open "System" process with sufficient rights. And here Process Hacker driver comes to the rescue with it hackbox IOCTL's allowing us: open full process handle for "System" process, duplicate physical memory section handle to our process with same full access rights. Further is trivial. Important note about fancy new Windows 10 rebrand called Windows 11. There is no physical memory section handle in "System" process as I observed and it is too boring to figure out is it intentional or need any preconditions to make it popup again - you may consider this as homework.

19. Process Explorer "ProcExp152"

Rival of previous task manager. Or previous task manager is a rival to this, or new Windows 10/11 taskmanager is a rival to both or vice versa or..., I don't really follow this "task manager market war" which is a complete bullshit, just the fact that Process Explorer existed long before PH release and PH "release to public" place was Process Explorer developers forums. This is a small handy tool developed by Mark Russinovich before his acquiring by Microsoft and abandoning all his tools (they are now out-sourced to some Microsoft geniuses who decided to remake classic UI with new over overstretched buttons and idiotic bitmaps ruining your old UI experience, and oh-ah "dark mode" I forgot about it). Process Explorer driver provide limited set of features that works almost the same as hackbox from PH. Have you heard about AV detecting Process Explorer as malware? I didn't, maybe because it is signed by Microsoft?😄 Anyway, this driver does have access checks implemented at dispatch routine so it fits into Microsoft wonderland of what they call "security boundaries". It doesn't really matter for BYOVD, this driver allows process opening, handle duplication, process termination and more. It is used in KDU in a similar manner as KProcessHacker2 driver. Oh, it even re-used next by KDU as placeholder for the final shellcode, what an irony.

20. Dell BIOS Utility (assigned CVE-2021-36276)

The same as previous Dell driver except it has different steps required for loading and new device name. In fact this is example of "fix" similar to that I described in my previous blogpost. TL;DR Dell fixed nothing and posed this driver update as ultimate fix for previously reported vulnerabilities. KDU exploits 2.5 version driver as I didn't bothered to find 2.7, but from all the description etc it will work the same way on 2.7 you only need to change device name.

21. Cheat Engine

Pic 2. Cheat Engine 7.4

Infamous open-source tool mostly used for game cheating and cracking. Has a kernel mode component called DBK (DarkByte Kernel?) which is a wormhole by design with WHQL signature, yeah. This driver abused by malware in recent GhostEmperor attacks. KDU uses similar pattern to write and execute code in kernel mode. Cheat Engine author tried to complicate his driver usage by 3rd parties (most likely by other cheat programs) by introducing few pseudo-security checks implemented on driver side. None of them can be considered as sufficient and mentioned above malware fully bypass them. KDU uses driver from the up-to-date Cheat Engine 7.4 package and proxy application "kernelmodeunloader.exe" from the same package. This driver is in HVCI blocklist. Warning to these who want to try: while installing Cheat Engine package (from official site) may install you a bunch of scamware if you won't pay attention to installation process and just spam "Next" clicks. Note that Cheat Engine driver has some problems with Windows 7, so it may not work or load here.

Pic 3. Cheat Engine DBK load failure, Windows 7



22. ASUS GPU Tweak II/III (EneTech next-gen)

It is implementation of what is stated in my previous blogpost. Nothing changed since that time, ASUS continuously use this trash in a number of it software products up to date. Side note, they also introduced new driver which looks like heavy remake of original WinIO with most of it dangerous features stripped, however not all. It is a something to investigate later.

HVCI blocklist or welcome to wonderful world of Microsoft incoherency


This feature introduced with HVCI on Windows 10. It is implemented as blocklist stored in \systemroot\system32\codeintegrity\driversipolicy.p7b file as certificate blob and specific code at CI.DLL to manage it. Decoding this "driverspolicy" data maybe accomplished with the following PowerShell script -> https://gist.github.com/mattifestation/92e545bf1ee5b68eeb71d254cec2f78e. Microsoft maintains current state of this list on github -> https://github.com/MicrosoftDocs/windows-itpro-docs/blob/public/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-driver-block-rules.md. This blocklist is loaded and parsed by CI.DLL in kernel mode and invoked when HVCI is enabled (Core Isolation -> Memory Integrity) and something is trying to load driver. If this driver (authenticode hash, page hash, filename from version block, filename and version range from version block) found in blocklist Windows will deny it loading and log event. Presumable this list will be updated and each new Windows 1X "release" will bring brand new blocklist. Or they even managed to do it auto updating didn't checked that, at least previous Windows 10 versions doesn't seems update it since install.

Lets take Process Hacker discussed above, but latest version, and try to load it as admin with HVCI enforced:

Pic 4. HVCI enforced block of kprocesshacker.sys


With event 5038 added to the system security event log: 

Code integrity determined that the image hash of a file is not valid.  The file could be corrupt due to unauthorized modification or the invalid hash could indicate a potential disk device error.

File Name: \Device\HarddiskVolume3\ProcessHacker\kprocesshacker.sys

and NTSTATUS codes like STATUS_IMAGE_CERT_REVOKED and STATUS_DRIVER_UNABLE_TO_LOAD. This is actual Process Hacker v3.0 with valid digital signature and KProcessHacker3 which is immune to previous abuse by malware and cheaters. 

Why is this happening or welcome to wonderful world of Microsoft incoherency.

Microsoft added Process Hacker (PH) to HVCI blocklist just recently. There are no live examples of Process Hacker v3 abuse by malware except one from Crowdstrike dated back to 2019 and updated in the Dec 2021, https://www.crowdstrike.com/blog/how-doppelpaymer-hunts-and-kills-windows-processes/. This post gives you a brief to supposedly PH driver malicious usage involving full bypass of it integrated client verification introduced in 2.39 and still used in 3.0+. From that post you will learn that over-engineered approach which is used almost everywhere in PH code doesn't guarantee security and wormhole features are still can be used by 3rd party if they really want to. From my point of view malware authors has nothing else to do by choosing Process Hacker driver as their "provider" because:
  1. There are exist alternatives with much simpler (or none at all) verification logic, using them you can achieve the same "terminator" features;
  2. Process Hacker already signatured by various FakeAV as PUP/Tool/HackTool (or TrojanMulDrop lol) because it different old versions are used by malware and they share scan patterns.
Or they just wanted to piss-off PH authors showing them bypass of it over-engineered verification. Why then Microsoft doesn't considers its own Process Explorer (PE) driver as malicious security breaking tool? Lets leave aside "because it Microsoft signed lol" or "because it fits into security boundaries, have you saw secure device and SePrivilegeCheck?". If you compare how exactly PH and PE drivers does their "process" management you will notice that PH actually does it on lower level than PE. There are other functionally which is also should not exist at all - like duplicating handles, write/reading arbitrary processes memory, changing thread contexts etc. But lets start with simple thing, how PH and PE both acquire process handles. 

PH uses PsLookupProcessThreadByCid/PsLookupProcessByProcessId and ObOpenObjectByPointer. This allows it to skip ordinary access checks, ETW logging and... bypass some of the security products relying on filtering. It is basically reimplemented ntoskrnl ZwOpenProces->PsOpenProcess function with all the Se validation replaced with PH client/call verification. In comparison PE simple calls ZwOpenProcess with GENERIC_ALL desired access value. Both approaches are terrible piece of shit and comes from Windows XP era. If you need a handle to process/thread etc - use usermode call, that's is the only solid way to guarantee security and audit. If you still insist on accessing protected processes then entire operation should only take place in kernel after Windows security verification without returning anything important to usermode. Any termination/memory read/write from driver should be banned at all. This will however turn off "hacking" features of products as they won't be able to open/read/write everything. Sorry guys but this is how Windows now designed - if you not a part of trusted system code you can't access what ever you want. And there we have a dilemma - two drivers with wormhole functionality ideal for BYOVD attacks. One maintained open-source project, second proprietary Microsoft code without updates for decades. Both used by malware including APT. One in HVCI blocklist, second nope. I call this bullshit, Microsoft. What about PH, guys you are fucking process manager with extended features, not a Windows subsystem to replace or reinvent the MS security wheel just because you have nothing else to do and want to practice with system programming. Your "multi-purposing" is actually playing against you and serves no other purpose. You already removed a lot of "hacking" code from Process "Hacker" and still have a lot to remove/rework. Leave all this "hacking" to where it started - in the Windows XP era.

Another piece in this blocklist that attracted my attention is a number of strange drivers MS added seems by lurking on unknowncheats.me forum, including leaked certificates. Well it is good to know you lurk on most currently famous forum dedicated to kernel mode rootkits (what an irony yeah).

VBoxDrv innotek entry brings good old memories of Turla and later DSEFix/TDL. The only question here is why innotek only. Unlike popular opinion the exploit used by Turla group wasn't previously disclosed and therefore fixed in next versions, so basically it was a zeroday. This entire confuse makes you think that VirtualBox has only innotek signed Turla-style exploitable drivers. Meanwhile I would remember you that Sun acquired innotek GmbH in 2008 and later VirtualBox versions came out signed by Sun certificate. Since this vulnerability in vboxdrv wasn't fixed - all vboxdrv drivers at least up to 3.0 version are equally vulnerable and can be easily adopted to be used like in DSEFix or TDL 😉 (which was already done by some Chinese APT few years ago). Strange that this is not noticed by Microsoft.

Pic 5. The old the new thing

Ideally this blocklist should be twice or triple size bigger with only what is available on public today. No iobit, zemana fakeav drivers, no mihoyo, other anticheat crapware, no nVidia trash, no endless MSI packs of crap. Are you kidding, Microsoft? This is all available and exploitable. Right here, right now. Stop being a slowpoke, I've cookie for you.

People That

By: hfiref0x
5 November 2020 at 06:32

Succ 

(c) Andrea Allievi aka aall64
Pic 1. What is all about.

When you interact with software and it developing company (in face of some developers) sometimes you meet a bunch of company fanatics. Those are people who actually jumped into the wagon not so long time ago but already think they are part/have rights on anything - they are deeply identify themselves with company they are working now. It is of course true if we take this from the commercial point of view and inter company communications. From the other (public) side this creates a problem of fanaticism. It is when you are become brainwashed at that level so you start to see things that does not exist. This depends on people but unfortunately it is a common trend. And they are not necessary devil advocates.

For example, any criticism targeting products of their company they take with pain in their own asses. And it does not matter if this criticism is valid or not.

Usually it starts with classic sentence - "If you don't %verb% %my company/product% then why you still %verb% it". E.g. - "if you don't like Windows then why you still use it". Such sentences used as a typical indicator of upcoming demagogy attack next.

So what is all about?

Meet the proud Microsoft fanatic who are unhappy with recent blogpost I made.

Pic 2. Meet aall64.
 

Long story short - he read (as he said) that https://swapcontext.blogspot.com/2020/10/uacme-35-wd-and-ways-of-mitigation.html. This ignited his butt very well and he went to me expressing his deep displeasure along with the demonstration of a rich imagination and the ability to see what is not exist.

Who is this guy? It is Microsoft employee that formerly worked in PrevX. Infamous MD5 calculators NextGen AV developing company with always lurking copy-pasters on various forums and EraserHW (Marco G.) as main PR man at charge who was linked to the fake overestimated malware campaigns of Gromozon/LinkOptimizer in 2006. This toxic active has been acquired by Webroot in the end of 2010 and later went to special hell dedicated for hash calculators NextGen AV. Andrea is a current co-author of that yet another full of water Russinovich book edition (which 3rd edition copy I accidentally bought in 2006, when actually liked it those days). Also he is a "proud Microsoft guy" (as he said). I know about him 10 years. This guy come up to kernelmode.info in 2010 with his pet project called AntiTdl. He come here after advice from wilderssecurity.com forums where he initially posted his project. Casuals from that forum wasn't happy with it (they wasn't able to deal with it), so following their advice he registered on kernelmode.info and posted stuff. That is how we meet. This project was already out-dated, extremely bugged and was basically useless. However no one said a word against it, and KM community (including me) welcomed and provided all possible support to this author. Because sharing knowledge is always great idea. You can find this in kernelmode.info by searching with google "antitdl site:kernelmode.info". Next he come up to TDL4 reversing and other kind of bootkits, along the way he did plagiarism on existing content (https://twitter.com/Fyyre/status/155383565943701504). 

Pic 3. 2 years delay reply, rofl.
 

Next there was something about PatchGuard (another doubtful technology from MS) and he ended up surprisingly in Microsoft. I actually glad that he made his way from a mediocre half-fake AV company to the MSFT, good job.

Here is what exactly he does not like in my mentioned article about UAC. I specifically asked him about this because his initial claims has nothing to do with actual article context - it simple does not have anything he said. This is what he answered to me in a DM which I next made public.

Pic 4. "I see dead people everywhere".

To make it more readable, here is the part of article as screenshot.

Pic 5. Comedy Section Bonus part screenshot.

First, lets begin with "edited" statement.

His first tweet with accusations was 29 October 2020, it is on picture 2. The DM conversation take place 31 October 2020. So following this guy logic (I really hope it is not the same when he code anything), I edited material in between of his first tweet (29 Oct) and my answer to it few hours later.

Unfortunately to this guy there is a Google Cache of my blogpost available from 27 October -> https://webcache.googleusercontent.com/search?q=cache:_dzbCypL044J:https://swapcontext.blogspot.com/2020/+&cd=5&hl=ru&ct=clnk&gl=en&client=firefox-b-d (this google cache page saved to WebArchive additionally now).

This article has never been edited after publication. I have no habit of changing anything after it became public, except and only if I fix typos. However, if you remember his glorious way to Microsoft, you should remember this guy already familiar with plagiarism so probably he just projected his own habits on me.

Since we are dealing with a typical fanatic he still can claim that he read it before 27 Oct (and I don't have google cache earlier that date), so I magically got notified about that reading fact, magically imagined his reaction and edited content doing that in a stealth mode. It is ridiculous but from this guy I can expect anything now.

The context of the bonus of this article is describing typical social media behavior taking place each year. So this part "Woohoo, Windoze Byp@$$3d M1cr0$0ft SuXx!" is not my words and not a projection of my options. It is what people say and mean. I don't know Andrea aka aall86, are you seriously thinking you are dealing with a sort of 14 year old script-kiddie here? What is the 86 here btw, year of birth or IQ rate?

The last part about "s3curity r3s3arch3rs", I've to decipher to Andrea, is about mister "DimopoulosElias" a guy who stuck in copy-pasta, use google for more info. Now put here your imagined "MiCro$oft sucks" and try to read this sentence again. It actually will lose all sense.

All these lying accusations is just weak attempt to hide actual reason of Andrea butt ignition. If you read this article it contains a lot of criticism. And harsh part related to Windows Defender. It is not the first time Andrea come ups trying to defend this crappy Microsoft imposed product. The last time he was defending that brain-dead Microsoft employees who multiple times signatured Process Hacker - popular open source software. So this guy read this vertically, butt ignited and he hang on the most notable sentences for him from this article (the magic number of 86 don't forget) completely ignoring not only their context but actual text, because I don't know what kind of reading skills you should have to read "s3curity r3s3arch3rs" as "MiCro$oft sucks" 😆

Pic 6. DM part


Yes, you just a dumbfuck fanatic 👌. Mister aall86 insisted during "conversation" via DM so he got a dedicated blogpost, achievement unlocked.

Conclusions:

1. Always backup your original content with ability for others track any changes in it. You can use WebArchive and save your page after publication or copy contents to the some public git repository, so everybody will be able do a simple fact-check and track exact changes.

2. PrevX as indicator in people portfolio. Take such guys with a caution. Yes it is a sad thing but almost all of them I know ended up to be like this guy. It is PrevX curse and knowing this company past and key personalities of it - I should not be that surprised.

3. Since all his content now viewed through the prism of the above events - as of the "book" he co-writes - well, thankfully, it is now 2020 and not 2001-2005 so if you for some unknown reason still want to learn anything(new) about Windows internals you can always find a alternate way instead of this water pool. Remember one simple thing - since beginning, this book was a perfect illustration of Microsoft inability to write somewhat decent public documentation, MSDN is when they do this not because they want to, but because they have to. That's explains failing quality of available content. And to compensate this here we came up with sort of fan-fictions which are approved and welcomed by company.

Microsoft Office Vulnerabilities Used to Distribute Zyklon Malware in Recent Campaign

17 January 2018 at 17:00

Introduction

FireEye researchers recently observed threat actors leveraging relatively new vulnerabilities in Microsoft Office to spread Zyklon HTTP malware. Zyklon has been observed in the wild since early 2016 and provides myriad sophisticated capabilities.

Zyklon is a publicly available, full-featured backdoor capable of keylogging, password harvesting, downloading and executing additional plugins, conducting distributed denial-of-service (DDoS) attacks, and self-updating and self-removal. The malware may communicate with its command and control (C2) server over The Onion Router (Tor) network if configured to do so. The malware can download several plugins, some of which include features such as cryptocurrency mining and password recovery, from browsers and email software. Zyklon also provides a very efficient mechanism to monitor the spread and impact.

Infection Vector

We have observed this recent wave of Zyklon malware being delivered primarily through spam emails. The email typically arrives with an attached ZIP file containing a malicious DOC file (Figure 1 shows a sample lure).

The following industries have been the primary targets in this campaign:

  • Telecommunications
  • Insurance
  • Financial Services


Figure 1: Sample lure documents

Attack Flow

  1. Spam email arrives in the victim’s mailbox as a ZIP attachment, which contains a malicious DOC file.
  2. The document files exploit at least three known vulnerabilities in Microsoft Office, which we discuss in the Infection Techniques section. Upon execution in a vulnerable environment, the PowerShell based payload takes over.
  3. The PowerShell script is responsible for downloading the final payload from C2 server to execute it.

A visual representation of the attack flow and execution chain can be seen in Figure 2.


Figure 2: Zyklon attack flow

Infection Techniques

CVE-2017-8759

This vulnerability was discovered by FireEye in September 2017, and it is a vulnerability we have observed being exploited in the wild.

The DOC file contains an embedded OLE Object that, upon execution, triggers the download of an additional DOC file from the stored URL (seen in Figure 3).


Figure 3: Embedded URL in OLE object

CVE-2017-11882

Similarly, we have also observed actors leveraging another recently discovered vulnerability (CVE-2017-11882) in Microsoft Office. Upon opening the malicious DOC attachment, an additional download is triggered from a stored URL within an embedded OLE Object (seen in Figure 4).


Figure 4: Embedded URL in OLE object


Figure 5: HTTP GET request to download the next level payload

The downloaded file, doc.doc, is XML-based and contains a PowerShell command (shown in Figure 6) that subsequently downloads the binary Pause.ps1.


Figure 6: PowerShell command to download the Pause.ps1 payload

Dynamic Data Exchange (DDE)

Dynamic Data Exchange (DDE) is the interprocess communication mechanism that is exploited to perform remote code execution. With the help of a PowerShell script (shown in Figure 7), the next payload (Pause.ps1) is downloaded.


Figure 7: DDE technique used to download the Pause.ps1 payload

One of the unique approaches we have observed is the use of dot-less IP addresses (example: hxxp://258476380).

Figure 8 shows the network communication of the Pause.ps1 download.


Figure 8: Network communication to download the Pause.ps1 payload

Zyklon Delivery

In all these techniques, the same domain is used to download the next level payload (Pause.ps1), which is another PowerShell script that is Base64 encoded (as seen in Figure 8).

The Pause.ps1 script is responsible for resolving the APIs required for code injection. It also contains the injectable shellcode. The APIs contain VirtualAlloc(), memset(), and CreateThread(). Figure 9 shows the decoded Base64 code.


Figure 9: Base64 decoded Pause.ps1

The injected code is responsible for downloading the final payload from the server (see Figure 10). The final stage payload is a PE executable compiled with .Net framework.


Figure 10: Network traffic to download final payload (words.exe)

Once executed, the file performs the following activities:

  1. Drops a copy of itself in %AppData%\svchost.exe\svchost.exe and drops an XML file, which contains configuration information for Task Scheduler (as shown in Figure 11).
  2. Unpacks the code in memory via process hollowing. The MSIL file contains the packed core payload in its .Net resource section.
  3. The unpacked code is Zyklon.


Figure 11: XML configuration file to schedule the task

The Zyklon malware first retrieves the external IP address of the infected machine using the following:

  • api.ipify[.]org
  • ip.anysrc[.]net
  • myexternalip[.]com
  • whatsmyip[.]com

The Zyklon executable contains another encrypted file in its .Net resource section named tor. This file is decrypted and injected into an instance of InstallUtiil.exe, and functions as a Tor anonymizer.

Command & Control Communication

The C2 communication of Zyklon is proxied through the Tor network. The malware sends a POST request to the C2 server. The C2 server is appended by the gate.php, which is stored in file memory. The parameter passed to this request is getkey=y. In response to this request, the C2 server responds with a Base64-encoded RSA public key (seen in Figure 12).


Figure 12: Zyklon public RSA key

After the connection is established with the C2 server, the malware can communicate with its control server using the commands shown in Table 1.

Command

Action

sign

Requests system information

settings

Requests settings from C2 server

logs

Uploads harvested passwords

wallet

Uploads harvested cryptocurrency wallet data

proxy

Indicates SOCKS proxy port opened

miner

Cryptocurrency miner commands

error

Reports errors to C2 server

ddos

DDoS attack commands

Table 1: Zyklon accepted commands

The following figures show the initial request and subsequent server response for the “settings” (Figure 13), “sign” (Figure 14), and “ddos” (Figure 15) commands.


Figure 13: Zyklon issuing “settings” command and subsequent server response


Figure 14: Zyklon issuing “sign” command and subsequent server response


Figure 15: Zyklon issuing “ddos” command and subsequent server response

Plugin Manager

Zyklon downloads number of plugins from its C2 server. The plugin URL is stored in file in following format:

  • /plugin/index.php?plugin=<Plugin_Name>

The following plugins are found in the memory of the Zyklon malware:

  • /plugin/index.php?plugin=cuda
  • /plugin/index.php?plugin=minerd
  • /plugin/index.php?plugin=sgminer
  • /plugin/index.php?plugin=socks
  • /plugin/index.php?plugin=tor
  • /plugin/index.php?plugin=games
  • /plugin/index.php?plugin=software
  • /plugin/index.php?plugin=ftp
  • /plugin/index.php?plugin=email
  • /plugin/index.php?plugin=browser

The downloaded plugins are injected into: Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe.

Additional Features

The Zyklon malware offers the following additional capabilities (via plugins):

Browser Password Recovery

Zyklon HTTP can recover passwords from popular web browsers, including:

  • Google Chrome
  • Mozilla Firefox
  • Internet Explorer
  • Opera Browser
  • Chrome Canary/SXS
  • CoolNovo Browser
  • Apple Safari
  • Flock Browser
  • SeaMonkey Browser
  • SRWare Iron Browser
  • Comodo Dragon Browser
FTP Password Recovery

Zyklon currently supports FTP password recovery from the following FTP applications:

  • FileZilla
  • SmartFTP
  • FlashFXP
  • FTPCommander
  • Dreamweaver
  • WS_FTP
Gaming Software Key Recovery

Zyklon can recover PC Gaming software keys from the following games:

  • Battlefield
  • Call of Duty
  • FIFA
  • NFS
  • Age of Empires
  • Quake
  • The Sims
  • Half-Life
  • IGI
  • Star Wars
Email Password Recovery

Zyklon may also collect email passwords from following applications:

  • Microsoft Outlook Express
  • Microsoft Outlook 2002/XP/2003/2007/2010/2013
  • Mozilla Thunderbird
  • Windows Live Mail 2012
  • IncrediMail, Foxmail v6.x - v7.x
  • Windows Live Messenger
  • MSN Messenger
  • Google Talk
  • GMail Notifier
  • PaltalkScene IM
  • Pidgin (Formerly Gaim) Messenger
  • Miranda Messenger
  • Windows Credential Manager
License Key Recovery

The malware automatically detects and decrypts the license/serial keys of more than 200 popular pieces of software, including Office, SQL Server, Adobe, and Nero.

Socks5 Proxy

Zyklon features the ability to establish a reverse Socks5 proxy server on infected host machines.

Hijack Clipboard Bitcoin Address

Zyklon has the ability to hijack the clipboard, and replaces the user’s copied bitcoin address with an address served up by the actor’s control server.

Zyklon Pricing

Researchers identified different versions of Zyklon HTTP being advertised in a popular underground marketplace for the following prices:

  • Normal build: $75 (USD)
  • Tor-enabled build: $125 (USD)
  • Rebuild/Updates: $15 (USD)
  • Payment Method: Bitcoin (BTC)

Conclusion

Threat actors incorporating recently discovered vulnerabilities in popular software – Microsoft Office, in this case – only increases the potential for successful infections. These types of threats show why it is very important to ensure that all software is fully updated. Additionally, all industries should be on alert, as it is highly likely that the threat actors will eventually move outside the scope of their current targeting.

At this time of writing, FireEye Multi Vector Execution (MVX) engine is able to recognize and block this threat. Table 2 lists the current detection and blocking capabilities by product.

Detection Name

Product

Action

POWERSHELL DOWNLOADER D (METHODOLOGY)

HX

Detect

SUSPICIOUS POWERSHELL USAGE (METHODOLOGY)

HX

Detect

POWERSHELL DOWNLOADER (METHODOLOGY)

HX

Detect

SUSPICIOUS EQNEDT USAGE (METHODOLOGY)

HX

Detect

TOR (TUNNELER)

HX

Detect

SUSPICIOUS SVCHOST.EXE (METHODOLOGY)

HX

Detect

Malware.Binary.rtf

EX/ETP/NX

Block

Malware.Binary

EX/ETP/NX

Block

FE_Exploit_RTF_CVE_2017_8759

EX/ETP/NX

Block

FE_Exploit_RTF_CVE201711882_1

EX/ETP/NX

Block

Table 2: Current detection capabilities by FireEye products

Indicators of Compromise

The contained analysis is based on the representative sample lures shown in Table 3.

MD5

Name

76011037410d031aa41e5d381909f9ce

accounts.doc

4bae7fb819761a7ac8326baf8d8eb6ab

Courrier.doc

eb5fa454ab42c8aec443ba8b8c97339b

doc.doc

886a4da306e019aa0ad3a03524b02a1c

Pause.ps1

04077ecbdc412d6d87fc21e4b3a4d088

words.exe

Table 3: Sample Zyklon lures

Network Indicators
  • 154.16.93.182
  • 85.214.136.179
  • 178.254.21.218
  • 159.203.42.107
  • 217.12.223.216
  • 138.201.143.186
  • 216.244.85.211
  • 51.15.78.0
  • 213.251.226.175
  • 93.95.100.202
  • warnono.punkdns.top

Cerber: Analyzing a Ransomware Attack Methodology To Enable Protection

18 July 2016 at 12:00

Ransomware is a common method of cyber extortion for financial gain that typically involves users being unable to interact with their files, applications or systems until a ransom is paid. Accessibility of cryptocurrency such as Bitcoin has directly contributed to this ransomware model. Based on data from FireEye Dynamic Threat Intelligence (DTI), ransomware activities have been rising fairly steadily since mid-2015.

On June 10, 2016, FireEye’s HX detected a Cerber ransomware campaign involving the distribution of emails with a malicious Microsoft Word document attached. If a recipient were to open the document a malicious macro would contact an attacker-controlled website to download and install the Cerber family of ransomware.

Exploit Guard, a major new feature of FireEye Endpoint Security (HX), detected the threat and alerted HX customers on infections in the field so that organizations could inhibit the deployment of Cerber ransomware. After investigating further, the FireEye research team worked with security agency CERT-Netherlands, as well as web hosting providers who unknowingly hosted the Cerber installer, and were able to shut down that instance of the Cerber command and control (C2) within hours of detecting the activity. With the attacker-controlled servers offline, macros and other malicious payloads configured to download are incapable of infecting users with ransomware.

FireEye hasn’t seen any additional infections from this attacker since shutting down the C2 server, although the attacker could configure one or more additional C2 servers and resume the campaign at any time. This particular campaign was observed on six unique endpoints from three different FireEye endpoint security customers. HX has proven effective at detecting and inhibiting the success of Cerber malware.

Attack Process

The Cerber ransomware attack cycle we observed can be broadly broken down into eight steps:

  1. Target receives and opens a Word document.
  2. Macro in document is invoked to run PowerShell in hidden mode.
  3. Control is passed to PowerShell, which connects to a malicious site to download the ransomware.
  4. On successful connection, the ransomware is written to the disk of the victim.
  5. PowerShell executes the ransomware.
  6. The malware configures multiple concurrent persistence mechanisms by creating command processor, screensaver, startup.run and runonce registry entries.
  7. The executable uses native Windows utilities such as WMIC and/or VSSAdmin to delete backups and shadow copies.
  8. Files are encrypted and messages are presented to the user requesting payment.

Rather than waiting for the payload to be downloaded or started around stage four or five of the aforementioned attack cycle, Exploit Guard provides coverage for most steps of the attack cycle – beginning in this case at the second step.

The most common way to deliver ransomware is via Word documents with embedded macros or a Microsoft Office exploit. FireEye Exploit Guard detects both of these attacks at the initial stage of the attack cycle.

PowerShell Abuse

When the victim opens the attached Word document, the malicious macro writes a small piece of VBScript into memory and executes it. This VBScript executes PowerShell to connect to an attacker-controlled server and download the ransomware (profilest.exe), as seen in Figure 1.

Figure 1. Launch sequence of Cerber – the macro is responsible for invoking PowerShell and PowerShell downloads and runs the malware

It has been increasingly common for threat actors to use malicious macros to infect users because the majority of organizations permit macros to run from Internet-sourced office documents.

In this case we observed the macrocode calling PowerShell to bypass execution policies – and run in hidden as well as encrypted mode – with the intention that PowerShell would download the ransomware and execute it without the knowledge of the victim.

Further investigation of the link and executable showed that every few seconds the malware hash changed with a more current compilation timestamp and different appended data bytes – a technique often used to evade hash-based detection.

Cerber in Action

Initial payload behavior

Upon execution, the Cerber malware will check to see where it is being launched from. Unless it is being launched from a specific location (%APPDATA%\&#60GUID&#62), it creates a copy of itself in the victim's %APPDATA% folder under a filename chosen randomly and obtained from the %WINDIR%\system32 folder.

If the malware is launched from the specific aforementioned folder and after eliminating any blacklisted filenames from an internal list, then the malware creates a renamed copy of itself to “%APPDATA%\&#60GUID&#62” using a pseudo-randomly selected name from the “system32” directory. The malware executes the malware from the new location and then cleans up after itself.

Shadow deletion

As with many other ransomware families, Cerber will bypass UAC checks, delete any volume shadow copies and disable safe boot options. Cerber accomplished this by launching the following processes using respective arguments:

Vssadmin.exe "delete shadows /all /quiet"

WMIC.exe "shadowcopy delete"

Bcdedit.exe "/set {default} recoveryenabled no"

Bcdedit.exe "/set {default} bootstatuspolicy ignoreallfailures

Coercion

People may wonder why victims pay the ransom to the threat actors. In some cases it is as simple as needing to get files back, but in other instances a victim may feel coerced or even intimidated. We noticed these tactics being used in this campaign, where the victim is shown the message in Figure 2 upon being infected with Cerber.

Figure 2. A message to the victim after encryption

The ransomware authors attempt to incentivize the victim into paying quickly by providing a 50 percent discount if the ransom is paid within a certain timeframe, as seen in Figure 3.

 

 

Figure 3. Ransom offered to victim, which is discounted for five days

Multilingual Support

As seen in Figure 4, the Cerber ransomware presented its message and instructions in 12 different languages, indicating this attack was on a global scale.

Figure 4.   Interface provided to the victim to pay ransom supports 12 languages

Encryption

Cerber targets 294 different file extensions for encryption, including .doc (typically Microsoft Word documents), .ppt (generally Microsoft PowerPoint slideshows), .jpg and other images. It also targets financial file formats such as. ibank (used with certain personal finance management software) and .wallet (used for Bitcoin).

Selective Targeting

Selective targeting was used in this campaign. The attackers were observed checking the country code of a host machine’s public IP address against a list of blacklisted countries in the JSON configuration, utilizing online services such as ipinfo.io to verify the information. Blacklisted (protected) countries include: Armenia, Azerbaijan, Belarus, Georgia, Kyrgyzstan, Kazakhstan, Moldova, Russia, Turkmenistan, Tajikistan, Ukraine, and Uzbekistan.

The attack also checked a system's keyboard layout to further ensure it avoided infecting machines in the attackers geography: 1049—Russian, ¨ 1058—Ukrainian, 1059—Belarusian, 1064—Tajik, 1067—Armenian, 1068—Azeri, (Latin), 1079—Georgian, 1087—Kazakh, 1088—Kyrgyz (Cyrillic), 1090—Turkmen, 1091—Uzbek (Latin), 2072—Romanian (Moldova), 2073—Russian (Moldova), 2092—Azeri (Cyrillic), 2115—Uzbek (Cyrillic).

Selective targeting has historically been used to keep malware from infecting endpoints within the author’s geographical region, thus protecting them from the wrath of local authorities. The actor also controls their exposure using this technique. In this case, there is reason to suspect the attackers are based in Russia or the surrounding region.

Anti VM Checks

The malware searches for a series of hooked modules, specific filenames and paths, and known sandbox volume serial numbers, including: sbiedll.dll, dir_watch.dll, api_log.dll, dbghelp.dll, Frz_State, C:\popupkiller.exe, C:\stimulator.exe, C:\TOOLS\execute.exe, \sand-box\, \cwsandbox\, \sandbox\, 0CD1A40, 6CBBC508, 774E1682, 837F873E, 8B6F64BC.

Aside from the aforementioned checks and blacklisting, there is also a wait option built in where the payload will delay execution on an infected machine before it launches an encryption routine. This technique was likely implemented to further avoid detection within sandbox environments.

Persistence

Once executed, Cerber deploys the following persistence techniques to make sure a system remains infected:

  • A registry key is added to launch the malware instead of the screensaver when the system becomes idle.
  • The “CommandProcessor” Autorun keyvalue is changed to point to the Cerber payload so that the malware will be launched each time the Windows terminal, “cmd.exe”, is launched.
  • A shortcut (.lnk) file is added to the startup folder. This file references the ransomware and Windows will execute the file immediately after the infected user logs in.
  • Common persistence methods such as run and runonce key are also used.
A Solid Defense

Mitigating ransomware malware has become a high priority for affected organizations because passive security technologies such as signature-based containment have proven ineffective.

Malware authors have demonstrated an ability to outpace most endpoint controls by compiling multiple variations of their malware with minor binary differences. By using alternative packers and compilers, authors are increasing the level of effort for researchers and reverse-engineers. Unfortunately, those efforts don’t scale.

Disabling support for macros in documents from the Internet and increasing user awareness are two ways to reduce the likelihood of infection. If you can, consider blocking connections to websites you haven’t explicitly whitelisted. However, these controls may not be sufficient to prevent all infections or they may not be possible based on your organization.

FireEye Endpoint Security with Exploit Guard helps to detect exploits and techniques used by ransomware attacks (and other threat activity) during execution and provides analysts with greater visibility. This helps your security team conduct more detailed investigations of broader categories of threats. This information enables your organization to quickly stop threats and adapt defenses as needed.

Conclusion

Ransomware has become an increasingly common and effective attack affecting enterprises, impacting productivity and preventing users from accessing files and data.

Mitigating the threat of ransomware requires strong endpoint controls, and may include technologies that allow security personnel to quickly analyze multiple systems and correlate events to identify and respond to threats.

HX with Exploit Guard uses behavioral intelligence to accelerate this process, quickly analyzing endpoints within your enterprise and alerting your team so they can conduct an investigation and scope the compromise in real-time.

Traditional defenses don’t have the granular view required to do this, nor can they connect the dots of discreet individual processes that may be steps in an attack. This takes behavioral intelligence that is able to quickly analyze a wide array of processes and alert on them so analysts and security teams can conduct a complete investigation into what has, or is, transpiring. This can only be done if those professionals have the right tools and the visibility into all endpoint activity to effectively find every aspect of a threat and deal with it, all in real-time. Also, at FireEye, we go one step ahead and contact relevant authorities to bring down these types of campaigns.

Click here for more information about Exploit Guard technology.

Two Limited, Targeted Attacks; Two New Zero-Days

14 October 2014 at 14:46

The FireEye Labs team has identified two new zero-day vulnerabilities as part of limited, targeted attacks against some major corporations. Both zero-days exploit the Windows Kernel, with Microsoft assigning CVE-2014-4148 and CVE-2014-4113 to and addressing the vulnerabilities in their October 2014 Security Bulletin.

FireEye Labs have identified 16 total zero-day attacks in the last two years – uncovering 11 in 2013 and five in 2014 so far.

Microsoft commented: “On October 14, 2014, Microsoft released MS14-058 to fully address these vulnerabilities and help protect customers. We appreciate FireEye Labs using Coordinated Vulnerability Disclosure to assist us in working toward a fix in a collaborative manner that helps keep customers safe.”

In the case of CVE-2014-4148, the attackers exploited a vulnerability in the Microsoft Windows TrueType Font (TTF) processing subsystem, using a Microsoft Office document to embed and deliver a malicious TTF to an international organization. Since the embedded TTF is processed in kernel-mode, successful exploitation granted the attackers kernel-mode access. Though the TTF is delivered in a Microsoft Office document, the vulnerability does not reside within Microsoft Office.

CVE-2014-4148 impacted both 32-bit and 64-bit Windows operating systems shown in MS14-058, though the attacks only targeted 32-bit systems. The malware contained within the exploit has specific functions adapted to the following operating system platform categories:

  • Windows 8.1/Windows Server 2012 R2
  • Windows 8/Windows Server 2012
  • Windows 7/Windows Server 2008 R2 (Service Pack 0 and 1)
  • Windows XP Service Pack 3

CVE-2014-4113 rendered Microsoft Windows 7, Vista, XP, Windows 2000, Windows Server 2003/R2, and Windows Server 2008/R2 vulnerable to a local Elevation of Privilege (EoP) attack. This means that the vulnerability cannot be used on its own to compromise a customer’s security. An attacker would first need to gain access to a remote system running any of the above operating systems before they could execute code within the context of the Windows Kernel. Investigation by FireEye Labs has revealed evidence that attackers have likely used variations of these exploits for a while. Windows 8 and Windows Server 2012 and later do not have these same vulnerabilities.

Information on the companies affected, as well as threat actors, is not available at this time. We have no evidence of these exploits being used by the same actors. Instead, we have only observed each exploit being used separately, in unrelated attacks.

 

About CVE-2014-4148

 

 

Mitigation

 

Microsoft has released security update MS14-058 that addresses CVE-2014-4148.

Since TTF exploits target the underlying operating system, the vulnerability can be exploited through multiple attack vectors, including web pages. In the past, exploit kit authors have converted a similar exploit (CVE-2011-3402) for use in browser-based attacks. More information about this scenario is available under Microsoft’s response to CVE-2011-3402: MS11-087.

 

Details

 

This TTF exploit is packaged within a Microsoft Office file. Upon opening the file, the font will exploit a vulnerability in the Windows TTF subsystem located within the win32k.sys kernel-mode driver.

The attacker’s shellcode resides within the Font Program (fpgm) section of the TTF. The font program begins with a short sequence of instructions that quickly return. The remainder of the font program section is treated as unreachable code for the purposes of the font program and is ignored when initially parsing the font.

During exploitation, the attacker’s shellcode uses Asynchronous Procedure Calls (APC) to inject the second stage from kernel-mode into the user-mode process winlogon.exe (in XP) or lsass.exe (in other OSes). From the injected process, the attacker writes and executes a third stage (executable).

The third stage decodes an embedded DLL to, and runs it from, memory. This DLL is a full-featured remote access tool that connects back to the attacker.

Plenty of evidence supports the attacker’s high level of sophistication. Beyond the fact that the attack is zero-day kernel-level exploit, the attack also showed the following:

  • a usable hard-coded area of kernel memory is used like a mutex to avoid running the shellcode multiple times
  • the exploit has an expiration date: if the current time is after October 31, 2014, the exploit shellcode will exit silently
  • the shellcode has implementation customizations for four different types of OS platforms/service pack levels, suggesting that testing for multiple OS platforms was conducted
  • the dropped malware individually decodes each string when that string is used to prevent analysis
  • the dropped malware is specifically customized for the targeted environment
  • the dropped remote access capability is full-featured and customized: it does not rely on generally available implementations (like Poison Ivy)
  • the dropped remote access capability is a loader that decrypts the actual DLL remote access capability into memory and never writes the decrypted remote access capability to disk

 

About CVE-2014-4113

 

 

Mitigation

 

Microsoft has released security update MS14-058 that addresses this vulnerability.

 

Vulnerability and Exploit Details

 

The 32-bit exploit triggers an out-of-bounds memory access that dereferences offsets from a high memory address, and inadvertently wraps into the null page. In user-mode, memory dereferences within the null page are generally assumed to be non-exploitable. Since the null page is usually not mapped – the exception being 16-bit legacy applications emulated by ntvdm.exe--null pointer dereferences will simply crash the running process. In contrast, memory dereferences within the null page in the kernel are commonly exploited because the attacker can first map the null page from user-mode, as is the case with this exploits. The steps taken for successful 32-bit exploitation are:

 

     

  1. Map the null page:

     

     

       

    1. ntdll!ZwAllocateVirtualMemory(…,BaseAddress=0x1, …)
    2.  

     

     

  2. Build a malformed win32k!tagWND structure at the null page such that it is properly validated in the kernel
  3. Trigger vulnerability
  4. Attacker’s callback in win32k!tagWND.lpfnWndProc executes in kernel-mode

     

     

       

    1. Callback overwrites EPROCESS.Token to elevate privileges
    2.  

     

     

  5. Spawns a child process that inherits the elevated access token
  6.  

 

32-bit Windows 8 and later users are not affected by this exploit. The Windows 8 Null Page protection prohibits user-mode processes from mapping the null page and causes the exploits to fail.

In the 64-bit version of the exploit, dereferencing offsets from a high 32-bit memory address do not wrap, as it is well within the addressable memory range for a 64-bit user-mode process. As such, the Null Page protection implemented in Windows versions 7 (after MS13-031) and later does not apply. The steps taken by the 64-bit exploit variants are:

 

     

  1. Map memory page:

     

     

       

    1. ntdll!ZwAllocateVirtualMemory(…)
    2.  

     

     

  2. Build a malformed win32k!tagWND structure at the mapped page such that it is properly validated in the kernel
  3. Trigger vulnerability
  4. Attacker’s callback in win32k!tagWND.lpfnWndProc executes in kernel-mode

     

     

       

    1. Callback overwrites EPROCESS.Token to elevate privileges
    2.  

     

     

  5. Spawns a child process that inherits the elevated access token
  6.  

 

64-bit Windows 8 and later users are not affected by this exploit. Supervisor Mode Execution Prevention (SMEP) blocks the attacker’s user-mode callback from executing within kernel-mode and causes the exploits to fail.

 

Exploits Tool History

 

The exploits are implemented as a command line tool that accepts a single command line argument – a shell command to execute with SYSTEM privileges. This tool appears to be an updated version of an earlier tool. The earlier tool exploited CVE-2011-1249, and displays the following usage message to stdout when run:

 

Usage:system_exp.exe cmd

 

 

Windows Kernel Local Privilege Exploits

 

The vast majority of samples of the earlier tool have compile dates in December 2009.  Only two samples were discovered with compile dates in March 2011. Although the two samples exploit the same CVE, they carry a slightly modified usage message of:

 

Usage:local.exe cmd

 

 

Windows local Exploits

 

The most recent version of the tool, which implements CVE-2014-4113, eliminates all usage messages.

The tool appears to have gone through at least three iterations over time. The initial tool and exploits is believed to have had limited availability, and may have been employed by a handful of distinct attack groups. As the exploited vulnerability was remediated, someone with access to the tool modified it to use a newer exploit when one became available. These two newer versions likely did not achieve the widespread distribution that the original tool/exploits did and may have been retained privately, not necessarily even by the same actors.

We would like to thank Barry Vengerik, Joshua Homan, Steve Davis, Ned Moran, Corbin Souffrant, Xiaobo Chen for their assistance on this research.

Hunting Down MS Exchange Attacks. Part 2 (CVE-2020–0688, CVE-2020–16875, CVE-2021–24085)

By: BI.ZONE
16 June 2021 at 12:44

The article written by Anton Medvedev, reviewed by Vadim Khrykov

Our previous article focused on the different techniques used to detect ProxyLogon exploitation. This time we will talk about the techniques used to detect other notorious MS Exchange Server vulnerabilities, namely CVE-2020–0688, CVE-2020–16875 and CVE-2021–24085.

Although these vulnerabilities are not as recent as ProxyLogon, we continue to find signs of their exploitation (including successful exploitation). The sooner an exploitation attempt is detected, the more likely it is to minimise or avoid the impact of the attack on the organisation.

Logs and Useful Events

We will use the previously mentioned MS Exchange and Windows logs as event sources.

Detecting Exploitation of CVE-2020–0688

The CVE-2020–0688 vulnerability is contained in the Exchange Control Panel (ECP) component and is related to the the server being unable to properly create unique cryptographic keys because the keys are not randomly generated but are preset with identical values. If we examine the content of the ECP settings in the web.config file from C:\Program Files\Microsoft\Exchange Server\<Version Number>\ClientAccess\ecp, we see that the validationKey and decryptionKey values are already set. These keys are used to secure the ViewState parameter.

web.config file fragment

One of the articles on the Microsoft website describes the ViewState parameter as follows:

On the ASP.NET pages View State presents the state of the page when it was last processed on the server. This parameter is used to create a call context and store values in two consecutive requests for the same page. By default, the state is saved on the client using a hidden field added to the page and restored on the server before the page request is processed. View State moves back and forth with the page itself, but does not represent or contain any information relating to the display of the page on the client side.

As such, pre-shared keys allow an authenticated user to send a deliberate ViewState parameter to the ECP application, which when deserialised will cause malicious code to be executed on the Exchange server in the context of System.

The ysoserialutility which exploits insecure deserialisation in .NET applications can help us create a malicious object.

Below is an example of ViewState generation, its payload in turn runs whoami.

Running ysoserial utility

The validationkey and generator parameters, as described earlier, are preset and cannot be changed. The viewstateuserkey value must be taken from the ASP.NET_SessionId value of the user authorised on the ECP service.

Cookie settings for the user authorised on the ECP service

Once the ViewState has been generated, a request is sent to the vulnerable ECP service, resulting in the server returning an error code 500.

Server response when CVE-2020–0688 is exploited

If you run the request through the BurpSuite utility, you can see in the ViewState decoder that the payload is passed in the <System> tag along with other user parameters:

ViewState decoded

If the vulnerability is successfully exploited, the w3wp.exe process responsible for the ECP (MSExchangeECPAppPool) will execute the payload transferred in the ViewState parameter. Below is the correlation rule to detect cmd.exe commands or the PowerShell interpreter being executed by a w3wp.exe web server process:

  • event_log_source:'Security' AND event_id:'4688' AND proc_parent_file_path end with:'\w3wp.exe' AND proc_file_path end with:('\cmd.exe' OR '\powershell.exe')

The IIS access logs contain a request for the URL /ecp/default.aspx to which the server responded with status 500 (internal server error). Below is the rule for detecting the exploitation of CVE-2020-0688 using IIS events:

  • event_log_source:’IIS’ AND http_method=’GET’ AND http_status_code=’500’ AND url_path=’/ecp/default.aspx’ AND url_query contains ‘__VIEWSTATEGENERATOR’ AND hurl _query contains ‘__VIEWSTATE’
CVE-2020–0688 (IIS) exploitation event

The Application log contains an event which indicates an error in the MSExchange Control Panel application with Event ID = 4.

CVE-2020–0688 (Application log) exploitation result

Below is the rule for detecting CVE-2020–0688 exploitation using Application log events:

  • event_log_source:’Application’ AND event_id=’4’ AND (Message contains ‘__VIEWSTATE’)

Detecting Exploitation of CVE-2020–16875

Successful exploitation of the CVE-2020–16875 vulnerability allows an attacker to execute arbitrary code on the Exchange server in the context of the System user. The attacker can then escalate their domain privileges and compromise the entire company network.

Successful authentication requires a domain account from a corporate mailbox that is a member of a group with Data Loss Prevention (DLP) privileges. The exploitation itself is done through the DLP component. DLP is configured through the ECP interface. The DLP engine allows you to filter mail flow according to predefined patterns and rules for content analysis of emails and attachments.

Since we already know that in order for the exploit to succeed, the attacker must be a member of the DLP group, a rule can be implemented to create a new group with the Data Loss Prevention role, and a new user can be added to that group. This can be done from either the ECP interface or from the Exchange Management Shell using the following commands:

  • New-RoleGroup -Name "dlp users" -Roles "Data Loss Prevention" -Members "user1" (create group dlp users with role Data Loss Prevention and add user1 to the group);
  • Update-RoleGroupMember -Members "dadmin" -identity "dlp users" (add dadmin to group dlp users).

The screenshot below shows the event of adding the user dadmin to the group using the ECP interface. This activity can also be traced back to PowerShell audit events (Event ID 800 and 4104).

Adding user dadmin to group dlp users (MSExchange Management log)

The new Data Loss Prevention creation event can be dected in PowerShell and MSExchange Management log events using the following rule:

Use the rule below to track down events of Data Loss Prevention rights being issued using PowerShell audit events and MSExchange Management logs:

  • event_log_source:('PowershellAudit' OR 'MSExchange Management') AND event_id:('1' OR ’800’ OR '4104') AND ((Message contains ‘New-RoleGroup’ AND Message contains ‘Data Loss Prevention’) OR (Message contains ‘Update-RoleGroupMember’ AND Message contains ‘<Group with DLP rights>’ AND Message contains '-Members'))

The exploit for this vulnerability performs the following steps in sequence:

  1. Authenticate under a given account to retrieve a session through OWA.
  2. Obtain the ViewState parameter by accessing the DLP policy management functionality.
  3. Add a new malicious DLP policy that contains an executable command that runs from PowerShell.

Let’s run the utility and see what the Exchange events look like. Below you can see that the exploit run under the dadmin account was successful.

Successful exploitation of CVE-2020–16875

The access logs of ECP contain an event of a new DLP policy being successfully added:

  • 2021-03-09 12:03:31 10.3.132.20 POST /ecp/DLPPolicy/ManagePolicyFromISV.aspx ActID=3b6c5adc-c7d0-4aeb-82ec-711c2257ece6 444 LAB\dadmin 192.168.1.20 python-requests/2.22.0 - 200 0 0 863

The rule to create a new DLP policy using IIS events:

  • event_log_source:’IIS’ AND http_method=’POST’ AND http_code='200' AND url_path='/ecp/DLPPolicy/ManagePolicyFromISV.aspx'

To exploit the vulnerability, we have to create a new policy, this will come up in the MSExchange Management log as a new event with a random name that contains a malicious payload in the TemplateData parameter:

New DLP policy creation event (MSExchange Management log)

The creation of a new DLP policy can be dected in PowerShell and MSExchange Management log events using the following rule:

  • event_log_source:('PowershellAudit' OR 'MSExchange Management') AND event_id:('1' OR ’800’ OR '4104') AND (Message contains ‘New-DlpPolicy’ AND Message contains '-TemplateData')

The exploition of this vulnerability launches Notepad. Looking at the process start events in the Security log, we see that the Notepad process is initiated by the parent process w3wp.exe with System privileges.

Process start event (Security log)

Use the rules above to detect a successful exploitation of the CVE-2020–16875 vulnerability:

  • event_log_source:'Security' AND event_id:'4688' AND proc_parent_file_path end with:'\w3wp.exe' AND proc_file_path end with:('\cmd.exe' OR '\powershell.exe')

Another variant of the PowerShell exploit has similar logic and performs the following actions:

  1. It creates a remote PowerShell session using the PowerShell component of the Exchange server. The account attempting the connection must have the Data Loss Prevention role.
Code snippet for creating a remote PowerShell session

2. It creates a new policy using the New-DlpPolicy commandlet. The payload is stored in the variable $xml:

Running New-DlpPolicy within a remote PowerShell session

Below is the result of running the PowerShell exploit, successfully connecting as user1 with no privileges and running the whoami command with System privileges.

IIS events show the creation of a remote session:

  • 2021-03-09 13:47:04 10.3.132.20 POST /powershell serializationLevel=Full;ExchClientVer=15.1.1591.10;clientApplication=ManagementShell;TargetServer=;PSVersion=5.1.14393.693&sessionID=Version_15.1_(Build_1590.10)=rJqNiZqNgZqHnJeekZia0bO+vdGzsLy+s4HOxsvNz8nNycvIgc3Pzc7Sz8zSz8arzszFysvFz8s= 444 lab\dadmin 192.168.1.20 Microsoft+WinRM+Client - 500 687 0 180002

The rule that detects this activity is as follows:

  • event_log_source:’IIS’ AND http_method=’POST’ AND url_path='/powershell' AND (Message contains ‘serializationLevel=Full AND Message contains 'clientApplication=ManagementShell') AND user_agent='Microsoft+WinRM+Client'

The Security log detects a successful start of the whoami process with w3wp.exe as the parent process. Execution of the New-DlpPolicy command can be detected in the PowerShell audit log using one of the previously mentioned rules.

whoami process start event

Detecting Exploitation of CVE-2021–24085

The process for exploiting CVE-2021–24085 is more complex. The following steps are required to execute the attack successfully:

  1. Compromise an arbitrary domain account that has a mailbox.
  2. Use the ECP interface to export the certificate.
  3. Using the certificate obtained, generate a CSRF token, aka the msExchEcpCanary parameter.
  4. Get the Exchange administrator to go to the attacker’s malicious page, which will send a request to the Exchange server with the preset token value on behalf of the administrator.

A successful exploitation would allow the attacker to escalate their privileges to Exchange administrator.

A GitHub project can be used to implement the attack, where the poc.py file is responsible for obtaining the certificate that will be used to generate the CSRF token.

YellowCanary — a project coded in C# that is responsible for generating the token.
Poc.js— the JavaScript payload placed by the attacker on a monitored web server designed to lure the Exchange administrator.

The screenshot below shows that the poc.py script has successfully exported the certificate to the testcert.der file.

Successful export of the certificate

An ECP access-log event that contains traces of a certificate being saved:

  • 2021-03-09 15:52:55 10.3.132.20 POST /ecp/DDI/DDIService.svc/SetObject schema=ExportCertificate&msExchEcpCanary=yylkJJJocUWa3HVCEcQli7B3FcF--tgI2nbpJpHLcFZ60E9sZ2gmDpi_sFqf3jl9YcG9qcRMzek.&ActID=cf99b7d2-4eac-4435-a041-f0adaa44ed94 444 LAB\dadmin 192.168.1.20 python-requests/2.22.0 - 200 0 0 500

The certificate is saved in the Exchange server file system — in the poc.png file located in the IIS directory and then downloaded successfully using the same poc.py script.

Certificate download event:

  • 2021-03-09 15:52:55 10.3.132.20 GET /ecp/poc.png - 444 LAB\EXCHANGE$ 192.168.1.20 python-requests/2.22.0 - 200 0 0 7

In this way, we can implement a rule that detects the event of a certificate export in the IIS access logs:

  • event_log_source:’IIS’ AND http_method=’POST’ AND http_code='200' AND url_path='/ecp/DDI/DDIService.svc/SetObject' AND (Message contains 'schema=ExportCertificate')

Once the certificate is obtained, the attacker uses the YellowCanary utility to generate the msExchEcpCanary parameter needed to implement the CSRF attack. The first parameter is the SID of the user on whose behalf we want to perform an action on the ECP:

Generating the msExchEcpCanary parameter

The attacker must then trick a privileged user (ideally an Exchange administrator) into clicking on a prepared link containing the malicious JavaScript code. This code can send requests to the ECP on behalf of the administrator. This could, for example, be used to exploit the CVE-2021–27065 vulnerability, which we covered in the previous article. As a result, the attacker would gain access to the Exchange server with System privileges via the downloaded web shell.

In addition to the above technique, this attack can be performed by adding a malicious MS Outlook add-in, an application that provides users with advanced capabilities.

There are three ways to add an Outlook add-in:

  • Add via the URL where the add-in is located.
  • Download from the Office Store.
  • Download a new add-in from file.
Adding a new add-in via the ECP interface

The add-in is an XML format configuration file. An attacker can create a malicious config that will, for example, forward the contents of client emails to an attacker’s controlled server. The /ecp/Handlers/UploadHandler.ashx interface is used to upload the config file.

Below is a snippet of the JavaScript code that will be executed by the Exchange administrator after being redirected to the attacker’s website. This code fetches the content of the malicious evil.xml add-in, which is also located on the attacker's website, and sends it with a POST request to /ecp/Handlers/UploadHandler.ashx. The msExchEcpCanary parameter contains the CSRF token that was generated in the previous step. It is also worth keeping in mind that when the administrator accesses the attacker's website, their ECP session must still be active.

Adding an add-in using JavaScript

The following rule can be used to detect the loading of an add-in:

  • event_log_source:’IIS’ AND http_method=’POST’ AND http_code='200' AND url_path='/ecp/Handlers/UploadHandler.ashx'

Conclusion

The vulnerabilities discussed in this article are still being exploited today. Most of the time they are unsuccessful, but there are exceptions. Collecting significant security events and implementing detection rules will allow you to react to a possible attack in time to eliminate the fallout from the incident at an early stage.

In the next article, we will talk about Windows domain privilege escalation vectors through the MS Exchange server and how to detect them.

Hunting Down MS Exchange Attacks. Part 1. ProxyLogon (CVE-2021–26855, 26858, 27065, 26857)

By: BI.ZONE
15 April 2021 at 12:45

By Anton Medvedev, Demyan Sokolin, Vadim Khrykov

Microsoft Exchange is one of the most common mail servers used by hundreds of thousands of companies around the world. Its popularity and accessibility from the Internet make it an attractive target for attackers.

Since the end of 2020, we have recorded a sharp increase in the number of incidents related to the compromise of MS Exchange server and its various components, in particular OWA (Outlook Web Access). Given the MS Exchange’s 24-year history, the complexity of its architecture, its location on the perimeter, and the increased interest in it among security researchers, we can assume that the number of vulnerabilities found in the popular mail server will only increase over time. This is evidenced by the recent discovery by DEVCORE researchers of a chain of critical vulnerabilities known collectively as ProxyLogon.

All this led us to write a series of articles that will focus on MS Exchange security: server attacks and detection techniques.

In the first article in the series, we will take a brief look at the MS Exchange server architecture and move on to the most relevant topic for everyone, i.e. detecting the exploitation of ProxyLogon. We will show how to use standard operating system events and Exchange logs to detect ProxyLogon, both in real time, using proactive threat hunting approaches, and attacks that have already happened in the past.

MS Exchange Architecture and Primary Attack Vectors

The main components of the MS Exchange server and the links between them are shown in the diagram below.

MS Exchange architecture
Source: microsoft.com

Depending on the version, MS Exchange may have the following roles:

  • Mailbox server.
  • A Client Access server, which is a frontend service that proxies client requests to the backend servers.
  • Transport, which is responsible for managing mail traffic.
  • Unified Messaging, which allows voice messaging and other telephony features (the role is not available on version 2019 servers).
  • Management role, which is concerned with administration and flexible configuration of MS Exchange components.

Table 1. Basic protocols used by MS Exchange

The main components of Exchange and their brief descriptions are given below:

  • Outlook Web Access (OWA) — a web interface for mailbox access and management (read/send/delete mail, edit calendar, etc.).
  • Exchange Control Panel (ECP) — a web interface to administer Exchange components: manage mailboxes, create various policies to manage mail traffic, connect new mail servers, etc.
  • Autodiscover — a service that allows customers to retrieve information about the location of various Exchange server components such as the URL for the EWS service. A user needs to be authenticated before the information can be retrieved.
  • Exchange Web Services (EWS) — an API to provide various applications with access to mailbox components.
  • Exchange ActiveSync (EAS) — a service that allows mobile device users to access and manage their email, calendar, contacts, tasks, etc. without an internet connection.
  • RPC — a client access service that uses the RPC protocol, which runs on top of HTTP.
  • Offline Address Book (OAB) — an offline address book service on the Exchange server that allows Outlook users to cache the contents of the Global Address List (GAL) and access it even when not connected to Exchange.

All of the components described above function as applications on the Microsoft IIS web server.

Attackers typically target MS Exchange servers for the following purposes:

  • to gain access to confidential information in corporate emails
  • to launch a malicious mailing from the victim company’s addresses to infiltrate the infrastructure of another organisation
  • to compromise user accounts with the the use of Exchange components (successful bruteforce attack or detection of credentials in email correspondence) to infiltrate the company’s network via one of the corporate services
  • to gain foothold into the company network (e.g. by using a web shell on the OWA service)
  • to escalate privileges in the domain by using the Exchange server
  • to disable the Exchange server in order to disrupt internal business processes (e.g. by fully encrypting server data)

Logs and Useful Events

The source events listed in Table 2 will be useful for detecting various attacks against the MS Exchange server.

Table 2. Event source profile

ProxyLogon Vulnerabilities

On 2 March 2021, Microsoft released security updates for a number of critical MS Exchange server vulnerabilities. The updates included a chain of critical vulnerabilities CVE-2021–26857, CVE-2021–26855, CVE-2021–26858, CVE-2021–27065, commonly referred to as ProxyLogon. After security updates were released and the first articles about these vulnerabilities were published, cyberattacks that exploited these vulnerabilities started being detected all over the world. Most of the attacks were aimed at uploading the initial web shell to the server to develop the attack in the future. While US companies took the brunt of the attack, we also recorded a number of similar attacks targeting our customers in Russia and Asia.

ProxyLogon vulnerability chain

Let us take a closer look at the ProxyLogon vulnerability chain. CVE-2021–26857 is not actually part of this chain, as it leads to code execution on the server and does not require other vulnerabilities to be exploited beforehand. Vulnerability CVE-2021–26857 is related to insecure data deserialisation in the Unified Messaging service. Exploiting this vulnerability requires that the Unified Messaging role be installed and configured on the Exchange server. As this role is rarely used, no exploitation of this vulnerability has been reported so far. Instead, attackers exploit the CVE-2021–26855, CVE-2021–26858 and CVE-2021–27065 vulnerability chain, which also allows remote arbitrary code execution on the mail server but is easier to exploit.

ProxyLogon is the name of CVE-2021–26855 (SSRF) vulnerability that allows an external attacker to bypass the MS Exchange authentication mechanism and impersonate any user. By forging a server-side request, an attacker can send an arbitrary HTTP request that will be redirected to another internal service on behalf of the mail server computer account. To exploit the vulnerability, the attacker must generate a special POST request for a static file in a directory which is readable without authentication, such as /ecp/x.js, where the presence of the file in the directory is not required. The body of the POST request will also be redirected to the service specified in the cookie named X-BEResource.

An attacker using ProxyLogon can impersonate, for example, an administrator and authenticate into the Exchange Control Panel (ECP) and then overwrite any file on the system using the CVE-2021–26858 or CVE-2021–27065 vulnerabilities.

The greatest effect of overwriting files is achieved by creating a web shell in publicly accessible directories. To create a web shell, an attacker exploits a vulnerability in the built-in virtual directory mechanism. When creating a new virtual directory (for example, for an OAB service) an attacker can specify an address that includes a simple web shell as its external address. The attacker must then reset the virtual directory and specify the path to a file on the server where the current virtual directory settings should be saved as a backup. After resetting, the file to which the virtual directory backup will be saved will contain the web shell specified in the previous step.

Once the chain of vulnerabilities have been exploited, an attacker is able to execute commands through a web shell on the Exchange server with the privileges of the account that is used to run the application pool on the IIS server (NT AUTHORITY\SYSTEM by default). In order to exploit the vulnerability chain successfully, an attacker must have network access on port 443 to MS Exchange with Client Access role installed and know the email account name of a user with administrative privileges.

Detection of CVE-2021–26855 Vulnerability

The CVE-2021–26855 vulnerability allows an external attacker to send an arbitrary HTTP request that will be redirected to the specified internal service from the mail server computer account. In this way, the vulnerability allows the attacker to bypass the authentication mechanism of the Exchange server and perform the request with the highest privileges.

Since the attacker can specify the service to which an arbitrary HTTP request is to be redirected, this SSRF vulnerability can be exploited in different ways. Let us look at two ways to exploit this vulnerability: reading emails via EWS and downloading web shells via ECP (CVE-2021–26858 and CVE-2021–27065).

CVE-2021–26855 makes it easy to download any user’s email, just by knowing their email address. The exploitation requires at least two MS Exchange servers in the attacked infrastructure. For example, the request is sent to exchange.lab.local and from there it is redirected via SSRF to exchange02.lab.local. The screenshot below shows an example of this request to the EWS API using a SOAP request to get the last 10 emails from the [email protected] mailbox. The response from the server contains email IDs and other information about the emails (e.g. header or date received).

SOAP request for a list of emails

The attacker can retrieve the original email message by inserting its identifier into another SOAP request.

SOAP request to retrieve an email message

The response from the server will contain a base64 representation of the original email message.

Decoded contents of the email message

In this way, all emails from any given email account can be downloaded from the server without authentication. Email is often used to transmit sensitive information such as payment orders, configuration files, credentials or instructions for connecting to VPN servers, etc. Attackers can use the information obtained from compromised email correspondence for phishing mailings and other cybercrimes. This attack vector is no less dangerous than downloading a web shell to a server.

Such requests are logged by EWS. Accordingly, a rule to detect the described attack might look like this:

  • event_log_source:'EWS' AND AuthenticatedUser end with:'$' AND SoapAction IS NOT NULL AND UserAgent contains:'ExchangeWebServicesProxy/CrossSite/' AND NOT (SoapAction = 'GetUserOofSettings')

The second way to exploit the SSRF vulnerability is by authenticating into the ECP and then exploiting the CVE-2021–26858/CVE-2021–27065 vulnerabilities to upload the web shell to the server. In order to make requests to the ECP, a full session must be established in the ECP. For the attacker to impersonate an administrator when setting up a session, they need to know the SID of the mail server administrator’s account.

First of all, from the response to the NTLM request to /rpc/rpcproxy.dll, an attacker can find out the FQDN of the mail server, which will be needed in the following stages: it will be specified in the NTLM response to be decoded.

Obtaining the FQDN of the mail server

The next step is to obtain the LegacyDN and the email account ID by making an HTTP request to Autodiscover. The FQDN of the mail server obtained in the previous step is specified in a cookie named X-BEResource.

Query Autodiscover for admin email account information

The attacker can then retrieve the SID of the targeted user by sending an HTTP request to MAPI. The attacker sends a request to delegate access to the email account. This request is also forwarded to MAPI on behalf of the computer account user and causes an access error. The error contains the SID of the targeted user.

Query MAPI to retrieve the admin SID

Finally, having obtained the user’s SID, the attacker can authenticate themselves on the server by posing as the administrator by sending a specially crafted POST request to /ecp/proxyLogon.ecp.

Authenticating in ECP as an administrator

The request includes a header named msExchLogonMailBox with the SID of the user to be authenticated. The body of the POST request also contains the SID of that user. In response, the server returns two cookies named ASP.NET_SessionId and msExchEcpCanary that the attacker can use for any future ECP requests. Obtaining these cookies is the end result of the attacker exploiting the ProxyLogon vulnerability (CVE-2021-26855) if they plan to exploit CVE-2021-26858 and CVE-2021-27065 to upload a web shell to the server.

Such requests are logged in the IIS log. Accordingly, a rule to detect this activity can be as follows:

  • event_log_source:'IIS' AND cs-method:'POST' AND cs-uri-stem:'/ecp/proxyLogon.ecp' AND cs-username end with:'$'

Detection of CVE-2021–26858, CVE-2021–27065 Vulnerabilities

Successful exploitation of CVE-2021–27065 allows a malicious file to be uploaded to an Exchange server using the ECP interface, which can then be used as a web shell. Exploitation of this vulnerability requires pre-authentication, which can be performed using CVE-2021–26855. Let us take a closer look at the exploitation of CVE-2021–27065.

We start by logging into the ECP interface and going to Servers → Virtual directories. Editing the virtual directories allows the Exchange application to migrate by changing the current application directory to IIS.

By navigating to the OAB (Default Web Site) edit box in the External URL, an attacker can insert a web shell code, e.g. China Chopper:

Changing virtual directory settings for OAB (Default Web Site)

After setting the new virtual directory configuration parameters, the following event may be seen in the MSExchange Management log:

Setting new parameters for the OAB virtual directory (MSExchange Management log)

The following rule can be implemented to detect such activity:

  • event_log_source:('PowershellAudit' OR 'MSExchangeCMDExec') AND event_id:('1' OR ’800’ OR '4104') AND (Message contains ‘Set-’ AND Message contains ‘VirtualDirectory AND Message contains ‘-ExternalUrl’ AND Message contains ‘script’)

The next step resets the virtual directory settings. In the interface that appears, we see that before resetting we are prompted to save the current virtual directory settings to a selected file:

OAB virtual directory reset interface

After resetting the virtual directory in the MSExchange Management log we can see two events with EventID 1 where first the Remove-OabVirtualDirectory command is used, which is followed by the New-OabVirtualDirectory command in the next event. These events can be used as additional indicators in case the rule described above is triggered.

Let us save the configuration as test.aspx file in C:\Program Files\Microsoft\Exchange Server\V15\FrontEnd\HttpProxy\ecp\auth. In the IIS ECP events, we can see an event telling us that the settings for the application virtual directory have been reset. Example of the event:

2021-03-10 08:16:52 10.3.132.20 POST /ecp/DDI/DDIService.svc/SetObject ActivityCorrelationID=d874fdcd-bd9d-9545-af02-677d356f1aa9&schema=ResetOABVirtualDirectory
&msExchEcpCanary=xkdU4icLzEazuIzEhSZaYgDLNVmW49gIjMvzJCs7TmzJoNU9rXLN15tkY5JGHwEOROWXGGq9_NM.&ActID=113cbd79-1e40-4635-8bae-8c8af6731267
444 LAB\dadmin 192.168.1.20 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/89.0.4389.82+Safari/537.36
https://exchange/ecp/VDirMgmt/ResetVirtualDirectory.aspx?pwmcid=6&ReturnObjectType=1&id=7a466ca6-419b-4445-9cc8-ae66a6bff719&schema=ResetOABVirtualDirectory 200 0 0 7

The following rule detects attempts to reset virtual directories based on IIS log events:

  • event_log_source:’IIS’ AND http_method:’POST’ AND http_code:'200' AND url_path:'/ecp/DDI/DDIService.svc/SetObject' AND (Message contains 'schema=Reset' AND Message contains 'VirtualDirectory')

When exploiting this vulnerability with CVE-2021–26858, an SSRF attack is used to manipulate virtual directories. For this reason, the Username field will contain the computer account, in our case lab.local\EXCHANGE$, as the request is initiated by the Exchange server itself. Given this fact, another rule can be implemented:

  • event_log_source:’IIS’ AND http_method:’POST’ AND http_code:'200' AND url_path:'/ecp/DDI/DDIService.svc/SetObject' AND (Message contains 'schema=Reset' AND Message contains 'VirtualDirectory') AND Username contains '$'

The contents of the test.aspx configuration file can be seen in the screenshot below, where the ExternalUrl parameter contains the specified China Chopper.

Contents of test.aspx

Let us try to execute the command using the downloaded web shell. With Burp Suite we specify the command of interest in the POST parameter a. The result of the command is added to the response from the server, followed by the contents of the configuration file.

Executing commands using a downloaded web shell.

If we look at the start events of the processes, we can see the execution of our command in the IIS work process, which runs the cmd.exe command line interpreter with the corresponding arguments.

By supplementing the detection logic with the PowerShell interpreter, we get the following rule:

  • event_log_source:'Security' AND event_id:'4688' AND proc_parent_file_path end with:'\w3wp.exe' AND proc_file_path end with:('\cmd.exe' OR '\powershell.exe')

Detection of this activity will be described in more detail in one of our upcoming articles.

Web shell activity in Security log

In practice, this CVE was used as a payload after authentication was bypassed using the CVE-2021–26855 vulnerability.

The CVE-2021–26858 vulnerability also allows writing an arbitrary file to an Exchange server, but requires pre-authentication for successful exploitation. This vulnerability can also be used in conjunction with SSRF (CVE-2021–26858).

There are no publicly available PoCs or other sources detailing its exploitation. Nevertheless, Microsoft has reported how this activity can be detected. To do so, we implement the following rule using events from the OAB Generator service:

  • event_log_source:'OABGenerator' AND Message contains 'Download failed and temporary file'

Files must only be uploaded to the %PROGRAMFILES%\Microsoft\Exchange Server\V15\ClientAccess\OAB\Temp directory, writing the file to any other directory is considered illegitimate.

Detection of CVE-2021–26857 Vulnerability

CVE-2021–26857 is an insecure deserialisation vulnerability in a Unified Messaging service.

Unified Messaging allows voice messaging and other features, including Outlook Voice Access and Call Answering Rules. The service must be preconfigured for it to work properly, and is rarely used. For this reason, attackers more often exploit CVE-2021–27065 in real-world attacks.

The problem is contained in the Base64Deserialize method of the CommonUtil class, and the class itself in the Microsoft.Exchange.UM.UMCommon namespace of the Microsoft.Exchange.UM.UMCommon.dll library.

Base64Deserialize method code

This method is called upon in the main library of the Unified Messaging service — Microsoft.Exchange.UM.UMCore.dll, more specifically within the method FromHeaderFile, classed as PipelineContext with namespaces Microsoft.Exchange.UM.UMCore. This way, the attacker can generate their serialised object, for example using the ysoserial.net utility, and remotely execute their code on the Exchange server in the SYSTEM context.

A snippet of the FromHeaderFile method

The new version of the Microsoft.Exchange.UM.UMCore.dll library (after installing the update) has many additional checks on the incoming object types before the deserialisation process. As you can see in the screenshot below, the library is loaded into the UMWorkerProcess.exe process. Consequently, if the vulnerability is exploited, this process will initiate abnormal activity.

Using the Microsoft.Exchange.UM.UMCore.dll library

A rule to detect suspicious child processes being started by UMWorkerProcess.exe (cmd/powershell start, by Security and Sysmon log events):

  • event_log_source:'Security' AND event_id:'4688' AND proc_parent_file_path end with:'\UMWorkerProcess.exe' AND proc_file_path end with:('\cmd.exe' OR '\powershell.exe')

A malicious file may be created as a payload on the file system, such as a reverse shell in the autostart directory or a web shell in one of the IIS directories. The following rule can be implemented to detect this activity:

  • event_log_source:’Sysmon’ AND event_id:'11' AND proc_file_path end with:'\UMWorkerProcess.exe' AND file_name end with:(*.asp OR *.aspx) AND file_path contains:("\ClientAccess\Owa\" OR "\HttpProxy\Owa\" OR "\inetpub\wwwroot\" OR "\www\")

Conclusion

According to Microsoft, at the time of writing about 92% of MS Exchange servers have already been patched and are no longer vulnerable to ProxyLogon. Those who haven’t yet installed the patches should do so as a matter of urgency.

Even if the servers are already patched it is worth checking them for signs of ProxyLogon exploitation and repair the consequences if needed. This is quite easy to do with the standard operating system and Exchange server log events at hand.

Discovering new vulnerabilities in the Exchange server and new attacks are just a matter of time, so it is important to not only protect your mail servers properly, but also to collect and monitor important security events in advance.

We hope you have enjoyed our first article in this series. In the next article, we will explore how to detect the exploitation of other notorious MS Exchange vulnerabilities.

CVE-2022-21972: Windows Server VPN Remote Kernel Use After Free Vulnerability (Part 1)

10 May 2022 at 09:00

CVE-2022-21972 is a Windows VPN Use after Free (UaF) vulnerability that was discovered through reverse engineering the raspptp.sys kernel driver. The vulnerability is a race condition issue and can be reliably triggered through sending crafted input to a vulnerable server. The vulnerability can be be used to corrupt memory and could be used to gain kernel Remote Code Execution (RCE) or Local Privilege Escalation (LPE) on a target system.

Affected Versions

The vulnerability affects most versions of Windows Server and Windows Desktop since Windows Server 2008 and Windows 7 respectively. To see a full list of affected Windows versions check the official disclosure post on MSRC:

https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-21972

The vulnerable code is present on both server and desktop distributions, however due to configuration differences, only the server deployment is exploitable.

Overview

This vulnerability is based heavily on how socket object life cycles are managed by the raspptp.sys driver. In order to understand the vulnerability we must first understand some of the basics in the kernel driver interacts with sockets to implement network functionality.

Sockets In The Windows Kernel – Winsock Kernel (WSK)

WSK is the name of the Windows socket API that can be used by drivers to create and use sockets directly from the kernel. Head over to https://docs.microsoft.com/en-us/windows-hardware/drivers/network/winsock-kernel-overview to see an overview of the system.

The way in which the WSK API is usually used is through a set of event driven call back functions. Effectively, once a socket is set up, an application can provide a dispatch table containing a set of function pointers to be called for socket related events. In order for an application to be able to maintain its own state through these callbacks, a context structure is also provided by the driver to be given to each callback so that state can be tracked for the connection throughout its life-cycle.

raspptp.sys and WSK

Now that we understand the basics of how sockets are interacted with in the kernel, let’s look at how the raspptp.sys driver uses WSK to implement the PPTP protocol.

The PPTP protocol specifies two socket connections; a TCP socket used for managing a VPN connection and a GRE (Generic Routing Encapsulation) socket used for sending and receiving the VPN network data. The TCP socket is the only one we care about for triggering this issue, so lets break down the life cycle of how raspptp.sys handles these connections with WSK

  1. A new listening socket is created by the WskOpenSocket function in raspptp.sys.  This function is passed a WSK_CLIENT_LISTEN_DISPATCH dispatch table with the WskConnAcceptEvent function specified as the WskAcceptEven handler. This is the callback that handles a socket accept event, aka new incoming connection.
  2. When a new client connects to the server the WskConnAcceptEvent function is called.  This function allocates a new context structure for the new client socket and registers a WSK_CLIENT_CONNECTION_DISPATCH dispatch table with all event callback functions specified. These are WskConnReceiveEvent, WskConnDisconnectEvent and WskConnSendBacklogEvent for receive, disconnect and send events respectively.
  3. Once the accept event is fully resolved, WskAcceptCompletion is called and a callback is triggered (CtlConnectQueryCallback) which completes initialisation of the PPTP Control connection and creates a context structure specifically for tracking the state of the clients PPTP control connection. This is the main object which we care about for this vulnerability.

The PPTP Control connection context structure is allocated by the CtlAlloc function. Some abbreviated pseudo code for this function is:

PptpCtlCtx *__fastcall CtlAlloc(PptpAdapterContext *AdapterCtx)
{
    PptpAdapterContext *lpPptpAdapterCtx;
    PptpCtlCtx *PptpCtlCtx;
    PptpCtlCtx *lpPptpCtlCtx;
    NDIS_HANDLE lpNDISMiniportHandle;
    PDEVICE_OBJECT v6;
    __int64 v7;
    NDIS_HANDLE lpNDISMiniportHandle_1;
    NDIS_HANDLE lpNDISMiniportHandle_2;
    struct _NDIS_TIMER_CHARACTERISTICS TimerCharacteristics;

    lpPptpAdapterCtx = AdapterCtx;
    PptpCtlCtx = (PptpCtlCtx *)MyMemAlloc(0x290ui64, 'TPTP'); // Actual name of the allocator function in the raspptp.sys code
    lpPptpCtlCtx = PptpCtlCtx;
    if ( PptpCtlCtx )
    {
        memset(PptpCtlCtx, 0, 0x290ui64);
        ReferenceAdapter(lpPptpAdapterCtx);
        lpPptpCtlCtx->AllocTagPTPT = 'TPTP';
        lpPptpCtlCtx->CtlMessageTypeToLength = (unsigned int *)&PptpCtlMessageTypeToSizeArray;
        lpPptpCtlCtx->pPptpAdapterCtx = lpPptpAdapterCtx;
        KeInitializeSpinLock(&lpPptpCtlCtx->CtlSpinLock);
        lpPptpCtlCtx->CtlPptpWanEndpointsEntry.Blink = &lpPptpCtlCtx->CtlPptpWanEndpointsEntry;
        lpPptpCtlCtx->CtlCallDoubleLinkedList.Blink = &lpPptpCtlCtx->CtlCallDoubleLinkedList;
        lpPptpCtlCtx->CtlCallDoubleLinkedList.Flink = &lpPptpCtlCtx->CtlCallDoubleLinkedList;
        lpPptpCtlCtx->CtlPptpWanEndpointsEntry.Flink = &lpPptpCtlCtx->CtlPptpWanEndpointsEntry;
        lpPptpCtlCtx->CtlPacketDoublyLinkedList.Blink = &lpPptpCtlCtx->CtlPacketDoublyLinkedList;
        lpPptpCtlCtx->CtlPacketDoublyLinkedList.Flink = &lpPptpCtlCtx->CtlPacketDoublyLinkedList;
        lpNDISMiniportHandle = lpPptpAdapterCtx->MiniportNdisHandle;
        TimerCharacteristics.TimerFunction = (PNDIS_TIMER_FUNCTION)CtlpEchoTimeout;
        *(_DWORD *)&TimerCharacteristics.Header.Type = 0x180197;
        TimerCharacteristics.AllocationTag = 'TMTP';
        TimerCharacteristics.FunctionContext = lpPptpCtlCtx;
        if ( NdisAllocateTimerObject(
            lpNDISMiniportHandle,
            &TimerCharacteristics,
            &lpPptpCtlCtx->CtlEchoTimeoutNdisTimerHandle) )
        {
        ...
        }
        else
        {
            lpNDISMiniportHandle_1 = lpPptpAdapterCtx->MiniportNdisHandle;
            TimerCharacteristics.TimerFunction = (PNDIS_TIMER_FUNCTION)CtlpWaitTimeout;
            if ( NdisAllocateTimerObject(
            lpNDISMiniportHandle_1,
            &TimerCharacteristics,
            &lpPptpCtlCtx->CtlWaitTimeoutNdisTimerHandle) )
            {
                ...
            }
            else
            {
                lpNDISMiniportHandle_2 = lpPptpAdapterCtx->MiniportNdisHandle;
                TimerCharacteristics.TimerFunction = (PNDIS_TIMER_FUNCTION)CtlpStopTimeout;
                if ( !NdisAllocateTimerObject(
                lpNDISMiniportHandle_2,
                &TimerCharacteristics,
                &lpPptpCtlCtx->CtlStopTimeoutNdisTimerHandle) )
                {
                    KeInitializeEvent(&lpPptpCtlCtx->CtlWaitTimeoutTriggered, NotificationEvent, 1u);
                    KeInitializeEvent(&lpPptpCtlCtx->CtlWaitTimeoutCancled, NotificationEvent, 1u);
                    lpPptpCtlCtx->CtlCtxReferenceCount = 1;// Set reference count to an initial value of one
                    lpPptpCtlCtx->fpCtlCtxFreeFn = (__int64)CtlFree;
                    ExInterlockedInsertTailList(
                    (PLIST_ENTRY)&lpPptpAdapterCtx->PptpWanEndpointsFlink,
                    &lpPptpCtlCtx->CtlPptpWanEndpointsEntry,
                    &lpPptpAdapterCtx->PptpAdapterSpinLock);
                    return lpPptpCtlCtx;
                }
                ...
            }
        }
        ...
    }
    if...
        return 0i64;
}

The important parts of this structure to note are the CtlCtxReferenceCount and CtlWaitTimeoutNdisTimerHandle structure members. This new context structure is stored on the socket context for the new client socket and can then be referenced for all of the events relating to the socket it binds to.

The only section of the socket context structure that we then care about are the following fields:

00000008 ContextPtr dq ? ; PptpCtlCtx
00000010 ContextRecvCallback dq ? ; CtlReceiveCallback
00000018 ContextDisconnectCallback dq ? ; CtlDisconnectCallback
00000020 ContextConnectQueryCallback dq ? ; CtlConnectQueryCallback
  • PptpCtlCtx – The PPTP specific context structure for the control connection.
  • CtlReceiveCallback – The PPTP control connection receive callback.
  • CtlDisconnectCallback – The PPTP control connection disconnect callback.
  • CtlConnectQueryCallback – The PPTP control connection query (used to get client information on a new connection being complete) callback.

raspptp.sys Object Life Cycles

The final bit of background information we need to understand before we delve into the vulnerability is the way that raspptp keeps these context structures alive for a given socket. In the case of the PptpCtlCtx structure, both the client socket and the PptpCtlCtx structure have a reference count.

This reference count is intended to be incremented every time a reference to either object is created. These are initially set to 1 and when decremented to 0 the objects are freed by calling a free callback stored within each structure. This obviously only works if the code remembers to increment and decrement the reference counts properly and correctly lock access across multiple threads when handling the respective structures.

Within raspptp.sys, the code that performs the reference increment and de-increment functionality usually looks like this:

// Increment code
_InterlockedIncrement(&Ctx->ReferenceCount);

// Decrement Code
if ( _InterlockedExchangeAdd(&Ctx->ReferenceCount, 0xFFFFFFFF) == 1 )
    ((void (__fastcall *)(CtxType *))Ctx->fpFreeHandler)(Ctx);

As you may have guessed at this point, the vulnerability we’re looking at is indeed due to incorrect handling of these reference counts and their respective locks, so now that we have covered the background stuff let’s jump into the juicy details!

The Vulnerability

The first part of our use after free vulnerability is in the code that handles receiving PPTP control data for a client connection. When new data is received by raspptp.sys the WSK layer will dispatch a call the the appropriate event callback. raspptp.sys registers a generic callback for all sockets called ReceiveData. This function parses the incoming data structures from WSK and forwards on the incoming data to the client sockets contexts own receive data call back. For a PPTP control connection, this callback is the CtlReceiveCallback function.

The section of the ReceiveData function that calls this callback has the following pseudo code. This snippet includes all the locking and reference increments that are used to protect the code against multi threaded access issues…

_InterlockedIncrement(&ClientCtx->ConnectionContextRefernceCount);
((void (__fastcall *)(PptpCtlCtx *, PptpCtlInputBufferCtx *, _NET_BUFFER_LIST *))ClientCtx->ContextRecvCallback)(
ClientCtx->ContextPtr,
lpCtlBufferCtx,
NdisNetBuffer);

the CtlReceiveCallback function has the following pseudo code:

__int64 __fastcall CtlReceiveCallback(PptpCtlCtx *PptpCtlCtx, PptpCtlInputBufferCtx *PptpBufferCtx, _NET_BUFFER_LIST *InputBufferList)
{
    PptpCtlCtx *lpPptpCtlCx;
    PNET_BUFFER lpInputFirstNetBuffer;
    _NET_BUFFER_LIST *lpInputBufferList;
    ULONG NetBufferLength;
    PVOID NetDataBuffer;

    lpPptpCtlCx = PptpCtlCtx;
    lpInputFirstNetBuffer = InputBufferList->FirstNetBuffer;
    lpInputBufferList = InputBufferList;
    NetBufferLength = lpInputFirstNetBuffer->DataLength;
    NetDataBuffer = NdisGetDataBuffer(lpInputFirstNetBuffer, lpInputFirstNetBuffer->DataLength, 0i64, 1u, 0);
    if ( NetDataBuffer )
        CtlpEngine(lpPptpCtlCx, (uchar *)NetDataBuffer, NetBufferLength);
        ReceiveDataComplete(lpPptpCtlCx->CtlWskClientSocketCtx, lpInputBufferList);
        return 0i64;
}

The CtlpEngine function is the state machine responsible for parsing the incoming PPTP control data. Now there is one very important piece of code that is missing from these two sections and that is any form of reference count increment or locking for the PptpCtlCtx object!

Neither of the callback handlers actually increment the reference count for the PptpCtlCtx or attempt to lock access to signify that it is in use; this is potentially a vulnerability because if at any point the reference count was to be decremented then the object would be freed! However, if this is so bad, why isnt every PPTP server just crashing all the time? The answer to this question is that the CtlpEngine function actually uses the reference count correctly.

This is where things get confusing. Assuming that the raspptp.sys driver was completely single threaded, this implementation would be 100% safe as no part of the receive pipeline for the control connection decrements the object reference count without first performing an increment to account for it. In reality however, raspptp.sys is not a single threaded driver. Looking back at the initialization of the PptpCtlCtx object, there is one part of particular interest.

TimerCharacteristics.FunctionContext = PptpCtlCtx;
TimerCharacteristics.TimerFunction = (PNDIS_TIMER_FUNCTION)CtlpWaitTimeout;
if ( NdisAllocateTimerObject(
    lpNDISMiniportHandle_1,
    &TimerCharacteristics,
    &lpPptpCtlCtx->CtlWaitTimeoutNdisTimerHandle) )

Here we can see the allocation of an Ndis timer object. The actual implementation of these timers isn’t important, but what is important is that these timers dispatch there callbacks on a separate thread to that of which WSK dispatches the ReceiveData callback. Another interesting point is that both use the PptpCtlCtx structure as their context structure.

So what does this timer callback do and when does it happen? The code that sets the timer is as follows:

NdisSetTimerObject(newClientCtlCtx->CtlWaitTimeoutNdisTimerHandle, (LARGE_INTEGER)-300000000i64, 0, 0i64);// 30 second timeout timer

We can see that a 30 second timer trigger is set and when this 30 seconds is up, the CtlpWaitTimeout callback is called. This 30 second timer can be canceled but this is only done when a client performs a PPTP control handshake with the server, so assuming we never send a valid handshake after 30 seconds the callback will be dispatched. But what does this do?

The CtlpWaitTimeout function is used to handle the timer callback and it has the following pseudo code:

LONG __fastcall CtlpWaitTimeout(PVOID Handle, PptpCtlCtx *Context)
{
    PptpCtlCtx *lpCtlTimeoutEvent;

    lpCtlTimeoutEvent = Context;
    CtlpDeathTimeout(Context);
    return KeSetEvent(&lpCtlTimeoutEvent->CtlWaitTimeoutTriggered, 0, 0);
}

As we can see the function mainly serves to call the eerily named CtlpDeathTimeout function, which has the following pseudo code:

void __fastcall CtlpDeathTimeout(PptpCtlCtx *CtlCtx)
{
    PptpCtlCtx *lpCtlCtx;
    __int64 Unkown;
    CHAR *v3;
    char SockAddrString;

    lpCtlCtx = CtlCtx;
    memset(&SockAddrString, 0, 65ui64);
    if...
        CtlSetState(lpCtlCtx, CtlStateUnknown, Unkown, 0);
        CtlCleanup(lpCtlCtx, 0);
}

This is where things get even more interesting. The CtlCleanup function is the function responsible for starting the process of tearing down the PPTP control connection. This is done in two steps. First, the state of the Control connection is set to CtlStateUnknown which means that the CtlpEngine function will be prevented from processing any further control connection data (kind of). The second step is to push a task to run the similarly named CtlpCleanup function onto a background worker thread which belongs to the raspptp.sys driver.

The end of the CtlpCleanup function contains the following code that will be very useful for us being able to trigger a use after free as it will always run on a different thread to the CtlpEngine function.

result = (unsigned int)_InterlockedExchangeAdd(&lpCtlCtxToCleanup->CtlCtxReferenceCount, 0xFFFFFFFF);
if ( (_DWORD)result == 1 )
    result = ((__int64 (__fastcall *)(PptpCtlCtx *))lpCtlCtxToCleanup->fpCtlCtxFreeFn)(lpCtlCtxToCleanup);

It decrements the reference count on the PptpCtlCtx object and even better is that no part of this timeout pipeline increments the reference count in a way that would prevent the free function from being called!

So, theoretically, all we need to do is find some way of getting the CtlpCleanup and CtlpEngine function to run at the same time on seperate threads and we will be able to cause a Use after Free!

However, before we celebrate too early, we should take a look at the function that actually frees the PptpCtlCtx function because it is yet another callback. The fpCtlCtxFreeFn property is a callback function pointer to the CtlFree function. This function does a decent amount of tear down as well but the bits we care about are the following lines

WskCloseSocketContextAndFreeSocket(CtlWskContext);/
lpCtlCtxToFree->CtlWskClientSocketCtx = 0i64;
...
ExFreePoolWithTag(lpCtlCtxToFree, 0);

Now there is more added complication in this code that is going to make things a little more difficult. The call to WskCloseSocketContextAndFreeSocket actually closes the client socket before freeing the PptpCtlCtx structure. This means that at the point the PptpCtlCtx structure is freed, we will no longer be able to send new data to the socket and trigger any more calls into CtlpEngine. However, this doesn’t mean that we can’t trigger the vulnerability, since if data is already being processed by CtlpEngine when the socket is closed we simply need to hope the thread stays in the function long enough for the free to occur in CtlFree and boom – we have a UAF.

Now that we have a good old fashioned kernel race condition, let’s take a look at how we can try to trigger it!

The Race Condition

Like any good race condition, this one contains a lot of moving parts and added complication which make triggering it a non trivial task, but it’s still possible! Let’s take a look at what we need to happen.

  1. 30 second timeout is triggered and eventually runs CtlCleanup, pushing a CtlpCleanup task onto a background worker thread queue.
  2. Background worker thread wakes up and starts processing the CtlpCleanup task from its task queue.
  3. CtlpEngine starts or is currently processing data on a WSK dispatch thread when the CtlpCleanup function frees the underlying PptpCtlCtx structure from the worker thread!
  4. Bad things happen…

Triggering the Race Condition

The main parts of this race condition to consider are what are the limits on the data can we send to the server to spend as much time as possible in CtlpEngine parsing loop and can we do this without cancelling the timeout?

Thankfully as previously mentioned the only way to cancel the timeout is to perform a PPTP control connection handshake, which technically means we can get the CtlpEngine function to process any other part of the control connection, as long as we don’t start the handshake. However the state machine within CtlpEngine needs the handshake to take place to enable any other part of the control connection!

There is one part of the CtlpEngine state machine that can still be partially validly hit (without triggering an error) before the handshake has taken place. This is the EchoRequest control message type. Now we can’t actually enter the proper handling of the message type before the handshake has taken place but what we can do is use it to iterate through all the sent data in the parsing loop without triggering a parsing error. This effectively forms a way of us spinning inside the CtlpEngine function without cancelling the timeout which is exactly what we want. Even better is that this remains true when the CtlStateUnknown state is set by the CtlCleanup function.

Unfortunately the maximum amount of data we can process in one WSK receive data event callback trigger is limited to the maximum data that can be received in one TCP packet. In theory this is 65,535 bytes but due to the size limitation of Ethernet frames to 1,500 bytes we can only send ~1,450 bytes (1,500 minus the headers of the other network layer frames) of PPTP control messages in a single request. This works out at around 90 EchoRequest messages per callback event trigger. For a modern CPU this is not a lot to churn through before hopping out of the CtlpEngine function.

Another thing to consider is how do we know if the race condition was successful or a failure? Thankfully in this regard the server socket being closed on timeout works in our favour as this will cause a socket exception on the client if we attempt to send any more data once the server closes the socket. Once the socket is closed we know that the race is finished but we don’t necessarily know if we did or didn’t win the race.

With these considerations in place, how do we trigger the vulnerability? It actually becomes a simple proof of concept. Effectively we just continually send EchoRequest PPTP control frames in 90 frame bursts to a server until the timeout event occurs and then we hope that we’ve won the race.

We won’t be releasing the PoC code until people have had a chance to patch things up but when the PoC is successful we may see something like this on our target server:

Because the PptpCtlCtx structure is de-initialised there are a lot of pointers and properties that contain invalid values that, if used at different parts of the Receive Event handling code, will cause crashes in non fun ways like Null pointer deference’s. This is actually what happened in the Blue Screen of Death above, but the CtlpEngine function did still process a freed PptpCtlCtx structure.

Can we use this vulnerability for anything more than a simple BSOD?

Exploitation

Due to the state of mitigation in the Windows kernel against memory corruption exploits and the difficult nature of this race condition, achieving useful exploitation of the vulnerability is not going to be easy, especially if seeking to obtain Remote Code Execution (RCE). However, this does not mean it is not possible to do so.

Exploitability – The Freed Memory

In order to asses the exploitability of the vulnerability, we need to look at what our freed memory contains and where about it is in the Windows kernel heap. In windbg we can use the !pool command to get some information on the allocated chunk that will be freed in our UaF issue.

ffff828b17e50d20 size: 2a0 previous size: 0 (Allocated) *PTPT

We can see here that the size of the freed memory block is 0x2a0 or 672 bytes. This is important as it puts us in the allocation size range for the variable size kernel heap segment. This heap segment is fairly nice for use after free exploitation as the variable size heap also maintains a free list of chunks that have been freed and their sizes. When a new chunk is allocated this free list is searched and if a chunk of an exact or greater size match is found it will be used for the new allocation. Since this is the kernel, any other part of the kernel that allocates non paged pool memory allocations of this or a similar size could end up using this freed slot as well.

So, what do we need in order to start exploiting this issue? ideally we want to find some allocated object in the kernel that we can control the contents of and allocate at 0x2a0 bytes in size. This would allow us to create a fake PptpCtlCtx object, which we can then use to control the CtlpEngine state machine code. Finding an exact size match allocation isn’t the only way we could groom the heap for a potential exploit but it would certainly be the most reliable method.

If we can take control of a PptpCtlCtx object what can we do? One of the most powerful bits of this vulnerability from an exploit development perspective are the callback functions located inside the PptpCtlCtx structure. Usually a mitigation called Control Flow Guard (CFG) or Xtended Flow Guard (XFG) would prevent us from being able to corrupt and use these callback pointers with an arbitrary executable kernel address. However CFG and XFG are not enabled for the raspptp.sys driver (as of writing this blog) meaning we can point execution to any instruction located in the kernel. This gives us plenty of things to abuse for exploitation purposes. A caveat to this is that we are limited to the number of these gadgets we can use in one trigger of the vulnerability, meaning we would likely need to trigger the vulnerability multiple times with different gadgets to achieve a full exploit or at least that’s the case on a modern Windows kernel.

Exploitability – Threads

Allocating an object to fill our freed slot and take control of kernel execution through a fake PptpCtlCtx object sounds great, but one additional restriction on the way in which we do this is that we only have access to CtlpEngine using the freed object for a short period of CPU time. We can’t use the same thread that is processing the CtlpEngine to allocate objects to fill the empty slot, and if we do it would be after the thread has returned from CtlpEngine. At this point the vulnerability will no longer be exploitable.

What this means is that we would need the fake object allocations to be happening in a separate thread in the hope that we can get one of our fake objects allocated and populated with our fake object contents while the vulnerable kernel thread is still in CtlpEngine, allowing us to then start doing bad things with the state machine. All of this sounds like a lot to try and get done in relatively small CPU windows, but it is possible that it could be achieved. The issue with any exploit attempting to do this is going to be reliability, since there is a fairly high chance a failed exploit would crash the target machine and retrying the exploit would be a slow and easily detectable process.

Exploitability – Local Privilege Escalation vs Remote Code Execution

The ability to exploit this issue for LPE is much more likely to be successful over the affected Windows kernel versions than exploiting it for RCE. This is largely due to the fact that an RCE exploit will need to be able to first leak information about the kernel using either this vulnerability or another one before any of the potential callback corruption uses would be viable. There are also far fewer parts of the kernel accessible remotely, meaning finding a way of spraying a fake PptpCtlCtx object into the kernel heap remotely is going to be significantly harder to achieve.

Another reason that LPE is a much more viable exploit route is that the localhost socket or 127.0.0.1 allows for far more data than the ethernet frame capped 1,500 bytes we get remotely, to be processed by each WSK Receive event callback. This significantly increases most of the variables for achieving successful exploitation!

Conclusion

Wormable Kernel Remote Code Execution vulnerabilities are the holy grail of severity in modern operating systems. With great power however comes great responsibility. While this vulnerability could be catastrophic in its impact ,the skill to pull off a successful and undetected exploit is not to be underestimated. Memory corruption continues to become a harder and harder art form to master, however there are definitely those out there with the ability and determination to achieve the full potential of this vulnerability. For these reasons CVE-2022-21972 is a vulnerability that represents a very real threat to internet connected Microsoft based VPN infrastructure. We recommend that this vulnerability is patched with priority in all environments.

Timeline

  • Vulnerability Reported To Microsoft – 29 Oct 2021
  • Vulnerability Acknowledged – 29 Oct 2021
  • Vulnerability Confirmed – 11 November 2021
  • Patch Release Date Confirmed – 12 November 2021
  • Patch Release – 10 May 2022

The post CVE-2022-21972: Windows Server VPN Remote Kernel Use After Free Vulnerability (Part 1) appeared first on Nettitude Labs.

CVE-2022-23253 – Windows VPN Remote Kernel Null Pointer Dereference

22 March 2022 at 09:00

CVE-2022-23253 is a Windows VPN (remote access service) denial of service vulnerability that Nettitude discovered while fuzzing the Windows Server Point-to-Point Tunnelling Protocol (PPTP) driver. The implications of this vulnerability are that it could be used to launch a persistent Denial of Service attack against a target server. The vulnerability requires no authentication to exploit and affects all default configurations of Windows Server VPN.

Nettitude has followed a coordinated disclosure process and reported the vulnerability to Microsoft. As a result the latest versions of MS Windows are now patched and no longer vulnerable to the issue.

Affected Versions of Microsoft Windows Server

The vulnerability affects most versions of Windows Server and Windows Desktop since Windows Server 2008 and Windows 7 respectively. To see a full list of affected windows versions check the official disclosure post on MSRC: https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-23253.

Overview

PPTP is a VPN protocol used to multiplex and forward virtual network data between a client and VPN server. The protocol has two parts, a TCP control connection and a GRE data connection. The TCP control connection is mainly responsible for the configuring of buffering and multiplexing for network data between the client and server. In order to talk to the control connection of a PPTP server, we only need to connect to the listening socket and initiate the protocol handshake. After that we are able to start a complete PPTP session with the server.

When fuzzing for vulnerabilities the first step is usually a case of waiting patiently for a crash to occur. In the case of fuzzing the PPTP implementation we had to wait a mere three minutes before our first reproducible crash!

Our first step was to analyse the crashing test case and minimise it to create a reliable proof of concept. However before we dissect the test case we need to understand what a few key parts of the control connection logic are trying to do!

The PPTP Handshake

PPTP implements a very simple control connection handshake procedure. All that is required is that a client first sends a StartControlConnectionRequest to the server and then receives a StartControlConnectionReply indicating that there were no issues and the control connection is ready to start processing commands. The actual contents of the StartControlConnectionRequest has no effect on the test case and just needs to be validly formed in order for the server to progress the connection state into being able to process the rest of the defined control connection frames. If you’re interested in what all these control packet frames are supposed to do or contain you can find details in the PPTP RFC (https://datatracker.ietf.org/doc/html/rfc2637).

PPTP IncomingCall Setup Procedure

In order to forward some network data to a PPTP VPN server the control connection needs to establish a virtual call with the server. There are two types of virtual call when communicating with a PPTP server, these are outgoing calls and incoming calls. To to communicate with a VPN server from a client we typically use the incoming call variety. Finally, to set up an incoming call from a client to a server, three control message types are used.

  • IncomingCallRequest – Used by the client to request a new incoming virtual call.
  • IncomingCallReply – Used by the server to indicate whether the virtual call is being accepted. It also sets up call ID’s for tracking the call (these ID’s are then used for multiplexing network data as well).
  • IncomingCallConnected – Used by the client to confirm connection of the virtual call and causes the server to fully initialise it ready for network data.

The most important bit of information exchanged during call setup is the call ID. This is the ID used by the client and server to send and receive data along that particular call. Once a call is set up data can then be sent to the GRE part of the PPTP connection using the call ID to identify the virtual call connection it belongs to.

The Test Case

After reducing the test case, we can see that at a high level the control message exchanges that cause the server to crash are as follows:

StartControlConnectionRequest() Client -> Server
StartControlConnectionReply() Server -> Client
IncomingCallRequest() Client -> Server
IncomingCallReply() Server -> Client
IncomingCallConnected() Client -> Server
IncomingCallConnected() Client -> Server

The test case appears to initially be very simple and actually mostly resembles what we would expect for a valid PPTP connection. The difference is the second IncomingCallConnected message. For some reason, upon receiving an IncomingCallConnected control message for a call ID that is already connected, a null pointer dereference is triggered causing a system crash to occur.

Let’s look at the crash and see if we can see why this relatively simple error causes such a large issue.

The Crash

Looking at the stack trace for the crash we get the following:

... <- (Windows Bug check handling)
NDIS!NdisMCmActivateVc+0x2d
raspptp!CallEventCallInConnect+0x71
raspptp!CtlpEngine+0xe63
raspptp!CtlReceiveCallback+0x4b
... <- (TCP/IP Handling)

What’s interesting here is that we can see that the crash does not not take place in the raspptp.sys driver at all, but instead occurs in the ndis.sys driver. What is ndis.sys? Well, raspptp.sys in what is referred to as a mini-port driver, which means that it only actually implements a small part of the functionality required to implement an entire VPN interface and the rest of the VPN handling is actually performed by the NDIS driver system. raspptp.sys acts as a front end parser for PPTP which then forwards on the encapsulated virtual network frames to NDIS to be routed and handled by the rest of the Windows VPN back-end.

So why is this null pointer dereference happening? Let’s look at the code to see if we can glean any more detail.

The Code

The first section of code is in the PPTP control connection state machine. The first part of this handling is a small stub in a switch statement for handling the different control messages. For an IncomingCallConnected message, we can see that all the code initially does is check that a valid call ID and context structure exists on the server. If they do exist, a call is made to the CallEventCallInConnect function with the message payload and the call context structure.

case IncomingCallConnected:
    // Ensure the client has sent a valid StartControlConnectionRequest message
    if ( lpPptpCtlCx->CtlCurrentState == CtlStateWaitStop )
    {
        // BigEndian To LittleEndian Conversion
        CallIdSentInReply = (unsigned __int16)__ROR2__(lpCtlPayloadBuffer->IncomingCallConnected.PeersCallId, 8);
        if ( PptpClientSide ) // If we are the client
            CallIdSentInReply &= 0x3FFFu; // Maximum ID mask
            // Get the context structure for this call ID if it exists
            IncomingCallCallCtx = CallGetCall(lpPptpCtlCx->pPptpAdapterCtx, CallIdSentInReply);
            // Handle the incoming call connected event
            if ( IncomingCallCallCtx )
                CallEventCallInConnect(IncomingCallCallCtx, lpCtlPayloadBuffer);

The CallEventCallInConnect function performs two tasks; it activates the virtual call connection through a call to NdisMCmActivateVc and then if the returned status from that function is not STATUS_PENDING it calls the PptpCmActivateVcComplete function.

__int64 __fastcall CallEventCallInConnect(CtlCall *IncomingCallCallCtx, CtlMsgStructs *IncomingCallMsg)
{
    unsigned int ActiveateVcRetCode;
    ...
ActiveateVcRetCode = NdisMCmActivateVc(lpCallCtx->NdisVcHandle, (PCO_CALL_PARAMETERS)lpCallCtx->CallParams);
if ( ActiveateVcRetCode != STATUS_PENDING )
{
    if...
        PptpCmActivateVcComplete(ActiveateVcRetCode, lpCallCtx, (PVOID)lpCallCtx->CallParams);
    }
return 0i64;
}

...

NDIS_STATUS __stdcall NdisMCmActivateVc(NDIS_HANDLE NdisVcHandle, PCO_CALL_PARAMETERS CallParameters)
{
    __int64 v2; // rbx
    PCO_CALL_PARAMETERS lpCallParameters; // rdi
    KIRQL OldIRQL; // al
    _CO_MEDIA_PARAMETERS *lpMediaParameters; // rcx
    __int64 v6; // rcx

    v2 = *((_QWORD *)NdisVcHandle + 9);
    lpCallParameters = CallParameters;
    OldIRQL = KeAcquireSpinLockRaiseToDpc((PKSPIN_LOCK)(v2 + 8));
    *(_DWORD *)(v2 + 4) |= 1u;
    lpMediaParameters = lpCallParameters->MediaParameters;
    if ( lpMediaParameters->MediaSpecific.Length < 8 )
        v6 = (unsigned int)v2;
    else
        v6 = *(_QWORD *)lpMediaParameters->MediaSpecific.Parameters;
        *(_QWORD *)(v2 + 136) = v6;
        *(_QWORD *)(v2 + 136) = *(_QWORD *)lpCallParameters->MediaParameters->MediaSpecific.Parameters;
        KeReleaseSpinLock((PKSPIN_LOCK)(v2 + 8), OldIRQL);
    return 0;
}

We can see that in reality, the NdisMCMActivateVc function is surprisingly simple. We know that it always returns 0 so there will always be a proceeding call to PptpCmActivateVcComplete by the CallEventCallInConnect function.

Looking at the stack trace we know that the crash is occurring at an offset of 0x2d into the NdisMCmActivateVc function which corresponds to the following line in our pseudo code:

lpMediaParameters = lpCallParameters->MediaParameters;

Since NdisMCmActivateVc doesn’t sit in our main target driver, raspptp.sys, it’s mostly un-reverse engineered, but it’s pretty clear to see that the main purpose is to set some properties on a structure which is tracked as the handle to NDIS from raspptp.sys. Since this doesn’t really seem like it’s directly causing the issue we can safely ignore it for now. The particular variable lpCallParameters (also the CallParameters argument) is causing the null pointer dereference and is passed into the function by raspptp.sys; this indicates that the vulnerability must be occurring somewhere else in the raspptp.sys driver code.

Referring back to the call from CallEventCallInConnect we know that the CallParmaters argument is actually a pointer stored within the Call Context structure in raspptp.sys. We can assume that at some point in the call to PptpCmActivateVcComplete this structure is freed and the pointer member of the structure is set to zero. So lets find the responsible line!

void __fastcall PptpCmActivateVcComplete(unsigned int OutGoingCallReplyStatusCode, CtlCall *CallContext, PVOID CallParams)
{
    CtlCall *lpCallContext; // rdi
    ...
if ( lpCallContext->UnkownFlag )
{
    if ( lpCallParams )
        ExFreePoolWithTag((PVOID)lpCallContext->CallParams, 0);
        lpCallContext->CallParams = 0i64;
        ...

After a little bit of looking we can see the responsible sections of code. From reverse engineering the setup of the CallContext structure we know that the UnkownFlag structure variable is set to 1 by the handling of the IncomingCallRequest frame where the CallContext structure is initially allocated and setup. For our test case this code will always execute and thus the second call to CallEventCallInConnect will trigger a null pointer dereference and crash the machine in the NDIS layer, causing the appropriate Blue Screen Of Death to appear:

Proof Of Concept

We will release proof of concept code on May 2nd to allow extra time for systems administrators to patch.

Timeline

  • Vulnerability reported To Microsoft – 29 Oct 2021
  • Vulnerability acknowledged – 29 Oct 2021
  • Vulnerability confirmed – 11 Nov 2021
  • Patch release date confirmed – 18 Jan 2022
  • Patch released – 08 March 2022
  • Blog released – 22 March 2022

The post CVE-2022-23253 – Windows VPN Remote Kernel Null Pointer Dereference appeared first on Nettitude Labs.

KDU v1.2 release and the wonderful world of Microsoft incoherency

By: hfiref0x
19 February 2022 at 09:36

It's been a while since last KDU update and thanks to Artem Baranov from Kaspersky my attention is again on it. The new 1.2 release contain eight new providers and set of additional changes that were required for new providers work. Here is list of new providers added, the details on each are following:

  • GMER "antirootkit"
  • Dell BIOS Utility (assigned CVE-2021-21551)
  • Mimikatz "Mimidrv"
  • Process Hacker "KProcessHacker2"
  • Process Explorer "ProcExp152"
  • Dell BIOS Utility (assigned CVE-2021-36276)
  • Cheat Engine
  • ASUS GPU Tweak II/III (EneTech next-gen)
And after describing new providers we will take a tour into wonderful world of Microsoft incoherency with their newest Win10/Win11 drivers blacklist managed by CI.dll

Providers description 

(number is ID in KDU database)

15. GMER "antirootkit"

Pic 1. What could possible go wrong here

GMER "antirootkit", I'm familiar with this software since it birth and introduction by author (Przemyslaw Gmerek) on SysInternals forums during Rustock's first variants most active period. Since it first release it was a mediocre software with limited capabilities to detect or remove anything despite author claims (he still has a dedicated gallery on his long forgotten site). Since I was developing the same toolset during that time I of course reverse-engineered GMER to find out if there is anything interesting in it. It sounds fun but this is exactly how things were going in the 2005-2010 anywhere with tools developed by enthusiasts. Amount of copy-pasted techniques and code from different authors in different tools of this time is tremendous. GMER driver doesn't surprised me and except obvious bugs I didn't found anything else interesting in it, except number of simple ways how to completely make it blind in case of rootkit detection (we later implemented one of in our laboratory rootkit called Unreal so Gmerek was forced to do an emergency update 😅). Remember, it was year 2006 and Windows XP was all around and shiny again after general Vista fuckup. Entire class of this software died around 2011-2013 so I was surprised that GMER actually managed not only survive but move to x64 world. Ohh, better he doesn't. The actual x64 driver made of copy-paste from x86 version with few things adjusted to make it work on x64 and some features that are bound to x86 only completely removed. For some unknown reason it still has a branches of code that doesn't make any sense on x64, that shows how actually author didn't care about final product. Since acquiring by Avast their Avast MBR tool contain exact the same driver from GMER (because it's powered by "GMER technology", this is a fucking rofl yeah). From current perspective this driver is a wormhole and I'm surprised no one actually tried to exploit it for a fancy CVE id, almost just like Trend Micro tool highlighted in one of my previous posts. For KDU usage the most prominent features of GMER are arbitrary kernel virtual memory read and write. This is not a bug, it is intentionally created mess so GMER can read/write kernel memory via it's process. This feature implemented via MDL mapping and accessible with dedicated IOCTL with simple data structure. One important note is that before calling this (or any other IOCTL) you have to talk with GMER driver first to let it know it was "initialized". This is done with a special IOCTL. Note that GMER driver sets exclusive flag when creating it device object, however when application crash driver stays in memory and accessible for everyone.

TL;DR - current GMER is completely useless (and dangerous due to multiple bugs, just look on pic 1 - few seconds before BSOD) in terms of "rootkit detection" usage and represent a security risk by containing Windows security bypasses available without any proper verification of caller nor access checks. 

16. Dell BIOS Utility (assigned CVE-2021-21551)

This one is pretty simple and well described in CVE entry. This is a typical flaw in giveio-type drivers. It has memmove with completely user controlled parameters send by special IOCTL.  Such "features" aren't so rare in the wonderful world of hardware vendors drivers.

17. Mimikatz "Mimidrv"

This is auxiliary driver from Mimikatz tool which is open-source. Mimikatz is a well known tool and a lot of people found it damn useful. Well I'm not one of them. Speaking of mimidrv - it has full source available and by opening this source you will want to close it ASAP to not hurt your eyes with amount of shitcode you will face. It's a complete bugged wormhole which has number of built binaries with different versions all signed with a valid certificate. No wonder Microsoft banned this certificate in their HVCI blocklist which we will discuss later. We are interested here in arbitrary kernel virtual memory read/write IOCTL's, in fact they are almost the same as in GMER. You don't need any special preconditions to start using mimidrv. Here is the details on other features of mimidrv - Mimidrv In Depth: Exploring Mimikatz’s Kernel Driver if you are interested.

18. Process Hacker "KProcessHacker2"

It is famous tool and I remember how it was born. Process Hacker come at SysInternals forum with wj32 in the late 00s in form of open source task manager replacement written in C#. It was immediately criticized for this by forum members and after some reconsiderations wj32 ported it on more suitable programming language (thankfully there wasn't any cancer like Rust popular that days). PH roots from Windows XP era with same design and philosophy. That's how it started and worked just fine until Turla malware group widely popularized BYOVD (Bring Your Own Vulnerable Driver) attacks in 2014-2015. The mentioned PH driver KProcessHacker2 was abused by multiple actors starting from malware and ending up with cheat community. This followed with wave of antivirus detections and game bans. All because of this tool initial design and philosophy from Windows XP era. That is why it was full of wormhole functionality and still have it up-to-date. What is so unique in this driver? It provides a set of IOCTL's which work as Windows API replacements for several key to the Windows security functions. Just a few of them for example: OpenProcess, OpenThread, DuplicateHandle, TerminateThread, TerminateProcess, Set/GetThreadContext, Read/WriteProcessMemory. Natural hackbox isn't it? Earlier versions of PH code (which all nicely written and well documented) even contain remarks where author hopes that this driver client "is not a virus" so wj32 clearly predicted things can go worse 😏 We will go back to PH in the end of this post. For KDU tasks this driver maybe not looking good at first glance (it looks like more suitable for malware usage 😂), but then if you look on the things from a different perspective - hell yeah. Here is why - starting from ancient Windows NT versions up to latest Windows 10 release "System" process keeps handle to physical memory section. It was abused before for physical memory access and later Microsoft banned it from user mode usage by setting object header flag -> kernel only access so you can't open new handle for this section from the user mode. Later MS added protected processes feature which additionally blocked exploitation because you can't open "System" process with sufficient rights. And here Process Hacker driver comes to the rescue with it hackbox IOCTL's allowing us: open full process handle for "System" process, duplicate physical memory section handle to our process with same full access rights. Further is trivial. Important note about fancy new Windows 10 rebrand called Windows 11. There is no physical memory section handle in "System" process as I observed and it is too boring to figure out is it intentional or need any preconditions to make it popup again - you may consider this as homework.

19. Process Explorer "ProcExp152"

Rival of previous task manager. Or previous task manager is a rival to this, or new Windows 10/11 taskmanager is a rival to both or vice versa or..., I don't really follow this "task manager market war" which is a complete bullshit, just the fact that Process Explorer existed long before PH release and PH "release to public" place was Process Explorer developers forums. This is a small handy tool developed by Mark Russinovich before his acquiring by Microsoft and abandoning all his tools (they are now out-sourced to some Microsoft geniuses who decided to remake classic UI with new over overstretched buttons and idiotic bitmaps ruining your old UI experience, and oh-ah "dark mode" I forgot about it). Process Explorer driver provide limited set of features that works almost the same as hackbox from PH. Have you heard about AV detecting Process Explorer as malware? I didn't, maybe because it is signed by Microsoft?😄 Anyway, this driver does have access checks implemented at dispatch routine so it fits into Microsoft wonderland of what they call "security boundaries". It doesn't really matter for BYOVD, this driver allows process opening, handle duplication, process termination and more. It is used in KDU in a similar manner as KProcessHacker2 driver. Oh, it even re-used next by KDU as placeholder for the final shellcode, what an irony.

20. Dell BIOS Utility (assigned CVE-2021-36276)

The same as previous Dell driver except it has different steps required for loading and new device name. In fact this is example of "fix" similar to that I described in my previous blogpost. TL;DR Dell fixed nothing and posed this driver update as ultimate fix for previously reported vulnerabilities. KDU exploits 2.5 version driver as I didn't bothered to find 2.7, but from all the description etc it will work the same way on 2.7 you only need to change device name.

21. Cheat Engine

Pic 2. Cheat Engine 7.4

Infamous open-source tool mostly used for game cheating and cracking. Has a kernel mode component called DBK (DarkByte Kernel?) which is a wormhole by design with WHQL signature, yeah. This driver abused by malware in recent GhostEmperor attacks. KDU uses similar pattern to write and execute code in kernel mode. Cheat Engine author tried to complicate his driver usage by 3rd parties (most likely by other cheat programs) by introducing few pseudo-security checks implemented on driver side. None of them can be considered as sufficient and mentioned above malware fully bypass them. KDU uses driver from the up-to-date Cheat Engine 7.4 package and proxy application "kernelmodeunloader.exe" from the same package. This driver is in HVCI blocklist. Warning to these who want to try: while installing Cheat Engine package (from official site) may install you a bunch of scamware if you won't pay attention to installation process and just spam "Next" clicks. Note that Cheat Engine driver has some problems with Windows 7, so it may not work or load here.

Pic 3. Cheat Engine DBK load failure, Windows 7



22. ASUS GPU Tweak II/III (EneTech next-gen)

It is implementation of what is stated in my previous blogpost. Nothing changed since that time, ASUS continuously use this trash in a number of it software products up to date. Side note, they also introduced new driver which looks like heavy remake of original WinIO with most of it dangerous features stripped, however not all. It is a something to investigate later.

HVCI blocklist or welcome to wonderful world of Microsoft incoherency


This feature introduced with HVCI on Windows 10. It is implemented as blocklist stored in \systemroot\system32\codeintegrity\driversipolicy.p7b file as certificate blob and specific code at CI.DLL to manage it. Decoding this "driverspolicy" data maybe accomplished with the following PowerShell script -> https://gist.github.com/mattifestation/92e545bf1ee5b68eeb71d254cec2f78e. Microsoft maintains current state of this list on github -> https://github.com/MicrosoftDocs/windows-itpro-docs/blob/public/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-driver-block-rules.md. This blocklist is loaded and parsed by CI.DLL in kernel mode and invoked when HVCI is enabled (Core Isolation -> Memory Integrity) and something is trying to load driver. If this driver (authenticode hash, page hash, filename from version block, filename and version range from version block) found in blocklist Windows will deny it loading and log event. Presumable this list will be updated and each new Windows 1X "release" will bring brand new blocklist. Or they even managed to do it auto updating didn't checked that, at least previous Windows 10 versions doesn't seems update it since install.

Lets take Process Hacker discussed above, but latest version, and try to load it as admin with HVCI enforced:

Pic 4. HVCI enforced block of kprocesshacker.sys


With event 5038 added to the system security event log: 

Code integrity determined that the image hash of a file is not valid.  The file could be corrupt due to unauthorized modification or the invalid hash could indicate a potential disk device error.

File Name: \Device\HarddiskVolume3\ProcessHacker\kprocesshacker.sys

and NTSTATUS codes like STATUS_IMAGE_CERT_REVOKED and STATUS_DRIVER_UNABLE_TO_LOAD. This is actual Process Hacker v3.0 with valid digital signature and KProcessHacker3 which is immune to previous abuse by malware and cheaters. 

Why is this happening or welcome to wonderful world of Microsoft incoherency.

Microsoft added Process Hacker (PH) to HVCI blocklist just recently. There are no live examples of Process Hacker v3 abuse by malware except one from Crowdstrike dated back to 2019 and updated in the Dec 2021, https://www.crowdstrike.com/blog/how-doppelpaymer-hunts-and-kills-windows-processes/. This post gives you a brief to supposedly PH driver malicious usage involving full bypass of it integrated client verification introduced in 2.39 and still used in 3.0+. From that post you will learn that over-engineered approach which is used almost everywhere in PH code doesn't guarantee security and wormhole features are still can be used by 3rd party if they really want to. From my point of view malware authors has nothing else to do by choosing Process Hacker driver as their "provider" because:
  1. There are exist alternatives with much simpler (or none at all) verification logic, using them you can achieve the same "terminator" features;
  2. Process Hacker already signatured by various FakeAV as PUP/Tool/HackTool (or TrojanMulDrop lol) because it different old versions are used by malware and they share scan patterns.
Or they just wanted to piss-off PH authors showing them bypass of it over-engineered verification. Why then Microsoft doesn't considers its own Process Explorer (PE) driver as malicious security breaking tool? Lets leave aside "because it Microsoft signed lol" or "because it fits into security boundaries, have you saw secure device and SePrivilegeCheck?". If you compare how exactly PH and PE drivers does their "process" management you will notice that PH actually does it on lower level than PE. There are other functionally which is also should not exist at all - like duplicating handles, write/reading arbitrary processes memory, changing thread contexts etc. But lets start with simple thing, how PH and PE both acquire process handles. 

PH uses PsLookupProcessThreadByCid/PsLookupProcessByProcessId and ObOpenObjectByPointer. This allows it to skip ordinary access checks, ETW logging and... bypass some of the security products relying on filtering. It is basically reimplemented ntoskrnl ZwOpenProces->PsOpenProcess function with all the Se validation replaced with PH client/call verification. In comparison PE simple calls ZwOpenProcess with GENERIC_ALL desired access value. Both approaches are terrible piece of shit and comes from Windows XP era. If you need a handle to process/thread etc - use usermode call, that's is the only solid way to guarantee security and audit. If you still insist on accessing protected processes then entire operation should only take place in kernel after Windows security verification without returning anything important to usermode. Any termination/memory read/write from driver should be banned at all. This will however turn off "hacking" features of products as they won't be able to open/read/write everything. Sorry guys but this is how Windows now designed - if you not a part of trusted system code you can't access what ever you want. And there we have a dilemma - two drivers with wormhole functionality ideal for BYOVD attacks. One maintained open-source project, second proprietary Microsoft code without updates for decades. Both used by malware including APT. One in HVCI blocklist, second nope. I call this bullshit, Microsoft. What about PH, guys you are fucking process manager with extended features, not a Windows subsystem to replace or reinvent the MS security wheel just because you have nothing else to do and want to practice with system programming. Your "multi-purposing" is actually playing against you and serves no other purpose. You already removed a lot of "hacking" code from Process "Hacker" and still have a lot to remove/rework. Leave all this "hacking" to where it started - in the Windows XP era.

Another piece in this blocklist that attracted my attention is a number of strange drivers MS added seems by lurking on unknowncheats.me forum, including leaked certificates. Well it is good to know you lurk on most currently famous forum dedicated to kernel mode rootkits (what an irony yeah).

VBoxDrv innotek entry brings good old memories of Turla and later DSEFix/TDL. The only question here is why innotek only. Unlike popular opinion the exploit used by Turla group wasn't previously disclosed and therefore fixed in next versions, so basically it was a zeroday. This entire confuse makes you think that VirtualBox has only innotek signed Turla-style exploitable drivers. Meanwhile I would remember you that Sun acquired innotek GmbH in 2008 and later VirtualBox versions came out signed by Sun certificate. Since this vulnerability in vboxdrv wasn't fixed - all vboxdrv drivers at least up to 3.0 version are equally vulnerable and can be easily adopted to be used like in DSEFix or TDL 😉 (which was already done by some Chinese APT few years ago). Strange that this is not noticed by Microsoft.

Pic 5. The old the new thing

Ideally this blocklist should be twice or triple size bigger with only what is available on public today. No iobit, zemana fakeav drivers, no mihoyo, other anticheat crapware, no nVidia trash, no endless MSI packs of crap. Are you kidding, Microsoft? This is all available and exploitable. Right here, right now. Stop being a slowpoke, I've cookie for you.

People That

By: hfiref0x
5 November 2020 at 06:32

Succ 

(c) Andrea Allievi aka aall64
Pic 1. What is all about.

When you interact with software and it developing company (in face of some developers) sometimes you meet a bunch of company fanatics. Those are people who actually jumped into the wagon not so long time ago but already think they are part/have rights on anything - they are deeply identify themselves with company they are working now. It is of course true if we take this from the commercial point of view and inter company communications. From the other (public) side this creates a problem of fanaticism. It is when you are become brainwashed at that level so you start to see things that does not exist. This depends on people but unfortunately it is a common trend. And they are not necessary devil advocates.

For example, any criticism targeting products of their company they take with pain in their own asses. And it does not matter if this criticism is valid or not.

Usually it starts with classic sentence - "If you don't %verb% %my company/product% then why you still %verb% it". E.g. - "if you don't like Windows then why you still use it". Such sentences used as a typical indicator of upcoming demagogy attack next.

So what is all about?

Meet the proud Microsoft fanatic who are unhappy with recent blogpost I made.

Pic 2. Meet aall64.
 

Long story short - he read (as he said) that https://swapcontext.blogspot.com/2020/10/uacme-35-wd-and-ways-of-mitigation.html. This ignited his butt very well and he went to me expressing his deep displeasure along with the demonstration of a rich imagination and the ability to see what is not exist.

Who is this guy? It is Microsoft employee that formerly worked in PrevX. Infamous MD5 calculators NextGen AV developing company with always lurking copy-pasters on various forums and EraserHW (Marco G.) as main PR man at charge who was linked to the fake overestimated malware campaigns of Gromozon/LinkOptimizer in 2006. This toxic active has been acquired by Webroot in the end of 2010 and later went to special hell dedicated for hash calculators NextGen AV. Andrea is a current co-author of that yet another full of water Russinovich book edition (which 3rd edition copy I accidentally bought in 2006, when actually liked it those days). Also he is a "proud Microsoft guy" (as he said). I know about him 10 years. This guy come up to kernelmode.info in 2010 with his pet project called AntiTdl. He come here after advice from wilderssecurity.com forums where he initially posted his project. Casuals from that forum wasn't happy with it (they wasn't able to deal with it), so following their advice he registered on kernelmode.info and posted stuff. That is how we meet. This project was already out-dated, extremely bugged and was basically useless. However no one said a word against it, and KM community (including me) welcomed and provided all possible support to this author. Because sharing knowledge is always great idea. You can find this in kernelmode.info by searching with google "antitdl site:kernelmode.info". Next he come up to TDL4 reversing and other kind of bootkits, along the way he did plagiarism on existing content (https://twitter.com/Fyyre/status/155383565943701504). 

Pic 3. 2 years delay reply, rofl.
 

Next there was something about PatchGuard (another doubtful technology from MS) and he ended up surprisingly in Microsoft. I actually glad that he made his way from a mediocre half-fake AV company to the MSFT, good job.

Here is what exactly he does not like in my mentioned article about UAC. I specifically asked him about this because his initial claims has nothing to do with actual article context - it simple does not have anything he said. This is what he answered to me in a DM which I next made public.

Pic 4. "I see dead people everywhere".

To make it more readable, here is the part of article as screenshot.

Pic 5. Comedy Section Bonus part screenshot.

First, lets begin with "edited" statement.

His first tweet with accusations was 29 October 2020, it is on picture 2. The DM conversation take place 31 October 2020. So following this guy logic (I really hope it is not the same when he code anything), I edited material in between of his first tweet (29 Oct) and my answer to it few hours later.

Unfortunately to this guy there is a Google Cache of my blogpost available from 27 October -> https://webcache.googleusercontent.com/search?q=cache:_dzbCypL044J:https://swapcontext.blogspot.com/2020/+&cd=5&hl=ru&ct=clnk&gl=en&client=firefox-b-d (this google cache page saved to WebArchive additionally now).

This article has never been edited after publication. I have no habit of changing anything after it became public, except and only if I fix typos. However, if you remember his glorious way to Microsoft, you should remember this guy already familiar with plagiarism so probably he just projected his own habits on me.

Since we are dealing with a typical fanatic he still can claim that he read it before 27 Oct (and I don't have google cache earlier that date), so I magically got notified about that reading fact, magically imagined his reaction and edited content doing that in a stealth mode. It is ridiculous but from this guy I can expect anything now.

The context of the bonus of this article is describing typical social media behavior taking place each year. So this part "Woohoo, Windoze Byp@$$3d M1cr0$0ft SuXx!" is not my words and not a projection of my options. It is what people say and mean. I don't know Andrea aka aall86, are you seriously thinking you are dealing with a sort of 14 year old script-kiddie here? What is the 86 here btw, year of birth or IQ rate?

The last part about "s3curity r3s3arch3rs", I've to decipher to Andrea, is about mister "DimopoulosElias" a guy who stuck in copy-pasta, use google for more info. Now put here your imagined "MiCro$oft sucks" and try to read this sentence again. It actually will lose all sense.

All these lying accusations is just weak attempt to hide actual reason of Andrea butt ignition. If you read this article it contains a lot of criticism. And harsh part related to Windows Defender. It is not the first time Andrea come ups trying to defend this crappy Microsoft imposed product. The last time he was defending that brain-dead Microsoft employees who multiple times signatured Process Hacker - popular open source software. So this guy read this vertically, butt ignited and he hang on the most notable sentences for him from this article (the magic number of 86 don't forget) completely ignoring not only their context but actual text, because I don't know what kind of reading skills you should have to read "s3curity r3s3arch3rs" as "MiCro$oft sucks" 😆

Pic 6. DM part


Yes, you just a dumbfuck fanatic 👌. Mister aall86 insisted during "conversation" via DM so he got a dedicated blogpost, achievement unlocked.

Conclusions:

1. Always backup your original content with ability for others track any changes in it. You can use WebArchive and save your page after publication or copy contents to the some public git repository, so everybody will be able do a simple fact-check and track exact changes.

2. PrevX as indicator in people portfolio. Take such guys with a caution. Yes it is a sad thing but almost all of them I know ended up to be like this guy. It is PrevX curse and knowing this company past and key personalities of it - I should not be that surprised.

3. Since all his content now viewed through the prism of the above events - as of the "book" he co-writes - well, thankfully, it is now 2020 and not 2001-2005 so if you for some unknown reason still want to learn anything(new) about Windows internals you can always find a alternate way instead of this water pool. Remember one simple thing - since beginning, this book was a perfect illustration of Microsoft inability to write somewhat decent public documentation, MSDN is when they do this not because they want to, but because they have to. That's explains failing quality of available content. And to compensate this here we came up with sort of fan-fictions which are approved and welcomed by company.

Top Security QuickFails: #5 Angriff der KlonAdmins aka Missing LAPS

29 November 2021 at 07:49
#5 Angriff der KlonAdmins aka Missing LAPS Der Angriff In der FaulerHund AG in München starten die Mitarbeiter in ein neues Geschäftsjahr und freuen sich auf neue Herausforderungen. So auch der Administrator Karl KannNixDafür, welcher am Donnerstag Mittag gegen 12:30 festgestellt hat, dass der Account von Ute Unbeschwert noch angemeldet ist, obwohl diese gegen 11 […]

DGAs – Generating domains dynamically

5 November 2020 at 09:49

A domain generation algorithm is a routine/program that generates a domain dynamically. Think of the following example:

An actor registers the domain evil.com. The corresponding backdoor has this domain hardcoded into its code. Once the attacker infects a target with this malware, it will start contacting its C2 server.

As soon as a security company obtains the malware, it might blacklist the registered domain evil.com. This will hinder any attempts of the malware to receive commands from the original C2.

If a domain generation algorithm would have been used, the domain will be generated based on a seed. The current date for example is a popular seed amongst malware authors. A simple domain blacklisting would not solve the problem. The security company will have to resort to different methods.

By generating domains dynamically, it is harder for defenders to hinder the malware from contacting its C2 server. It will be necessary to understand the algorithm.

Example implementation of a DGA

A quick & dirty implementation(loosely based on Wikipedia)[1] of such algorithm could look like this:

"""Example implementation of a domain generation algorithm."""

import sys
import time
import random


def gen_domain(month, day, hour, minute):
    """Generate the domain based on time. Return domain"""
    print(
        f"[+] Gen domain based on month={month} day={day} hour={hour} min={minute}")
    domain = ""
    for i in range(8):
        month = (((month * 8) ^ 0xF))
        day = (((day * 8) ^ 0xF))
        hour = (((hour * 8) ^ 0xF))
        minute = (((minute * 8) ^ 0xF))
        domain += chr(((month * day * hour * minute) % 25) + 0x61)
    return domain


try:
    while True:
        d = gen_domain(random.randint(1, 12), random.randint(1, 30),
                       random.randint(0, 24), random.randint(0, 60))
        print(f"[+] Generated domain = {d}")
        time.sleep(5)
except KeyboardInterrupt:
    sys.exit()

Our DGA algorithm would use the current date and time as a seed. Each parameter is multiplied with 8 and XOR’d with 0xF. Finally all four values are multiplied with each other. The final operations are used to make sure that we generate a character in small caps. The output of this program looks like this:

[+] Gen domain based on month=12 day=2 hour=4 min=4
[+] Generated domain = taavtaab.com
[+] Gen domain based on month=3 day=10 hour=11 min=36
[+] Generated domain = kugxfkvx.com
[+] Gen domain based on month=2 day=27 hour=4 min=1
[+] Generated domain = kaasuapn.com

Seed or Dictionary based

There are different main approaches when implementing a domain generation algorithm. For the sake of keeping this simple, we will not focus on the hybrid approach.

Different kinds of approaches

Seed based Approach

We already introduced the first one. Our implementation is an algorithm based on a seed, which is served as an input. Another example I can provide, is how APT34 used such seed based algorithm in a campaign targeting a government organisation in the Middle East. The campaign was discovered by FireEye[2].

The mentioned APT group used domain generation algorithms in one of their downloaders. The Downloader was named BONDUPDATER by FireEye and is implemented in the Powershell Scripting Language.

BONDLOADER DGA algorithm

The first 12 chars of the UUID is extracted. Next the program runs into a loop. Each iteration a new random number is generated and the domain is generated by concatenating hardcoded, as well as generated values. GetHostAddresses will try to resolve the generated domain. If it fails, a new iteration starts. Once a registered domain is generated and resolved, it will break the loop.

Depending on the resolved ip address, the script will trigger different actions.

Dictionary based Approach

The second approach is to create a dictionary based domain generation algorithm. Instead of focusing on a seed, a list of words could be provided. The algorithm randomly selects words from these lists, concatenates them and generates a new domain. Suppobox[3] is a malware, which implemented the dictionary based approach[4].

Defeating Domain Generation Algorithms

The straight forward way to counter these algorithms is to reverse engineer the routine and to predict future domains. One famous case of predicting future domains is the takedown of the Necurs Botnet by Microsoft[5]. By understanding the DGA, they were able to predict the domains for the next 25 months.

I am not a ML magician. However, just a quick google research shows that there is a lot research going on. Machine Learning based approaches to counter DGAs seems to be promising too.

❌
❌