Normal view

There are new articles available, click to refresh the page.
Today — 18 June 2024Vulnerabily Research

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

18 June 2024 at 12:00
Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

Exploring malicious Windows drivers (Part 2): The I/O system, IRPs, stack locations, IOCTLs and more

This blog post is part of a multi-part series, and it is highly recommended to read the first entry here before continuing.

As the second entry in our “Exploring malicious Windows drivers” series, we will continue where the first left off: Discussing the I/O system and IRPs. We will expand on these subjects and discuss other aspects of the I/O system such as IOCTLs, device stacks and I/O stack locations, as all are critical components of I/O operations. 

In this series, we’ll introduce the concepts of drivers, the Windows kernel and basic analysis of malicious drivers. Please explore the links to code examples and the Microsoft documentation, as it will provide context for the concepts discussed here. 

I/O operations are extremely powerful, as they allow an attacker to perform a wide array of actions at the kernel level. With kernel-level access, an attacker could discreetly capture, initiate or alter network traffic, as well as access or alter files on a system. Virtualization protections such as Virtual Secure Mode can aid in defense against malicious drivers, although it is not enabled by default in a typical Windows environment. Even when these protections are enabled, certain configurations are required to effectively defend against kernel mode drivers.

The capability of a malicious driver is only limited by the skill level and knowledge of the individual writing it and the configuration of the target system. However, writing a reliable malicious driver is quite difficult as there are many factors that must be taken into consideration during development. One of these factors is correctly implementing I/O operations without crashing the target system, which can easily occur if the proper precautions are not taken.  

The I/O system, I/O request packets (IRPs) and device stacks:

As discussed in the previous entry, the I/O manager and the other components of the executive layer encapsulate data being sent to drivers within I/O request packets (IRPs). All IRPs are represented as the structure defined as “_IRP” in wdm.h:

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

 

IRPs are the result of a system component, driver or user-mode application requesting that a driver perform an operation it was designed to do. There are several ways that a request can be made, and the methods of doing so differ between user-mode and kernel-mode requestors.

Requests: User mode

The I/O request is one of the fundamental mechanisms of the Windows kernel, as well as user mode. Simple actions in user mode such as creating a text file requires that the I/O system create and send IRPs to drivers. The action of creating a text file and storing it on the hard drive involves multiple drivers sending and receiving IRPs until the physical changes are made on the disk.

One possible scenario where a user-mode application would initiate a request is calling the ReadFile routine, which can instruct the driver to perform some type of read operation. If the application passes a handle to a driver’s device object as the hFile parameter of ReadFile, this will tell the I/O manager to create an IRP and send it to the specified driver. 

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

 To get the appropriate handle to pass, the application can call the function CreateFile and pass the driver’s device name as the lpFileName parameter. If the function completes successfully, a handle to the specified driver is returned.

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more
 Note: The name of the CreateFile function is often misleading, as it implies that it only creates files, but it also can open files or devices and return a handle to them. 
Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

 As seen in the example above, the value of “\\\\.\\IoctlTest” is passed in the lpFileName parameter. When passing the device name as a parameter it must be prepended with “\\.\'' and since the backslashes must be escaped, it becomes “\\\\.\\”.

Requests: Kernel mode

For a system component or a driver to send an IRP, it must call the IoCallDriver routine with a DEVICE_OBJECT and a pointer to an IRP (PIRP) provided as parameters. It is important to note that IoCallDriver is essentially a wrapper for IofCallDriver, which Microsoft recommends should never be called directly. 

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

 While they are an important part of driver functionality, we will not be discussing requests between drivers. 

Device nodes and the device tree

Before we continue discussing IRPs – to better understand their purpose and functionality – it’s necessary to first explain the concept of device stacks and the device tree.

To reach its intended driver, an IRP is sent through what is referred to as a “device stack,” or sometimes as a “device node” or “devnode”. A device stack can be thought of as an ordered list of device objects that are logically arranged in a layered “stack.” Each layer in this stack consists of a DEVICE_OBJECT structure that represents a specific driver. It is important to note that drivers are not limited to creating only one device object, and it is quite common that a driver creates multiple. 

