In 2022 and 2023, Sophos X-Ops published research about a toolset to sabotage the functions of endpoint protection software that was being developed and used in conjunction with several major ransomware gangs. Mandiant had previously named this tool Poortry, and its loader application Stonestop.
The creators of the Poortry tool had managed to get purpose-built, custom kernel-level drivers signed through Microsoft’s attestation signing process. After we published our research — and Microsoft closed the loophole that allowed these drivers to be signed — the tool’s creators did not just stop. They have continued to add features and functionality to the Poortry driver, in an ongoing attempt to evade detection and to find new ways to disable EDR and endpoint protection software.
To explain the new features in Poortry, let’s review how drivers interact with the operating system, and how the developers of this EDR killer evolved their tool over time.
How Windows drivers can sabotage protection
Most EDR killers rely on a device driver being loaded into the operating system’s kernel, which gives them access to the kinds of low-level functionality to be able to unhook and terminate various kinds of protection software.
Under Windows, which supports a multitude of peripherals and connected components, kernel-mode drivers are given wide latitude to these kinds of low-level functions. Under normal circumstances, these drivers don’t interact with software or hardware from other companies or manufacturers, but there is no enforcement of this behavior. Thus, if a signed legitimate driver does not properly validate the processes interacting with it, EDR killers can exploit some of its features to remove protective measures.
Microsoft has developed a variety of ways that their operating systems can control whether drivers get loaded at all, such as the Driver Signature Enforcement mechanism: Drivers must be digitally signed by a software publisher Microsoft trusts before they can load.
The developers of EDR killers exploit the gaps in this trust model: They may use a driver vulnerable to abuse that was once published by a legitimate software company; They also might sign their own driver with a legitimate code-signing certificate (and there are many ways to obtain stolen or leaked certificates).
In general there are three ways EDR killer developers abuse code signatures:
Abuse of leaked certificates
This is the most straightforward way to handle the problem: Find a leaked, stolen, or otherwise compromised code-signing certificate from a legitimate company, and use it to sign your driver (or to trick Root Certificate Authorities into issuing a certificate to you).
For all versions of Windows that came after Windows 10 version 1607, Microsoft has required all third-party developers of kernel-mode drivers to submit their driver to Microsoft’s developer portal, to be cross-signed by Microsoft. However, cross-signed drivers not signed by Microsoft are still allowed to be loaded if it fulfills one of the following :
- The PC was upgraded from an earlier release of Windows to Windows 10, version 1607
- Secure Boot is switched off in the system BIOS
- Driver was signed with an end-entity certificate issued prior to July 29, 2015 that chains to a supported cross-signed CA
Even though the update lowered the danger of cross-signed drivers that had been signed by stolen certificates, the third bullet creates a loophole that enables the second method for attackers.
Signature timestamp forgery
In order to maintain compatibility with older drivers, Windows loads drivers signed with “an end-entity certificates issued prior to July 29, 2015 that chains to a supported cross-signed CA.”
When signing a kernel driver, Microsoft provides the software publisher with a tool named signtool.exe. In addition to signing the provided file, signtool also checks to ensure that the provided certificate is still valid. One way to ensure this is to use the function
Through a series of hooks to these low-level API calls inside the operating system, attackers can alter the signing process and bypass these checks to sign their own kernel driver. One of the functions being hooked in this technique is GetLocalTime to return a forged timestamp to pass through the checks in signtool.exe.
Bypassing Microsoft attestation signing
The final method is to get through Microsoft’s attestation signing process, and get the kernel driver signed directly by Microsoft. This is probably the most difficult to achieve, but also provides a signature a strong WHQL certificate that was issued by Microsoft itself – almost a holy grail of digital signatures.
To abuse this method, attackers need:
- A valid EV certificate
- Access to the Microsoft developer portal
If these requirements are fulfilled, they can prepare a CAB file, which includes the driver itself, sign it with the EV certificate, and submit it to the dashboard.
Once submitted, the driver undergoes several checks to ensure that the driver is not malicious. If the driver passes these tests, it will carry the “Microsoft Windows Hardware Compatibility Publisher” signature.
Poortry & Stonestop: A Relevant Threat Since 2022
Poortry (also sometimes called BurntCigar) is a malicious kernel driver used in conjunction with a loader named Stonestop by Mandiant, who first reported on the tool’s existence. The driver bypasses Driver Signature Enforcement by using any of the three techniques described above. Both are heavily obfuscated by commercial or open-source packers, such as VMProtect, Themida or ASMGuard.
From the end of 2022 to mid-2023, Poortry variants carried the Microsoft WHQL certificate. However, due to joint work Between Sophos X-Ops and Microsoft, most of this attestation signed samples were found and Microsoft deactivated the accounts that were abused to get those drivers signed.
Poortry’s creators were not deterred; Instead, they switched to either Signature Timestamp Forging or obtaining a valid leaked certificate.
Over the last year, we were able to link the use of Poortry to attacks involving at least five major ransomware families:
- CUBA
- BlackCat
- Medusa
- LockBit
- RansomHub
Since 2023, we’ve observed threat actors repeatedly use Poortry during attacks. One characteristic we observed in our earlier research is that Poortry’s creators change their packer frequently, creating a volume of slightly modified variants based off the original. In our research, we found multiple different WHQL-signed variants, packed with different commercial or non-commercial packers.
Since that venue was closed to them, Poortry’s makers now deploy the drivers signed by a wide variety of non-Microsoft certificates.
The figure below illustrates a timeline of the observed signer names used by Poortry’s payload driver over a 15 month period.
It is worthwhile mentioning that sometimes we make our observations during incident response engagements, and at other times collected as telemetry. One thing we can be sure of is that the total number and variety of certificates is larger than our observation alone can determine.
Playing certificate roulette
Sophos, from time to time, has observed a threat actor deploy variants of Poortry on different machines within a single estate during an attack. These variants contain the same payload, but signed with a different certificate than the driver first seen used during the attack.In August 2023, during a Sophos X-Ops investigation, we found that attackers gained initial access via a remote access tool named SplashTop. As soon as the attackers were on the network, they deployed Poortry and Stonestop. But the signer name, “bopsoft,” was already known as a stolen certificate, and was blocked using a behavioral rule.
Within 30 seconds after the last attempt using the “Bopsoft” signed code, the attackers were loading a different Poortry driver, this one signed by “Evangel Technology (HK) Limited.” The host was quickly isolated and the attack thwarted.
Transition from EDR killer To EDR wiper
In July 2024, while engaged in an incident where adversaries attempted to deploy RansomHub ransomware, Sophos CryptoGuard thwarted the attempted data encryption as analysts closed off the attackers’ points of access. A post-incident analysis revealed that two additional executables had been dropped on multiple machines prior to the final ransomware attack:
<d>\Users\<u>\desktop\c7iy3d.exe <d>\Users\<u>\appdata\local\temp\usnnr.sys
Through a combination of static and dynamic analysis, we determined the files to be Poortry and Stonestop. Among the differences we observed between the prior version and this version, Poortry now can also delete critical EDR components completely, instead of simply terminating their processes.
Trend Micro reported in 2023 that Poortry had developed the capability to delete files off disk, but this was the first time we observed this feature used in an attack.
A closer look at the latest variants
Both the Stonestop executable and the Poortry driver are heavily packed and obfuscated. This loader was obfuscated by a closed-source packer named ASMGuard, available on Github.
The driver is signed with a certificate carrying the signer name “FEI XIAO.” Sophos X-Ops has high confidence the signature timestamp was forged to sign the driver. Notably, it tries to masquerade by using the same information in its properties sheet as a driver (idmtdi.sys) for a commercially available software, Internet Download Manager by Tonec Inc. But it isn’t this software package’s driver – the attackers merely cloned the information from it.
For explanatory purposes, we divide the execution flow into three distinct phases.
Initialization Phase
In incidents we’ve tracked, threat actors drop Poortry and Stonestop together, into the same directory. On execution, Stonestop checks for the corresponding driver in the current directory.
The filename and device name of the driver are both hardcoded into the loader. Upon start, the loader fetches the handle of the malicious kernel driver and initiates a handshake by sending a hardcoded string to the driver via the DeviceIoControl API call.
Overall, communication between the components happens through this DeviceIoControl API. Each feature provided by the kernel-mode component is triggered via sending a different IOCTL code. Earlier variants communicated via the IRP_MJ_DEVICE_CONTROL handler. The current variant uses the IRP_MJ_MAXIMUM_FUNCTION handler now to receive I/O request packets.
It is worthwhile mentioning that the mappings from IOCTL code to feature has changed since our last analysis. As an example, the command to kill a specific process by process ID was triggered by sending an I/O request packet with code 0x222094. The latest sample maps the IOCTL code 0x222144 to the same functionality.
Since Trend Micro’s 2023 report, Poortry’s developers increased the number of receivable IOCTL codes from 10 to 22. Our analysis of all available features is still ongoing.
Like previous versions, a handshake is initiated by sending a hardcoded string to the driver. Once the handshake value is accepted, it sets a flag in the binary that enables the functionalities of the malicious driver.
Impairment Phase
The second phase is focused on disabling EDR products through a series of different techniques, such as removal or modification of kernel notify routines.
Security drivers make use of several different features provided by the Windows OS to register callbacks when specific events on the Windows system occur. An example would be the function PsSetCreateProcessNotifyRoutine, which adds a driver supplied callback routine when a new process is created.
Eliminating these callback routines are often a critical step to render EDR products useless. In 2022, we also wrote about a similar case where BlackByte ransomware abused a legitimate vulnerable driver to remove critical kernel notify routines.
In the second phase, we observed a total of seven distinct IOCTL codes are sent to the kernel-mode component. Only the functionality mapped to 0x222400 is executed. The other features bailed out early due to specific flags being set in the binary. We suspect that the non-triggered functionalities are either experimental, only triggered on specific type of systems, or simply disabled.
The IOCTL codes and their mapped behaviors are as follows:
0x2220C0 (Disabled)
When received, Poortry enters an additional initialization routine, fetching addresses of various critical structures and functions.
0x222100 (Disabled)
When received, Poortry attempts to disable or enable kernel callbacks via modification of the PspNotifyEnableMask flag. This is a common trick used by rootkits to enable or disable kernel routine callbacks, as explained by this article.
0x222104 (Disabled)
When it receives this IOCTL code, Poortry modifies the kernel callbacks of the PsProcess, PsThread and ExDesktopObj object types. These are kernel-mode data structures that represent specific objects in the Windows kernel. Self-explanatory, the PsProcess object type represents a process object. These object types also contain a variable pointing to the callbacks registered for the corresponding object.
Because this feature was disabled, we are unsure how adversaries might aim to modify these callback lists. One possible scenarios might be to either disable them entirely by setting the callbacks to a custom function without any functionality, simply returning instantly,
0x222108 (Disabled)
When received, Poortry modifies the CmpCallbackCount variable to either enable or disable registry kernel callbacks. The variable is used to count the number of registered callbacks. We suspect that if this value is patched to zero, the callbacks will be rendered useless.
0x22210C (Disabled)
When received, Poortry attempts to remove the fltMgr.sys driver from the \\FileSystem\\FastFat and \\FileSystem\\Ntfs device by use of the DeviceIoDetachDevice function. The function is usually used by valid drivers to clean up during shutdown. However, rootkits can use the function to prevent targeted drivers from receiving any further I/O requests.
fltMgr.sys is the filter manager on Windows. This driver is used to extend or modify the functionality of existing functionalities on the Windows system. The driver is also often used by EDR products.
We suspect by detaching it via use of IoDetachDevice installed filters are rendered useless on the targeted system.
0x2221C0 (Disabled)
When received, Poortry enters routines to fetch the address of major functions handlers of ClassPnp.sys and ntfs.sys, such as NtfsFsdClose or NtfsFsdRead of ntfs.sys. Thus, we suspect that this routine can be used as an additional initialization routine to fetch critical function addresses that are used by other features.
0x222400 (Enabled)
When received, Poortry disables installed kernel callbacks through a series of different techniques. The user-mode component includes the name of the targeted driver when the I/O request packet is sent.
Kernel callbacks installed via PsSetLoadImageNotifyRoutine, PsSetCreateThreadNotifyRoutine and PsSetCreateProcessNotifyRoutine are patched. At the prologue of the callback function, Poortry modifies the first instruction to instantly return zero when entered.
So far, we identified the following techniques to render kernel callbacks and security drivers useless:
- Internal structures used by the corresponding functions PsSetLoadImageNotifyRoutine, PsSetCreateThreadNotifyRoutine and PsSetCreateProcessNotifyRoutine are iterated. If the callback belongs to a tagged security driver, As a consequence, the registered callback function are exiting immediately without executing any of its intended operations.
- The Windows kernel implements important data structures such as PsProcess, PsThread and ExDesktopObject that represent fundamental elements of the Windows operating system. These structure contain a variable named CallbackList that manages all callback routines associated with the specific object. Poortry iterates this list and if the callback belongs to a tagged security driver, As a consequence, the registered callback function are exiting immediately without executing any of its intended operations.
- An internal linked listed used by CmRegisterCallback and CmUnregisterCallback is iterated. This linked list contains function points to registered registry and object callbacks. If the callback belongs to a tagged security driver, the prologue of the function is patched.
- Poortry uses the exported function FltEnumerateFilters from fltMgr.sys to iterate through applied filters. If the filter belongs to a tagged security driver, the prologue of the function is patched.
- While we were not able to directly trigger the functionality, we have found evidence that Poortry can abuse the IoDetachDevice function to detach a device object from a system’s device stack. In contrary to the functionality provided by IOCTL code 0x22210C, it is less evasive and detaches devices only if the device name matches the input name send via DeviceIoControl.
Cleanup Phase
After impairment, the EDR killer aims at terminating security-related processes and rendering the EDR agent useless by wiping critical files off disk.
First, the user-mode component sends multiple I/O requests with IOCTL code 0x222144 to the kernel-mode component, including the process id of the process to kill.
The loader contains a list of hardcoded paths pointing at the location where EDR products are installed. It iterates all sub-folders and files in the folder and deletes files critical to the EDR agent, such as EXE files or DLL files by sending an IOCTL request with code 0x222180 to the driver. The sent request includes the path of the file to delete.
Notably, the user-mode component can operate in two modes:
- Deleting files by type
- Deleting files by name
We suspect that the author added these operation modes to ensure flexibility when aiming for different targets. We also believe that the list of hardcoded paths pointing at installation folders of EDR products change depending on the target.
Conclusion
Poortry, and its associated loader Stonestop, have undergone a serious feature enhancement in the 20 months since Sophos and Microsoft released a joint report on the EDR killer’s abuse of the WHQL signing mechanism. What was once a relatively simple tool for unhooking “troublesome” endpoint protection components has become, in and of itself, a Swiss Army Knife of malicious capabilities abusing a virtually limitless supply of stolen or improperly used code signing certificates in order to bypass Driver Signature Verification protections.
Poortry’s developers made it a differentiating characteristic of their tool that it could do more than just unhook an EDR or endpoint protection anti-tamper driver. Poortry has evolved into something akin to a rootkit that also has with finite controls over a number of different API calls used to control low-level operating system functionality. It also now has the capacity to wipe its enemies – security software – right off the disk as a way to clear the path for a ransomware deployment.
Curt Wilson
Nice work. I’m noticing initial detection of these components is getting better over time yet I’m also seeing some sneaky TTPs at play that complicate analysis and detection.