Note: Technically, “device stack” and “device node” have slightly different definitions, although they are often used interchangeably. Even though they ultimately mean the same thing, their contexts differ. “Device stack” specifically refers to the list of device objects inside of a “device node” of the device tree.

Each device node, and the device stack inside of it, represents a device or bus that is recognized by the operating system, such as a USB device, audio controller, a display adapter or any of the other various possible types. Windows organizes these device nodes into a larger structure called the “device tree” or the “Plug and Play device tree.”

Nodes within the tree are connected through parent/child relationships in which they are dependent on the other nodes connected to them. The lowest node in the tree is called the “root device node,” as all nodes in the tree's hierarchy eventually connect to it through relationships with other nodes. During startup the Plug and Play (PnP) manager populates the device tree by requesting connected devices to enumerate all child device nodes. For an in-depth look at how the device tree and its nodes work, the MSDN documentation can be found here

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

A representation of a device tree. Source: MSDN documentation.

At this point, the device tree can essentially be thought of as a kind of map of all the drivers, buses and devices that are installed on or connected to the system. 

Device types

Of the device objects that can make up the layers within each device stack, there can be three types: physical device object (PDO), functional device object (FDO) and filter device object (FiDO). As shown below, a device object’s type is determined by the functionality of the driver that created it: 

  • PDO: Not physical, but rather a device object created by a driver for a particular bus, such as USB or PCI. This device object represents an actual physical device plugged into a slot.
  • FiDO: Created by a filter driver (largely outside the scope of this series). A driver that sits between layers that can add functionality to or modify a device.
  • FDO: Created by a driver that serves a function for a device connected to the system. Most commonly these will be drivers supplied by vendors for a particular device, but their purposes can vary widely. This blog post series pertains mostly to FDOs, as many malicious drivers are this type.  

For more information on the different object types see the MSDN documentation here.

Just as with the device tree, the PnP manager is also responsible for loading the correct drivers when creating a device node, starting with the lowest layer. Once created, a device stack will have a PDO as the bottom layer and typically at least one FDO. However, FiDOs are optional and can sit between layers or at the top of the stack. Regardless of the amount of device objects or their types, a device stack is always organized as a top-down list. In other words, the top object in the stack is always considered the first in line and the bottom is always the last. 

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

When an IRP is sent, it doesn’t go directly to the intended driver but rather to the device node that contains the target driver’s device object. As discussed above, once the correct node has received the IRP, it begins to pass through it from a top-to-bottom order. Once the IRP has found the correct device node, it needs to get to the correct layer within it, which is where I/O stack locations come into play.

I/O stack locations

When an IRP is allocated in memory, another structure called an I/O stack location – defined as IO_STACK_LOCATION – is allocated alongside it. There can be multiple IO_STACK_LOCATIONs allocated, but there must be at least one. Rather than being part of the IRPs structure, an I/O stack location is its own defined structure that is “attached” to the end of the IRP.

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

 The number of I/O stack locations that accompany an IRP is equal to the number of device objects in the device stack that the IRP is sent to. Each driver in the device stack ends up being responsible for one of these I/O stack locations, which will be discussed shortly. These stack locations help the drivers in the device stack determine if the IRP is relevant to them. If it is relevant, then the requested operations will be performed. If the IRP is irrelevant, it’s passed to the next layer.

The IO_STACK_LOCATION structure contains several members that a driver uses to determine an IRP’s relevance.

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

The first members of the structure are MajorFunction and MinorFunction, which we discussed in the first part of this series. These members will contain the function code that was specified when the IRP was created and sent to the driver receiving it. A function code represents what the request is asking the driver to do. For example, if the IRP contains the IRP_MJ_READ function code, the requested action will be a read of some type. As for MinorFunction, it is only used when the request involves a minor function code, such as IRP_MN_START_DEVICE

The Parameters member of the structure is a large union of structures that can be used in conjunction with the current function code. These structures can be used to provide the driver with more information about the requested operation, and each structure can only be used in the context of a particular function code. For instance, if MajorFunction is set to IRP_MJ_READ, Parameters.Read can be used to contain any additional information about the request. Later in this post, we will revisit the Parameters member on processing IOCTLs. For the complete description of Parameters and the remaining members of the structure, refer to this MSDN documentation entry here.

IRP flow

Regardless of the types of device objects within a device stack, all IRPs are handled the same way once they reach the intended device node. IRPs are “passed” through the stack from top to bottom, through each layer until it reaches the intended driver. Once it has passed through the layers and completed its task, it is passed back up through the node, from bottom to top and then returned to the I/O manager.

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

 While the IRP is passing through the stack, each layer needs to decide what to do with the request. There are several different actions that can be taken by the driver responsible for a layer in the stack. If the request is intended for the layer processing it, it can process the request in whichever way it was programmed to do. However, if the request isn’t relevant, it will then be passed down the stack to the next layer. If the receiving layer is related to a filter driver, it can then perform its functions – if applicable – and pass the request down the stack.

When the request is passed into a layer, the driver receives a pointer to the IRP (PIRP) and calls the function IoGetCurrentIrpStackLocation, passing the pointer as the parameter.

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

This routine lets the driver check the I/O stack location that it is responsible for in the request, which will tell the driver if it needs to perform operations on the request or pass it to the next driver.

If a request does not pertain to the driver in a layer, the IRP can be passed down to the next layer – an action frequently performed by filter drivers. A few things need to happen before the request is passed to a lower layer. The function `IoSkipCurrentIrpStackLocation` needs to be called, followed by `IoCallDriver`. The call to `IoSkipCurrentIrpStackLocation` ensures that the request is passed to the next driver in the stack. Afterwards, IoCallDriver is called with two parameters: a pointer to the device object of the next driver in the stack and a pointer to the IRP. Once these two routines are complete, the request is now the responsibility of the next driver in the stack.

If a driver in the stack receives a request that is intended for it, the driver can complete the request in whatever way it was designed to. Regardless of how it handles the request, IoCompleteRequest must be called once it has been handled. Once IoCompleteRequest is called, the request makes its way back up to the stack and eventually returns to the I/O manager.

For a thorough description of the flow of IRPs during a request, refer to the following entries in the MSDN documentation:

Handling and completing IRPs

As discussed in the first post in this series, a driver contains functions called “dispatch routines,” which are called when the driver receives an IRP containing a MajorFunction code that it can process. Dispatch routines are one of the main mechanisms that give drivers their functionality and understanding them is critical when analyzing a driver.

For example, if a driver has a dispatch routine called `ExampleRead` that handles the `IRP_MJ_READ` function code, that routine will be executed when it processes an IRP containing `IRP_MJ_READ`. Since that dispatch routine handles `IRP_MJ_READ` – as the name implies – it will be performing some type of read operation. This function code is commonly related to functions such as `ReadFile` or `ZwReadFile`. For more information regarding dispatch routines and how they function, the MSDN documentation is highly recommended, and can be found here

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

Example of assigning MajorFunction codes to dispatch routine entry points.

Bringing it all together

Putting all this information regarding I/O requests together, it becomes much easier to visualize the process. While there are plenty of aspects of the process that aren't discussed here – as there are too many to fit them all into a series – we have walked through the core logic behind requesting, processing and completing an I/O request. Below is a brief summary of the flow of a typical I/O request:

  • The I/O manager creates the IRP and attaches the necessary I/O stack locations.
  • The IRP is then sent to the appropriate device stack.
  • The IRP passes through the stack until it reaches the device object of the target driver. Each driver in the stack either processes the request or passes it down to the next layer.
  • When the request reaches the correct layer, the driver is called.
  • The driver reads the MajorFunction member of the I/O stack location and executes the dispatch routine associated with the function code.
  • IoCompleteRequest is called once the driver has completed its operations and the IRP is passed up back through the stack.
  • The IRP returns to the I/O manager.

Understanding these concepts provides the foundation for learning the more complex and intricate parts of drivers and the Windows kernel. Learning about these topics takes time and direct interaction with them, as they are inherently complicated and, in many ways, can appear abstract. 

Device input and output control, IOCTLs: 

IRPs can deliver requests in a slightly different way than what has been described so far. There is another mode of delivering requests drivers employ that makes use of what are called I/O control codes (IOCTLs). Device Input and Output Control, sometimes referred to as IOCTL as well, is an interface that allows user mode applications and other drivers to request that a specific driver execute a specific dispatch routine assigned a pre-defined I/O control code. 

Note: To eliminate confusion, the use of “IOCTL” in this blog series will be referring to I/O control codes, not “Device Input and Output Control.”

An IOCTL is a hardcoded 32-bit value defined within a driver that represents a specific function in that same driver. IOCTL requests are delivered by IRPs, much in the same way as described above. However, there are specific MajorFunction codes used in these requests. While both user-mode applications and drivers can both initiate these requests, there are slight differences in the requirements for doing so.

MajorFunction codes and IOCTLs

The MajorFunction codes related to IOCTLs are delivered the same way as the function codes discussed so far. They are delivered via an IRP that is sent by the I/O manager which in turn is received by the driver and processed. All IOCTL requests use either IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL, which are assigned to a driver’s dispatch routine entry point in the same manner described earlier.

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

Assigning IRP_MJ_DEVICE_CONTROL to a dispatch routine entry point. Source: GitHub

While IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL are both used for processing IOCTLs, they serve slightly different purposes. In cases where an IOCTL will be made available for use by a user-mode application, IRP_MJ_DEVICE_CONTROL must be used. In the situation of an IOCTL only being available to other drivers, IRP_MJ_INTERNAL_DEVICE_CONTROL must be used instead.

Defining an IOCTL

To process an IOCTL, a driver must define and name it, and implement the function that is to be executed when it's processed. IOCTLs are usually defined in a header file by using a system-supplied macro named CTL_CODE:

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

When naming an IOCTL Microsoft recommends using the “IOCTL_Device_Function” naming convention, as it makes it easier to read and understand. The following example of this convention is provided on MSDN: “IOCTL_VIDEO_ENABLE_CURSOR”. Applications and drivers commonly pass the IOCTL’s name as a parameter when making a request – rather than the 32-bit value – which highlights the importance of the readability and consistency of the naming convention.

Aside from establishing the IOCTL’s name, CTL_CODE also takes four arguments: 

  • DeviceType: This value must be set to the same value as the DeviceType member of the driver’s DEVICE_OBJECT structure, which defines the type of hardware the driver was designed for. For further information on device types, refer to the MSDN documentation here
  • Function: The function that will be executed upon an IOCTL request; represented as a 32-bit hexadecimal (DWORD) value, such as 0x987. Any value that is less than 0x800 is reserved for use by Microsoft. 
  • Method: The method used to pass data between the requester and the driver handling the request. This can be set to one of four values: METHOD_BUFFERED, METHOD_IN_DIRECT, METHOD_OUT_DIRECT or METHOD_NEITHER. For more information on these methods, refer to the links regarding memory operations provided in the next section.
  • Access: The level of access required to process the request. This can be set to the following values: FILE_ANY_ACCESS, FILE_READ_DATA or FILE_WRITE_DATA. If the requester needs both read and write access, FILE_READ_DATA and FILE_WRITE_DATA can be passed together by separating them using the OR “|” operator: FILE_READ_DATA | FILE_WRITE_DATA. 
Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

Example of defining IOCTLs. Source: GitHub.

Note: The image above is from a header file for a driver from the Microsoft “Windows-driver-samples” GitHub repository. An invaluable resource for learning about Windows drivers. Microsoft has included a plethora of source code samples that demonstrate the implementation of many of the documented WDM and KMDF functions and macros. Also, all the samples contain helpful comments to provide context.

Processing IOCTL requests

Once an I/O control code is defined, an appropriate dispatch function needs to be implemented. To handle IOCTL requests, drivers will commonly have a function that is named using the “XxxDeviceControl” naming convention. For example, the function that handles I/O control requests in this Microsoft sample driver uses the name “SioctlDeviceControl”.

In common practice, these functions contain switch statements that execute different functions depending on the IOCTL it received. A thorough example of this can be found in Microsoft’s driver sample GitHub repository here

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

  As seen in the image above, this device control function takes two arguments: A pointer to a device object (PDEVICE_OBJECT DeviceObject) and a pointer to an IRP (PIRP Irp). The DeviceObject parameter is a pointer to the device that the initiator of the request wants the IOCTL to perform operations on. This could be a pointer to the device object of a directory, file, volume or one of the many other types of objects in the Windows environment. The second parameter the function takes is simply a pointer to the IRP that the driver received when the IOCTL request was sent.

Once the device control function is executed, it reads the `Parameters.DeviceIoControl.IoControlCode` member of the IRP structure that the driver received to retrieve the IOCTL. The IOCTL is then compared to the IOCTLs defined within the driver, and if there is a match, it executes the appropriate routine. Once the processing and the necessary clean-up has been done, the request can be completed by calling `IoCompleteRequest`.

DeviceIoControl

Requestors can initiate an IOCTL request by calling `DeviceIoControl`, in which several parameters may be passed. 

Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and more

 For the sake of simplicity, we will only be discussing the first two parameters: `hDevice` and `dwIoControlCode`. The rest of the parameters pertain to memory operations but are outside the scope of this blog post as the topic is complex and requires lengthy explanation. Interaction with data buffers is a common occurrence for drivers performing I/O operations; additionally, it is critical to become familiar with these concepts for conducting driver analysis. For further reading, the MSDN documentation is an excellent source of information. Relevant links are provided below:

When calling DeviceIoControl, the caller must provide a handle to the target driver’s device object and the IOCTL it is requesting. These parameters are passed as the arguments `hDevice` and `dwIoControlCode`, respectively. An important aspect of making an IOCTL request is that the caller must know the value of the I/O control code before requesting. Additionally, a driver must be able to handle receiving an unrecognized control code, otherwise it may crash.

Drivers sending IOCTLs to other drivers

In some instances, a higher-level driver needs to send an IOCTL request to a lower-level device driver, known as an “internal request.” These IOCTLs in particular are not available to be requested by a user-mode application and use the IRP_MJ_INTERNAL_DEVICE_CONTROL MajorFunction code. The dispatch routines that handle these requests are conventionally referred to as either DispatchDeviceControl when the driver receives IRP_MJ_DEVICE_CONTROL, or DispatchInternalDeviceControl when IRP_MJ_INTERNAL_DEVICE_CONTROL is received. The main distinction between the two is that DispatchDeviceControl handles requests that may originate from user mode, whereas DispatchInternalDeviceControl handles internal requests.

For the sake of brevity, the details of this process will not be discussed here. However, the details can be found in the MSDN documentation here. We’ll not be covering IOCTLs sent from one driver to another, but rather, IOCTLs sent from user-mode applications, as it is easier to become familiar with. Once the basics are understood, learning about I/O between drivers will be much easier. The topic of IOCTLs will be concluded in the next part of this series when we demonstrate debugging drivers.

Conclusion

Anyone interested in learning more should explore the provided links to the MSDN documentation and Microsoft’s sample driver GitHub repository for more in-depth information. The I/O section of the MSDN driver documentation is worth exploring and contains most of the entries that have been linked to in this blog post and can be found here.

In the next entry in this series, we will discuss installing, running and debugging drivers and the security concepts surrounding them. This will include a description of the basic setup and tooling required for analysis and knowing what to look for while performing it. To demonstrate the use of debuggers, we will show how a driver processes IOCTLs and executes dispatch routines.

How are attackers trying to bypass MFA?

18 June 2024 at 11:57
How are attackers trying to bypass MFA?

In the latest Cisco Talos Incident Response Quarterly Trends report, instances related to multi-factor authentication (MFA) were involved in nearly half of all security incidents that our team responded to in the first quarter of 2024. 

In 25% of engagements, the underlying cause was users accepting fraudulent MFA push notifications that originated from an attacker. In 21% of engagements, the underlying cause for the incident was a lack of proper implementation of MFA. 

I was curious to see what some of the reasons might be as to why these two issues were the top security weaknesses outlined in the report. To do so, I’ll explore (with the help of Cisco Duo’s AI and Security Research team and their push-based attack dataset) the parameters that attackers are using to send their fraudulent MFA attempts, including: 

  • The percentage of MFA push spray attacks accepted by the user. 
  • How many push requests a victim user was sent. 
  • Peak times of occurrence. 
  • Time between successive push attempts. 

I’ll also explore the current methods that attackers are using to bypass MFA or social engineer it to gain access.  

It’s worth noting that there has been a lot of progress made by defenders over the past few years regarding implementing MFA within their organizations. MFA has significantly contributed to reducing the effectiveness of classic credential stuffing and password spraying attacks by adding an extra layer of authentication. This is a large reason as to why attackers are targeting MFA so heavily – it’s a significant barrier they need to get around to achieve their goals.  

But as with any form of defense, MFA isn’t a silver bullet. The issues we’re seeing now are mostly down to attacker creativity to try and bypass MFA, and overall poor implementation of the solution (for example, not installing it on public-facing applications or EOL software). There are also some legitimate cases where MFA cannot be implemented by an organization, in which case, a robust access policy must be put in place. 

The data behind push spray attacks 

The most common type of MFA bypass attempts we see are MFA push attacks, where the attacker has gained access to a user’s password and repeatedly sends push notifications to their MFA-enabled device, hoping they will accept. 

We asked Cisco Duo’s AI and Security Research team to provide some metrics for push-based attacks from their attack dataset, which contains 15,000 catalogued push-based attacks from June 2023 - May 2024.  

In the first metric (the overall response to fraudulent pushes) we learn that most push-based attacks aren’t successful i.e., they are ignored or reported. Five percent of sent push attacks were accepted by users. 

How are attackers trying to bypass MFA?
Source: Duo AI and Security Research

However, of that 5%, it didn’t take many attempts to persuade the user to accept the push. Most users who accepted fraudulent pushes were sent between one and five requests, while a very small number were “bombarded” with 20 - 50 requests. 

How are attackers trying to bypass MFA?
Source: Duo AI and Security Research

The team also looked at the times of day when fraudulent push attempts were sent. The majority were sent between 10:00 UTC and 16:00, which is slightly ahead of U.S working hours. This indicates that attackers are sending push notifications as people are logging on in the morning, or during actual work hours – presumably hoping that the notifications are in context of their usual working day, and therefore less likely to be flagged. 

How are attackers trying to bypass MFA?
Source: Duo AI and Security Research

There is a large peak between 8 and 9 a.m. (presumably when most people are authenticating for the day). The small peak in the early evening is less clear cut, but one potential reason is that people may be on their phones catching up on news or social media, and may be more susceptible to an accidental push acceptance. 

Most authentications within a single push attack (sent from the same classified IP) occurred within 60 seconds of each other. As authentications timeout after 60 seconds, the most common “failure” reason was “No response.” 

Rather than a “spray-and-pray” approach, this data appears to indicate that attackers are being more targeted in their approach by sending a small number of push notifications to users within a certain period. If they don’t respond, they move onto the next user to try and target as many users as possible within the peak time of 8 – 9 a.m. 

Different examples of MFA bypass attempts

As well as push-based spray attacks, recently we have seen several instances where attackers have got a bit creative in their MFA bypass attempts.  

In speaking to several members of our Cisco Talos Incident Response team, here are some of the MFA bypass methods that they have seen used in security incidents, beyond the “traditional” MFA push-spray attacks: 

  1. Stolen authentication tokens from employees. Attackers then replay session tokens with the MFA check completed (giving the attackers a trusted user identity to move laterally across the network). 
  2. Social engineering the IT department to add new MFA enabled devices using the attacker’s device. 
  3. Compromising a company contractor, and then changing their phone number so they can access MFA on their own device. 
  4. Compromising a single endpoint, escalating their privileges to admin level, and then logging into the MFA software to deactivate it. 
  5. Compromising an employee (otherwise known as an insider attack) to click “allow” on an MFA push that originated from an attacker. 

The attacks outlined above don’t solely rely on MFA weaknesses – social engineering, moving laterally across the network, and creating admin access involves several steps where red flags can be spotted or ultimately prevented. Therefore, taking a holistic view of how an attacker might use MFA or social engineer their access to it is important. 

New MFA attack developments 

As the commercialization of cybercrime continues to increase with more attacks becoming available “as a service,” it’s worth paying attention to phishing-as-a-service kits that offer an element of MFA bypass as part of the tool. 

One such platform is the Tycoon 2FA phishing-as-a-service which relies on the attacker-in-the-middle (AiTM) technique. This isn’t anything new – the technique involves an attacker server (also known as reverse proxy server) hosting a phishing web page, intercepting victims’ inputs, and relaying them to the legitimate service.  

The tool has now incorporated the prompt of an MFA request. If the user accepts this, the server in the middle captures the session cookies. Stolen cookies then allow attackers to replay a session and therefore bypass the MFA, even if credentials have been changed in between. 

Cat and mouse

These push spray attacks and MFA bypass attempts are simply an evolution of cybersecurity defense. It’s the cat-and-mouse game that persists whenever defenders introduce new technology. 

When defenders introduced passwords, attackers introduced password-cracking methodology through rainbow tables, tools like Hashcat and GPU cards. Defenders countered this by introducing account lockout features. 

Attackers then introduced password spray attacks to obtain credentials through dedicated tools such as MSOLSpray. After that, defenders brought out MFA to add an additional credential check. 

Next, attackers developed dedicated tools like MFASweep to find gaps in the MFA coverage of organizations, looking for IP addresses and ranges, or specific OS platforms that are granted an exception. MFA bypass also contributed to a comeback of social engineering techniques. 

How are attackers trying to bypass MFA?

With the MFA bypass attempts that are happening in the field, defenders are now exploring various countermeasures. These include WebAuthn and inputting a four-digit number code into MFA tools such as Cisco Duo (requiring the user to input specific text is a stronger MFA method than say SMS). And considering a Zero Trust environment to include contextual factors, such as where and when the device is accessing the system. 

Recommendations

From an organizational/ defender point of view, here are some of Talos’ recommendations for implementing MFA: 

  • Consider implementing number-matching in MFA applications such as Cisco Duo to provide an additional layer of security to prevent users from accepting malicious MFA push notifications.  
  • Implement MFA on all critical services including all remote access and identity access management (IAM) services. MFA will be the most effective method for the prevention of remote-based compromises. It also prevents lateral movement by requiring all administrative users to provide a second form of authentication.  
  • Organizations can set up an alert for single-factor authentication to quickly identify potential gaps and changes in the MFA policy (if for example, MFA has been downgraded to a single factor authentication).  
  • Conduct employee education within the IT department to help prevent social engineering campaigns where attackers request additional MFA enabled devices or accounts. 
  • Conduct overall employee education about MFA bypass attacks and how they may be targeted. Provide clear reporting lines for alerting the organization to potential MFA attacks. 
  • In cases where MFA cannot be implemented, for example on some legacy systems that cannot be updated or replaced, work with your MFA vendor to define access policies for those systems and ensure they are separated from the rest of the network. 
  • Another potential authentication method is a Security key – a hardware device that requires a PIN. 

Read the latest Cisco Talos Incident Response Quarterly Trends report to learn more about the current threat trends and tactics. 

Read the Cisco Duo Trusted Access Report to examine trends (existing and emerging) in both access management and identity. 

❌
❌