本帖最后由 00006666 于 2022-2-12 23:29 编辑
此文章转载自ESET研究报告 This article from the ESET research report 译文位于原文的下方,如有差错,请采纳原文中的相关内容 译文为本人翻译,请勿转载
ESET researchers look at malware that abuses vulnerabilities in kernel drivers and outline mitigation techniques against this type of exploitation.
There are various types of kernel drivers; the first that come to mind are device drivers that provide a software interface to hardware devices like plug and play interfaces or filter drivers. These low-level system components have a strict development process including scrutiny regarding security. However, there are additional “software” drivers that are designed to run in Ring 0 and provide specific, non-hardware related features like software debugging and diagnostics, system analysis, etc. As you can see below, these are prone to extend the attack surface significantly. While directly loading a malicious, unsigned driver is no longer possible in the newer versions of Windows (unless driver signature enforcement is explicitly disabled during boot) and kernel rootkits are considered to be a thing of the past, there are still ways to load malicious code into the kernel. While actual vulnerabilities and exploits that achieve that get a lot of attention, there is a much easier way: abusing legitimate, signed drivers. There are many drivers from various hardware and software vendors lying around that offer functionality to fully access the kernel with minimal effort. Vulnerabilities in signed drivers are mostly utilized by game cheat developers to circumvent anti-cheat mechanisms, but they have also been observed being used by several APT groups and in commodity malware alike. This paper discusses the types of vulnerabilities that commonly occur in kernel drivers, provides several case studies of malware utilizing such vulnerable drivers, analyzes examples of vulnerable drivers that we discovered during our research, and outlines effective mitigation techniques against this type of exploitation. While this problem is not new and relevant research about the topic has been presented in the past, mainly during 2018 and 2019 ([1], [2], [3]), it is still a problem as of this writing.
Common types of driver vulnerabilitiesWhile every vulnerability is different, similar types of vulnerabilities seem to be recurrent in unrelated kernel drivers. This may be partially caused by (ancient) driver code samples that were created back when access to kernel mode was not restricted to signed drivers and developers did not take security into consideration (malware could simply load unsigned rootkit drivers instead). The following sections describe the vulnerabilities most frequently observed in drivers from a large variety of, and even high-profile, hardware and software vendors.
MSR read/writeModel-specific registers (MSRs) were introduced in Pentium 80586 CPUs in 1993. MSRs can be thought of as “global variables” of a CPU (or of a specific core). Some contain various information about the processor or specific CPU core – such as temperature, power, …. Additionally, there are also many MSRs that contain data critical for the working of a system, such as IA32_LSTAR (0xC0000082) for SYSCALL or IA32_SYSENTER_EIP (0x00000176) for SYSENTER, both of which contain pointers to an address in the kernel where the CPU jumps when a SYSCALL or SYSENTER instruction is executed. On newer Windows x64 platforms such as Windows 10 or 11, SYSCALL is used for both AMD and Intel CPUs where IA32_LSTAR should point to the KiSystemCall64 function found in ntoskrnl.exe. The mechanism of the transition to Windows kernel when executing SYSCALL is displayed in Figure 1.
Figure 1. How SYSCALL is handled in x64 Windows
MSRs are indexed by a number and accessed by the privileged RDMSR and WRMSR instructions, which can only be executed in kernel mode. Many commercial drivers implement functionality for user-mode applications to access these instructions through an IOCTL mechanism. This is usually intended to be able to read or write a few specific innocent MSRs (like CPU voltage, temperature, …), but developers sometimes do not add any additional checks to restrict access to critical MSRs, such as the example seen in Figure 2. This gives potential attackers an opportunity to, for example, patch the SYSCALL/SYSENTER entry point MSRs, which are pointers to a function that handles any system call from user mode.
Figure 2. Vulnerable MSR IOCTL handler in the AMDPowerProfiler.sys driver
Overwriting the system call pointer was trivial and very powerful on older CPUs and systems before mitigations like Supervisor Mode Execution Prevention (SMEP) were introduced. On such systems, simply changing the pointer to the address of an arbitrary user-mode executable buffer containing malicious code, and then immediately executing a system call instruction on a same CPU core, was enough to gain kernel-level code execution. This is no longer the case with newer systems due to modern exploitation mitigations. That being said, with clever use of various techniques, it is still possible to bypass most of these mitigations and achieve kernel-level code execution on Windows 10 or even brand-new Windows 11 systems (as of December 2021). All the mitigations in the following sections are in place on most modern machines and need to be bypassed to achieve successful kernel-mode exploitation.
SMEPSMEP is a protection mechanism introduced in 2011 in Intel processors based on the Ivy Bridge architecture and enabled by default since Windows 8.0. It prevents execution of code in user-mode pages from Ring 0, and is implemented by assigning a user-mode or kernel-mode value to a flag bit on every virtual memory page in the page table. If a system attempts to execute code in a user-mode page from kernel space, a 0x000000FC error (ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY) will be triggered and cause a BSOD. SMEP can be dynamically toggled on and off during execution with its status saved in the CR4 register for each CPU core individually (see Figure 3).
Figure 3. CR4 register flags of a CPU
SMEP mitigates the naïve exploitation technique of abusing an MSR R/W IOCTL in order to change the LSTAR MSR to point directly to malicious user-mode code. That being said, since the attacker is in control of the stack that is passed to kernel mode on system calls, they may utilize a technique called a ROP chain to manipulate the stack. By placing a chain of return addresses on the stack, the attacker can arrange to execute a carefully picked set of instructions in kernel mode by changing the LSTAR MSR via a vulnerable IOCTL. With the stack suitably prepared, executing the system call instruction results in the first “gadget” in the ROP chain executing and when complete its code will “return” to the next gadget in the chain, which was supplied on the stack with the rest of the chain. The functionality of such a ROP chain is limited by the availability of suitable code chunks, called gadgets, available in the kernel’s modules. Since an attacker can read kernel modules from the file system and knows at which addresses the modules are loaded, the gadgets can be easily looked up and if those gadgets exist, a working ROP chain can then be constructed. To properly initialize the transition to kernel, the ROP chain needs to swap the GS register using the SWAPGS instruction. On 64-bit Windows, the GS register holds the address of the Thread Environment Block (TEB) in user mode, and the address of the Kernel Processor Control Region (KPCR) in kernel mode. Therefore, it is crucial that those two addresses change before any operations happen in the kernel. It is no surprise that the SWAPGS instruction is also the first instruction in the Windows kernel KiSystemCall64 function. The next step is restoring the original value of the LSTAR MSR using the WRMSR instruction, in order to avoid executing the ROP chain on the next execution of the SYSCALL instruction. At this point, the malicious code properly executes in the kernel and the attacker can execute whatever payload is desired. This can be additional ROP gadgets to, for example, disable SMEP or SMAP protections by overwriting CR4, or even be direct calls to an exported ntoskrnl API function. The attacker can overwrite CR4 utilizing a MOV CR4 gadget to disable SMEP and also SMAP, which is covered in the next section. They then can proceed to execute a user-mode payload directly. The only difficulty with this approach is precalculating a valid CR4 value. Although most of the CR4 values can be guessed from user mode by running the CPUID instruction, there may be some inconsistencies between different versions of Windows. To transition back to user mode safely, once the attacker’s ROP chain has run they need to execute the SWAPGS instruction again and then execute the SYSRET instruction. Older exploits bypassing SMEP are described in [4], (2015).
SMAPSupervisor Mode Access Prevention (SMAP) is a newer mitigation that has been introduced to complement SMEP and further restrict access from the kernel to user-mode pages – it disallows both reads and writes. Just as SMEP, its status is stored as a bit in the CR4 register (see Figure 3). SMAP should render the previously described ROP chain technique useless, since the stack containing the ROP chain is in fact a user-mode page. A system with SMAP active will bluescreen the moment it tries to access the stack after transitioning to the kernel via the system call. SMAP can also be temporarily disabled by setting the AC flag in the EFLAGS CPU register. This feature is also the downfall of this mitigation in regard to MSR exploitation – it turns out the AC flag can be set from user mode, right before transitioning to kernel mode, by utilizing the POPF and PUSHF instructions. This is caused by the SFMASK MSR that controls which EFLAGS register bits are cleared when the SYSCALL instruction is executed. Even on the newest Windows 11 machines, the mask does not have the AC flag bit set, which means it is not cleared upon transitioning to the kernel so SMAP can be disabled by the user. As the SFMASK is controlled by another MSR (0xC0000084), even if Microsoft changed SFMASK to implicitly clear the AC flag, theoretically the attacker could patch this MSR prior to the exploitation anyway. It is worth noting that SMAP has only recently been enabled by default in Windows 10 x64 with newer hardware.
KVA shadowingKVA shadowing was introduced as a software mitigation for the Meltdown CPU vulnerability discovered at the end of 2017. The basic idea of this mitigation is that the virtual address space is split into two – user mode and kernel mode. The user-mode address space has access only to very restricted parts of the ntoskrnl module, specifically a single code section called .KVASCODE that is responsible for low-level operations like entering and leaving the kernel when handling a system call. This is handled by implementing “Shadow” equivalents of the responsible functions, like KiSystemCall64Shadow that works as the original KiSystemCall64, but contains differences responsible for handling KVA shadowing and switching the address space context properly (see Figure 4). The rest of the kernel is completely separated and mapped to its own address space and cannot be accessed even directly by the CPU from user-mode address space until the context is appropriately switched.
Figure 4. Comparison of KiSystemCall64 and KiSystemCall64Shadow versions of the system call handler – minor differences can be spotted at the beginning of the function
While KVA shadowing was designed as a fix for the Meltdown vulnerability, it also potentially causes trouble for other kinds of vulnerabilities, including the MSR one. There are generally two approaches to disable the mitigation – one is to disable it as a setting in the registry. This requires admin access and a reboot afterwards for the changes to take effect. Alternatively, when building a ROP chain for MSR exploitation, an attacker tries to find gadgets exclusively in the .KVASCODE section of the ntoskrnl module – since that section handles the system call transition, it is possible to build a working ROP chain. Similar mitigation was also introduced in Linux systems, where it is called Kernel Page Table Isolation (KPTI).
Physical memory read/writeBeing able to directly read and write physical memory seems to be a common feature in many low-level kernel drivers. This is achieved by mapping a specific range of physical memory to a virtual memory buffer that can be read or written and even passed to a user-mode application. There are several ways to achieve this, the most common one being an ability to map the \Device\PhysicalMemory section to virtual memory, as shown in Figure 5.
Figure 5. Physical memory map vulnerability in Passmark DirectIO64.sys driver
A potential drawback for the attackers is that they first need to translate the virtual address to a physical one. Drivers that implement physical memory I/O sometimes also offer an IOCTL for physical to virtual address translation, but even if the driver does not have any such address conversion, there are still many ways to utilize this feature. The most straightforward use case is simply to walk through all the physical memory looking for specific artifacts that represent critical data structures that the attacker wants to find. For example, the attacker might try to look for the EPROCESS structure of the malicious process and elevate it to SYSTEM privileges by stealing a token from a more privileged process or modifying its rights. Some of these strategies are demonstrated here and here. Since physical memory mappings disregard any virtual memory protection features, it is also possible to write to executable memory pages. This gives the attacker an opportunity to look up specific kernel modules and chunks of code, carefully modify them and, if patched code can be executed via a system API or an IOCTL of a driver, to achieve malicious kernel-level code execution.
Virtual memory read/writeVirtual memory access IOCTLs are not as commonly found in these drivers as physical memory ones, but they have very similar repercussions. Utilizing these is even easier, as there is no address translation needed and all the virtual kernel addresses found from user mode can be accessed directly. A potential downside is that the access is limited by the memory protection of the target address, so it is not possible to write read-only memory pages without changing the protection first. Therefore, this vulnerability is commonly used to manipulate various kernel data structures to achieve things like elevating a malicious process to SYSTEM rights by stealing tokens from such kernel structures. The most common way this vulnerability arises is via an IOCTL with a simple pointer dereference in kernel mode, so it can be hard to detect this vulnerability using heuristic methods.
Case studiesWhen malware actors need to run malicious code in the Windows kernel on x64 systems with driver signature enforcement (DSE) in place, carrying a vulnerable signed kernel driver seems to be a viable option for doing so. This technique is known as Bring Your Own Vulnerable Driver (BYOVD) and has been observed being used in the wild by both high-profile APT actors and in commodity malware. In the following sections we present some examples.
Slingshot APTSlingshot is a cyberespionage platform that was uncovered by Kaspersky in 2018 [5] and is believed to have been active since at least 2012. The actors behind this malware decided to implement their main module, called Cahnadr, as a kernel-mode driver. On older x86 systems, the driver would be loaded directly by the user-mode module. On newer systems with active DSE, they decided to implement a custom driver loader that leverages the following signed kernel drivers with MSR vulnerabilities: Goad, SpeedFan (CVE-2007-5633), Sandra (CVE-2010-1592), and ElbyCDIO (CVE-2009-0824). The exploitation targeted pre-Windows 8 systems, so the exploitation was a simple modification of the LSTAR MSR to point to a malicious payload in a user-mode buffer. Note that the Kaspersky researchers estimated these threat actors to have been active from 2012 to 2018, which means that these exploits were quite old and well known, but that was no reason for the attackers to stop using them as the certificates of those vulnerable drivers were never revoked.
InvisiMoleIn 2018, fellow ESET researchers uncovered a sophisticated APT actor that they named InvisiMole [6]. The group has been tracked by ESET ever since and in 2020 an extensive white paper about the group and its toolset was published. In that white paper, our colleagues reported that InvisiMole used the BYOVD technique, exploiting the MSR vulnerability in the speedfan.sys driver (CVE-2007-5633) to load a malicious unsigned driver. While this campaign was targeting older x86 systems and the exploitation using a malicious driver was trivial from the modern standpoint, due to the fact there were no mitigations like SMEP in place, it was still an interesting case showing that the group behind this malware is very technically capable. Later during that investigation, however, a newer variant of the InvisiMole malware using the BYOVD technique was discovered. This variant is the only case to date that we have observed of MSR exploitation on Windows 10 x64 systems being used in the wild by a malicious actor. It employs advanced techniques to bypass mitigations like SMEP and even SMAP. That being said, the exploitation is mitigated by KVA shadowing, which the authors failed to take care of. Coincidentally, MSR exploitation was used to deploy a malicious driver that attempted to disable our security products. Although the whole compromise chain is more extensive, we will focus on a specific part of the malware that leverages the BYOVD technique and MSR exploitation that happens in the main user-mode module.
User-mode moduleInvisiMole’s authors seem to have developed a sophisticated ROP chain exploitation framework that they use for MSR exploitation – although the sample contains many debug messages in the code, we were not able to identify and link them to any known projects. This leads us to believe the framework is an original work of these malware authors and that non-negligible resources have been spent on developing it. The framework is an extensive C++ codebase with various classes. It appears that InvisiMole’s authors did not know about the possibility of setting the AC flag with the PUSHF and POPF instructions as described in the SMAP section, and instead chose a very complex ROP gadget found in the MiDbgCopyMemory kernel function that starts with the privileged STAC instruction, which is dedicated to setting the AC flag (see Figure 6). On top of that, InvisiMole utilizes the IRETQ instruction after every gadget that explicitly sets the RFLAGS register with the AC flag set, which stabilizes the exploit even further.
Figure 6. ROP gadget used by InvisiMole to disable SMAP mitigation
The initial gadget jumps directly to the STAC instruction, which immediately disables SMAP by setting the AC flag. Since this gadget appears in the middle of the MiDbgCopyMemory function, the malware carefully prepares the stack and registers to safely leave the function. Once the MiDbgCopyMemory function returns, the ROP chain proceeds to the SWAPGS gadget [7] in order to properly switch to kernel mode, followed by the WRMSR gadget to set the LSTAR MSR back to its original value. At this point, InvisiMole will proceed with executing the payload, which may be an exported kernel function or the entry point of a loaded malicious driver.
Driver loaderThe driver loading technique is quite complex – InvisiMole will first install a “driver loader” – another kernel driver module that is used to load the malicious payload (yet another driver) passed as an argument. To initialize the driver loader, InvisiMole executes several separate MSR exploitations, where every instance carries a dedicated ROP chain with a single API call payload. The malware will start by executing ExAllocatePoolWithTag to allocate an executable kernel memory buffer for the loader, followed by preparing the image in user mode to reflect its future address in the kernel – sections are moved to their virtual offsets; imports are resolved, and relocations fixed. Once the image is ready, it is copied over from user mode to the allocated kernel buffer using memcpy from the ntoskrnl module. To transfer code execution to the loader once it is copied to the kernel, InvisiMole’s authors also leverage the MSR vulnerability and designed several dedicated PE exports in the loader (see Figure 7 for an example) that are intended to handle transitions from user-mode system calls. It works very similarly to the ROP chain gadgets – swap the GS register, swap the user-mode and kernel-mode stacks, save all registers on the stack, restore the original LSTAR MSR value and then call the actual function. Once finished, this process is reversed.
Figure 7. Exported function in the driver loader module that is called by changing LSTAR MSR
When the loader is properly initialized in the kernel, an export named _Start64 is executed by changing LSTAR MSR to the export address in the kernel. After handling the transition to the kernel, _Start64 registers a deferred routine that is responsible for loading the payload driver, and returns to user mode. The deferred loader routine will attempt to initialize the payload driver in a “proper” fashion – creating registry keys and kernel driver objects, performing all the necessary steps to register the driver in the system as if the operating system were loading the driver itself, and eventually calling IoCreateDriver. The proper initialization approach was chosen so the loaded payload driver can process I/O request packets and communicate with a user-mode module using IOCTLs.
Payload driverThe payload driver offers IOCTL functionality for disabling various notification callbacks (see Figure 8), mostly aimed at disarming third-party security solutions, and the possibility of protecting a file in the file system. The specific commands are passed from the user-mode module. Interestingly, the user-mode module will attempt to disable various parts of ESET protection in the kernel.
Figure 8. IOCTL handler in the InvisiMole payload driver
RobbinHoodSeeing a BYOVD technique in commodity malware that aims to reach as many people as possible is rare, but the RobbinHood ransomware family shows that it may still prove useful [8]. This ransomware leverages a vulnerable GIGABYTE motherboard driver GDRV.SYS (CVE-2018-19320; see Figure 9 and Figure 10) to disable DSE in order to install its own malicious driver.
Figure 9. GIODrv driver exploitation in RobbinHood sample
The way DSE is disabled depends on the Windows version – on Windows 7 and older, an nt!g_CiEnabled variable is modified directly in the ntoskrnl module. On newer Windows 8 through Windows 11 systems, the variable ci!g_CiOptions in the ci.dll module is modified instead. Finding this variable is slightly more complicated and it looks like the authors adopted a method found in an open-source project called DSEFix that is available on GitHub. Moreover, since Windows 8.1, the variables in ci.dll are protected by PathcGuard and tampering with the module will eventually cause the system to BSOD, even if the variable is changed back to an original value. The malicious driver is then used to kill a long list of processes and delete their files, mainly focusing on endpoint protection software and other utilities. Since the termination is done from kernel mode, most self-protection mechanisms employed by security software are circumvented and the technique is more likely to succeed than attempting to disarm the protections from user mode.
Figure 10. WriteVirtualMemory IOCTL handler in GIODrv
LoJaxIn 2018, ESET researchers discovered the first-ever UEFI rootkit used in the wild. In order to have access to victims’ UEFI modules, the malware utilizes a powerful utility called RWEverything. The RWEverything driver was recently disabled by Microsoft directly in Windows 10 and 11 using the HVCI memory integrity feature described in the Virtualization-based security section.
Discovered vulnerabilitiesDuring our research we decided not only to catalog existing vulnerabilities, but also to look for new ones. We set up YARA rules to hunt for kernel drivers with specific functionality and indicators of being potentially vulnerable. We also created a proof-of-concept exploitation framework for testing the newly found drivers and confirming that they are exploitable. We went through hundreds of different kernel drivers that matched our criteria and aside from finding the already discovered drivers, we also found three drivers previously not known to be vulnerable, some containing several unrelated bugs. The fact that even after several independent research groups tackled this area we were still able to find new vulnerabilities, even from reputable vendors, shows that Windows driver security is still an issue. While we were looking for all kinds of vulnerabilities described in previous sections, finding ones with MSR access turned out to be the easiest, appearing most commonly due to the use of special privileged instructions (RDMSR/WRMSR) that give away this functionality. Interestingly enough, in many cases it would turn out that this class of drivers also contained other kinds of vulnerabilities like arbitrary physical or virtual memory read and write functions.
AMD μProf (CVE-2021-26334)We have identified an MSR vulnerability in the AMDPowerProfiler.sys kernel driver, which is a part of AMD μProf profiling software. What makes this driver stand out is that once the underlying software package is installed, the driver runs on every system boot. The unfiltered MSR IOCTL access combined with the lack of FILE_DEVICE_SECURE_OPEN flags (see Figure 11) and on-boot presence gives the attacker a good opportunity to exploit the driver even as an unprivileged user – this is an advantage compared to the BYOVD approach when the attacker needs to load the driver themselves.
Figure 11. AMD uProf kernel driver device creation without the FILE_DEVICE_SECURE_OPEN flag allowing non-admin access
On the other hand, the software is a niche utility for developers and not a package distributed to a large number of systems. We have not identified any other vulnerability in the driver. The vulnerable IOCTL is IOCTL_ACCESS_MSR (0x222030). AMD acknowledged the vulnerability (CVE-2021-26334) and released a fix in the November 2021 Patch Tuesday release.
Passmark softwarePassmark is a company offering various computer benchmark and diagnostic tools. To achieve such functionality in user mode, a lot of low-level system features need to be accessed by leveraging a kernel-mode driver. Passmark’s DirectIo32.sys and DirectIo64.sys kernel drivers are a common framework shared and distributed among several of the vendor’s applications – namely BurnInTest, PerformanceTest and OSForensics. The driver contains direct, unfiltered MSR R/W access (CVE-2020-15480), an ability to map physical memory (CVE-2020-15481) for both reading and writing, and the IOCTL handler also contains a buffer overflow (CVE-2020-15479) due to blindly copying, without any size check, an IOCTL input buffer of arbitrary size to a local variable on the stack. Passmark acknowledged these vulnerabilities and released a fixed version soon thereafter.
CVE-2020-15479When the driver receives an IOCTL request from a user-mode program, it will first copy the requested input buffer into a local buffer on the stack. The size of the memmove is based only on the size of the input buffer (see Figure 12) and does not consider the capacity of the stack buffer. This may lead to a buffer overflow, if a large enough IOCTL buffer is provided. There are multiple unchecked memmove calls in the IOCTL handler function and several IOCTLs can be used to leverage the buffer overflow.
Figure 12. Buffer overflows in the vulnerable Passmark drivers
CVE-2020-15480This driver offers RDMSR and WRMSR functionality exposed via an IOCTL that allows an unprivileged user-mode program to read and write arbitrary CPU MSRs without any additional checks. The vulnerable IOCTLs are IOCTL_READ_MSR (0x80112060) and IOCTL_WRITE_MSR (0x80112088).
CVE-2020-15481Physical memory mapping functionality is exposed via a single control code – IOCTL_MAP_PHYSICAL_MEMORY (0x80112044). The implementation is split into two parts: the primary version is done through the ZwMapViewOfSection API; if for some reason this method fails, the function also implements a secondary approach as a backup, through the MmMapIoSpace and MmMapLockedPages kernel APIs. Both are illustrated in Figure 13.
Figure 13. Physical memory IOCTL implementation in Passmark’s drivers
Devid Espenschied PC AnalyserPC Analyser is another utility for inspecting various details about the machine. The PCADRVX64.sys kernel driver distributed with the application contains two separate vulnerabilities – unfiltered MSR access (CVE-2020-28921) and ability to read from and write to arbitrary physical memory addresses (CVE-2020-28922). When creating the driver device, the FILE_DEVICE_SECURE_OPEN flag is unspecified, allowing unprivileged users to retrieve a handle to the driver. Devid Espenschied acknowledged the vulnerabilities and released an updated version.
CVE-2020-28921As with previous drivers, MSR access is unrestricted (see Figure 14) and the IOCTL code handler contains FILE_ANY_ACCESS flags allowing even an unprivileged user to leverage the functionality.
Figure 14. MSR IOCTL implementation in PC Analyser driver
CVE-2020-28922The driver’s physical memory read and write functionality is implemented with separate IOCTLs based on the size of the read or write request. It offers the following control codes, none of which make any checks on the memory addresses targeted by the request: IOCTL_READ_PHYSICAL_MEMORY_BYTE (0x82002400)
IOCTL_READ_PHYSICAL_MEMORY_WORD (0x82002500)
IOCTL_READ_PHYSICAL_MEMORY_DWORD (0x82002600)
IOCTL_WRITE_PHYSICAL_MEMORY_BYTE (0x82002700)
IOCTL_WRITE_PHYSICAL_MEMORY_WORD (0x82002800)
IOCTL_WRITE_PHYSICAL_MEMORY_DWORD (0x82002900)
MitigationsWhile we have already mentioned several mechanisms employed by the CPU and/or the operating system, most of them can be bypassed with some clever techniques and are not very effective if the attacker prepares for them ahead of time. In this section we would like to mention some mitigation ideas that are actually effective at completely stopping the abuse of vulnerable drivers.
Virtualization-based securityVirtualization-based security or VBS is a feature introduced in Windows 10 that leverages hardware virtualization and makes the kernel sandboxed by a hypervisor in order to secure the operating system with various protections. VBS offers several protection features with the most prominent one being Hypervisor-Protected Code Integrity (HVCI), which also comes as a standalone feature. HVCI enforces code integrity in the kernel and allows only signed code to be executed. It also employs blocklisting functionality, where a known piece of code signed by a specific, valid signature can be blocklisted and not allowed to be run or to be loaded. One of the drivers that has been blocklisted already via this method is the RWEverything utility. HVCI effectively prevents vulnerable drivers from being abused to execute unsigned kernel code or load malicious drivers (regardless of the exploitation method used) and it seems that malware abusing vulnerable drivers to load malicious code was one of the main motivations behind Microsoft implementing this feature: VBS provides significant security gains against practical attacks including several we saw last year, including human-operated ransomware attacks like RobbinHood and sophisticated malware attacks like Trickbot, which employ kernel drivers and techniques that can be mitigated by HVCI. Our research shows that there were 60% fewer active malware reports from machines reporting detections to Microsoft 365 Defender with HVCI enabled compared to systems without HVCI. The Surface Book 3 shipped in May 2020 and the Surface Laptop Go shipped in October 2020, and users may not have noticed they are running VBS and are therefore better protected based on the work done under the hood. [emphasis added] Aside from enforcing kernel code integrity, VBS also secures important MSRs and disallows any changes to them. Unsurprisingly, this protection also affects the LSTAR MSR and mitigates all of the exploitation possibilities described above. While VBS is an effective protection against MSR exploitation and running malicious code in the kernel in general, the adoption of this new feature is quite limited, as it has several hardware requirements that only newer machines can fulfill. There are also some drawbacks with the most notable being a performance hit, which may be quite noticeable depending on the workload. While some benchmarks estimate the performance hit being as high as 25% in specific video games, the more detailed benchmarking by Tom’s Hardware estimates the performance hit being around 5% depending on the specific benchmarks and hardware configuration (see Figure 15), which is still not a negligible amount and may lead some users to consider turning this feature off. There might also be some compatibility issues with legacy drivers and software. With the release of Windows 11, Microsoft has decided to enable HVCI by default for all compatible devices.
Figure 15. VBS benchmark results by Tom’s Hardware
Third-party hypervisorSimilar to Microsoft’s VBS, with new enough hardware, a third-party security solution may deploy its own custom hypervisor. Running the operating system under a hypervisor gives a detailed oversight of the state of the machine and provides the possibility of inspecting and intercepting any event including execution of a specific instruction. As with VBS, this comes at a cost, namely performance and compatibility.
Certificate revocationOn modern Windows systems, drivers need to have a valid signature based on an “acceptable” certificate. Hence, revoking the certificate of a vulnerable driver would be an easy way to “disarm” it and render it useless in most cases. Sadly, revocation rarely ever happens and of the vulnerable drivers documented in our research above, not a single one of them has had its signature revoked. There are probably a multitude of reasons why such revocations are not happening, but the primary ones are likely to be time and cost. As nobody requires the revocation, it does not make much sense from the vendor’s standpoint to ask for revocation, as this will be a costly and time-consuming process. Moreover, a signing certificate is usually shared among other projects, so the potential revocation because of a single driver could hinder the development of every project. Further, during our research we learned that drivers with revoked certificates are not always blocked and that this problem is more complicated than it seemed at first. Revocation may not be the easiest solution after all.
Driver blocklistingDriver blocklisting is a practice adopted by both Microsoft and various third-party security product vendors. Several of the most notorious vulnerable drivers are detected by ESET security products and deleted when found on a system. Microsoft also opted to blocklist drivers not only with its security solution, but also directly by the operating system utilizing their HVCI mitigation, which is part of virtualization-based security. While blocklisting is effective, it is not a proactive solution – only previously discovered vulnerable drivers can be blocklisted, and it must be done manually by each vendor. This means that this mitigation will not be effective against previously unknown, zero-day driver vulnerabilities that may be used in a sophisticated APT attack. Probably the most prominent blocklisted driver is the Capcom “anti-cheat” driver Capcom.sys, which explicitly implements an IOCTL that simply executes the contents of the provided buffer in kernel mode (see Figure 16). To be able to execute a buffer provided from user mode, it even temporarily disables SMEP! When discovered, the driver made several headlines and many unsigned driver loader tools were created based on abusing this function of the driver. Consequently, the driver was eventually blocklisted by many security product vendors including Microsoft and ESET.
Figure 16. Code snippet from Capcom anti-cheat driver
ConclusionVulnerable drivers have been a known problem for a long time and have been abused by the game-cheating community and malware authors alike, and while some effort has been made to mitigate the effects, it is still an ongoing battle. It seems that all the responsible parties involved want to solve this problem – the vendors we contacted were incredibly proactive during the disclosure process, eager to fix the vulnerabilities we uncovered. Microsoft is trying to strengthen the operating system from the inside and last but not least, third-party security vendors are trying to come up with clever ways to detect and mitigate such drivers themselves. However, it seems that there is still a piece missing – a common, unified way of handling these issues including more thorough “disarming” of the drivers, whether by revoking or blocklisting their certificates, or some public, shared blocklists adopted by the security companies.
以下内容为译文,如有差错,请采纳原文中的相关内容
ESET 研究人员研究了滥用内核驱动程序漏洞的恶意软件,并概述了针对此类利用的缓解技术。
有各种类型的内核驱动程序;首先想到的是为硬件设备提供软件接口的设备驱动程序,例如plug and play 接口或filter drivers. 。这些低级系统组件具有严格的开发过程,包括对安全性的审查。但是,还有一些额外的“软件”驱动程序被设计为在 Ring 0 中运行,并提供特定的、非硬件相关的功能,如软件调试和诊断、系统分析等。如下所示,这些程序很容易扩展攻击面。 虽然在较新版本的 Windows 中不再可能直接加载恶意的、未签名的驱动程序(除非禁用驱动程序签名强制验证),内核 rootkit 被认为已成为过去,但仍有加载恶意代码的方法进入内核。虽然实现这一目标的实际漏洞和利用得到了很多关注,但还有一种更简单的方法:滥用合法的签名驱动程序。有许多来自各种硬件和软件供应商的驱动程序提供了以最小的努力完全访问内核的功能。 签名驱动程序中的漏洞主要被游戏作弊开发人员用来规避反作弊机制,但也观察到它们被多个 APT 组织和商业恶意软件等使用。 本文讨论了内核驱动程序中常见的漏洞类型,提供了几个利用此类易受攻击驱动程序的恶意软件案例研究,分析了我们在研究期间发现的易受攻击驱动程序的示例,并概述了针对此类利用的有效缓解技术。虽然这个问题并不是新问题,而且过去已经提出了有关该主题的相关研究,主要是在 2018 年和 2019 年,但在撰写本文时它仍然是一个问题。
常见的驱动程序漏洞类型 虽然每个漏洞都不同,但类似类型的漏洞似乎在不相关的内核驱动程序中反复出现。这可能部分是由 (ancient) driver code samples 造成的,当访问内核模式不限于签名驱动程序并且开发人员没有考虑安全性时(恶意软件可以简单地加载未签名的 rootkit 驱动程序)。以下部分描述了来自各种甚至知名硬件和软件供应商的驱动程序中最常见的漏洞。
MSR 读/写 Model-specific registers (MSRs) 于 1993 年在 Pentium 80586 CPU 中引入。MSR 可以被认为是 CPU(或特定内核)的“全局变量”。有些包含有关处理器或特定 CPU 内核的各种信息——例如温度、功率……。此外,还有许多 MSR 包含对系统工作至关重要的数据,例如 SYSCALL 的 IA32_LSTAR (0xC0000082) 或 SYSENTER 的 IA32_SYSENTER_EIP (0x00000176),它们都包含指向内核中的地址的指针,CPU 在执行 SYSCALL 或 SYSENTER 指令。在较新的 Windows x64 平台(例如 Windows 10 或 11)上,SYSCALL 用于 AMD 和 Intel CPU,其中 IA32_LSTAR 应指向 ntoskrnl.exe 中的 KiSystemCall64 函数。执行 SYSCALL 时转换到 Windows 内核的机制如图 1 所示。
图 1. x64 Windows 中如何处理 SYSCALL
MSR 由数字索引并由特权RDMSR和WRMSR指令访问,这些指令只能在内核模式下执行。许多商业驱动程序实现了用户模式应用程序通过 IOCTL 机制访问这些指令的功能。这通常旨在能够读取或写入一些特定的无害 MSR(如 CPU 电压、温度等),但开发人员有时不会添加任何额外的检查来限制对关键 MSR 的访问,例如图 2 中的示例. 这为潜在的攻击者提供了机会,例如,修补 SYSCALL/SYSENTER 入口点 MSR,这些 MSR 是指向处理来自用户模式的任何系统调用的函数的指针。
图 2. AMDPowerProfiler.sys 驱动程序中易受攻击的 MSR IOCTL 处理程序
在引入管理模式执行保护 (SMEP) 等缓解措施之前,在较旧的 CPU 和系统上覆盖系统调用指针是微不足道的并且非常强大。在这样的系统上,只需将指针更改为包含恶意代码的任意用户模式可执行缓冲区的地址,然后立即在同一 CPU 内核上执行系统调用指令,就足以获得内核级代码执行。由于现代利用缓解措施的存在,较新的系统不再是这种情况。话虽如此,通过巧妙地使用各种技术,仍然可以绕过大部分漏洞缓解措施,并在 Windows 10 甚至全新的 Windows 11 系统(截至 2021 年 12 月)上实现内核级代码执行。 以下部分中的所有漏洞缓解措施都适用于大多数现代计算机,恶意软件需要绕过这些缓解措施才得以实施成功的内核利用。
SMEP SMEP 是 2011 年在基于 Ivy Bridge 架构的英特尔处理器中引入的一种保护机制,自 Windows 8.0 起默认启用。它阻止从 Ring 0 执行用户模式页面中的代码,并通过将用户模式或内核模式值分配给页表中每个虚拟内存页面上的标志位来实现。如果系统尝试从内核空间执行用户模式页面中的代码,则会触发 0x000000FC 错误 (ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY) 并导致蓝屏。SMEP 可以在执行期间动态地打开和关闭,其状态分别保存在每个 CPU 内核的 CR4 寄存器中(参见图 3)。
图 3. CPU 的 CR4 寄存器标志
SMEP 减轻了滥用 MSR R/W IOCTL 的低级利用技术,以便将 LSTAR MSR 更改为直接指向恶意用户模式代码。话虽如此,由于攻击者控制着系统调用时传递给内核模式的堆栈,因此他们可能会利用一种称为ROP chain 的技术来操纵堆栈。通过在堆栈上放置一个返回地址链,攻击者可以安排在内核模式下执行一组精心挑选的指令,方法是通过易受攻击的 IOCTL 更改 LSTAR MSR。在适当准备堆栈的情况下,执行系统调用指令会导致 ROP 链中的第一个“小工具”执行,完成后其代码将“返回”到链中的下一个小工具,该小工具与其余的堆栈一起提供连锁链条。 这种 ROP 链的功能受限于内核模块中可用的合适代码块(称为小工具)的可用性。由于攻击者可以从文件系统中读取内核模块并知道模块加载的地址,因此可以轻松查找小工具,如果这些小工具存在,则可以构建一个有效的 ROP 链。 为了正确初始化到内核的转换,ROP 链需要使用 SWAPGS 指令交换 GS 寄存器。在 64 位 Windows 上,GS 寄存器在用户模式下保存线程环境块 (TEB) 的地址,在内核模式下保存内核处理器控制区 (KPCR) 的地址。因此,在内核中发生任何操作之前改变这两个地址是至关重要的。毫无疑问,SWAPGS 指令也是 Windows 内核 KiSystemCall64 函数中的第一条指令。 下一步是使用 WRMSR 指令恢复 LSTAR MSR 的原始值,以避免在下一次执行 SYSCALL 指令时执行 ROP 链。 此时,恶意代码在内核中正确执行,攻击者可以执行所需的任何有效载荷。这可以是额外的 ROP 小工具,例如,通过覆盖 CR4 来禁用 SMEP 或 SMAP 保护,甚至可以直接调用导出的 ntoskrnl API 函数。 攻击者可以使用 MOV CR4 小工具覆盖 CR4,以禁用 SMEP 和 SMAP,这将在下一节中介绍。然后他们可以继续直接执行用户模式有效负载。这种方法的唯一困难是预先计算一个有效的 CR4 值。虽然大部分 CR4 值可以通过运行 CPUID 指令从用户态猜测出来,但不同版本的 Windows 之间可能存在一些不一致。 为了安全地转换回用户模式,一旦攻击者的 ROP 链运行,他们需要再次执行 SWAPGS 指令,然后执行 SYSRET 指令。 [4], (2015) 中描述了绕过 SMEP 的旧漏洞利用。
SMAP Supervisor Mode Access Prevention (SMAP)是一种较新的缓解措施,已被引入以补充 SMEP 并进一步限制从内核到用户模式页面的访问——它不允许读取和写入。与 SMEP 一样,它的状态作为一个位存储在 CR4 寄存器中(参见图 3)。 SMAP 应该使前面描述的 ROP 链技术变得无用,因为包含 ROP 链的堆栈实际上是一个用户模式页面。激活 SMAP 的系统在通过系统调用转换到内核后尝试访问堆栈时将出现蓝屏。 SMAP 也可以通过设置 EFLAGS CPU 寄存器中的 AC 标志来临时禁用。这个特性也是这种缓解在 MSR 漏洞利用方面的失败——事实证明,可以在转换到内核模式之前通过使用 POPF 和 PUSHF 指令从用户模式设置 AC 标志。这是由控制在执行 SYSCALL 指令时清除哪些 EFLAGS 寄存器位的 SFMASK MSR 引起的。即使在最新的 Windows 11 机器上,掩码也没有设置 AC 标志位,这意味着它在转换到内核时不会被清除,因此用户可以禁用 SMAP。 由于 SFMASK 由另一个 MSR (0xC0000084) 控制,即使 Microsoft 更改 SFMASK 以隐式清除 AC 标志,理论上攻击者仍可以在利用之前修补此 MSR。 值得注意的是,SMAP 直到最近才在 Windows 10 x64 中使用较新的硬件默认启用。
KVA shadowing 引入 KVA shadowing作为针对2017 年底发现的Meltdown 漏洞的软件缓解措施。 这种缓解的基本思想是将虚拟地址空间分为两部分——用户模式和内核模式。用户模式地址空间只能访问 ntoskrnl 模块中非常受限的部分,特别是称为 .KVASCODE 的单个代码段,它负责处理系统调用时进入和离开内核等低级操作。这是通过实现负责函数的“Shadow”等来处理的,例如作为原始 KiSystemCall64 工作的 KiSystemCall64Shadow,但包含负责处理 KVA shadowing和switching the address space context properly (see Figure 4)。内核的其余部分完全分离并映射到它自己的地址空间,甚至在适当切换上下文之前,即使 CPU 从用户模式地址空间直接访问也无法访问。
图 4. KiSystemCall64 和 KiSystemCall64Shadow 版本的系统调用处理程序的比较——可以在函数的开头发现细微的差异
虽然 KVA shadowing是为修复 Meltdown 漏洞而设计的,但它也可能对其他类型的漏洞(包括 MSR 漏洞)利用造成麻烦。 通常有两种方法可以禁用缓解 - 一种是将其作为注册表中的设置禁用。这需要管理员访问权限并在之后重新启动才能使更改生效。 或者,在构建用于 MSR 攻击的 ROP 链时,攻击者会尝试在 ntoskrnl 模块的 .KVASCODE 部分中查找小工具——因为该部分处理系统调用转换,所以可以构建一个有效的 ROP 链。 Linux 系统中也引入了类似的缓解措施,称为内核页表隔离 (KPTI)。
物理内存读/写 能够直接读写物理内存似乎是许多低级内核驱动程序中的一个共同特性。这是通过将特定范围的物理内存映射到可以读取或写入甚至传递给用户模式应用程序的虚拟内存缓冲区来实现的。有几种方法可以实现这一点,最常见的一种是将 \Device\PhysicalMemory 部分映射到虚拟内存的能力,如图 5 所示。
图 5. Passmark DirectIO64.sys 驱动程序中的物理内存映射漏洞
攻击者的一个潜在缺点是他们首先需要将虚拟地址转换为物理地址。实现物理内存 I/O 的驱动程序有时还提供 IOCTL 用于物理到虚拟地址的转换,但即使驱动程序没有任何此类地址转换,仍有许多方法可以利用此功能。 最直接的用例是简单地遍历所有物理内存,寻找代表攻击者想要找到的关键数据结构的特定工件。例如,攻击者可能会尝试寻找恶意进程的 EPROCESS 结构,并通过从特权更高的进程中窃取令牌或修改其权限来将其提升到 SYSTEM 权限。here和 here 展示了其中一些策略。 由于物理内存映射可以不考虑任何虚拟内存保护功能,因此也可以写入可执行内存页面。这使攻击者有机会查找特定的内核模块和代码块,仔细修改它们,如果修补的代码可以通过系统 API 或驱动程序的 IOCTL 执行,则可以实现恶意内核级代码执行。
虚拟内存读/写 虚拟内存访问 IOCTL 在这些驱动程序中不像物理内存驱动程序那样常见,但它们具有非常相似的影响。使用这些更容易,因为不需要地址转换,并且可以直接访问从用户模式找到的所有虚拟内核地址。一个潜在的缺点是访问受到目标地址的内存保护的限制,因此在不首先更改保护的情况下无法写入只读内存页面。 因此,此漏洞通常用于操纵各种内核数据结构,以通过从此类内核结构中窃取令牌来实现诸如将恶意进程提升为 SYSTEM 权限之类的事情。 此漏洞最常见的出现方式是通过 IOCTL 在内核模式下使用简单的指针取消引用,因此使用启发式方法很难检测到此漏洞。
实例探究 当恶意软件参与者需要在带有驱动程序签名强制验证 (DSE) 的 64位 Windows 系统中运行恶意驱动时,携带易受攻击的已签名内核驱动程序似乎是一个可行的选择。这种技术被称为自带漏洞驱动程序 (BYOVD),并且已被观察到被知名 APT组织和商业恶意软件广泛使用。
在以下部分中,我们将介绍一些示例。
Slingshot APT Slingshot 是卡巴斯基在 2018 年发现的一个网络间谍平台 [5],据信至少自 2012 年以来一直处于活跃状态。该恶意软件的幕后黑手决定将其名为 Cahnadr 的主要模块作为内核模式驱动程序实施。在较旧的 x86 系统上,驱动程序将由用户模式程序直接加载。在具有 DSE 的较新系统上,他们决定实施自定义驱动程序加载程序,该加载程序利用以下具有 MSR 漏洞的签名内核驱动程序:Goad、SpeedFan ( CVE-2007-5633 )、Sandra ( CVE-2010-1592 ) 和 ElbyCDIO ( CVE -2009-0824)。该漏洞针对的是 Windows 8 之前的系统,因此该漏洞是对 LSTAR MSR 的简单修改,以指向用户模式缓冲区中的恶意负载。 请注意,卡巴斯基研究人员估计这些威胁参与者从 2012 年到 2018 年一直活跃,这意味着这些漏洞利用非常古老且众所周知,但这并不是攻击者停止使用它们的理由,因为这些漏洞驱动程序的证书从未被撤销。
InvisiMole 2018 年,ESET 研究人员发现了一个复杂的 APT 攻击,他们将其命名为 InvisiMole [6]。从那时起,ESET 就一直在跟踪该小组,并于 2020 年发布了一份关于该小组及其工具集的广泛白皮书。在该白皮书中,我们的同事报告称,InvisiMole 使用 BYOVD 技术,利用 speedfan.sys 驱动程序 (CVE-2007-5633) 中的 MSR 漏洞加载恶意未签名驱动程序。尽管此活动针对的是较旧的 x86 系统,并且从现代角度来看,该攻击利用手段是微不足道的,但由于没有像 SMEP 这样的缓解措施,它仍然是一个有趣的案例,表明该恶意软件背后的组织非常有技术能力。 然而,在那次调查的后期,发现了使用 BYOVD 技术的 InvisiMole 恶意软件的新变种。此变体是迄今为止我们观察到的唯一一个恶意软件开发者者在 Windows 10 x64 系统上利用 MSR 的案例。它采用先进技术绕过 SMEP 甚至 SMAP 等缓解措施。话虽如此,KVA shadowing缓解了这种利用,但作者未能处理好。巧合的是,MSR 利用被用来部署恶意驱动程序,试图禁用我们的安全产品。尽管整个危害链更为广泛,但我们将关注恶意软件的特定部分,该部分利用 BYOVD 技术和发生在主用户模式模块中的 MSR 漏洞利用。
User-mode module InvisiMole 的作者似乎开发了一个复杂的 ROP 链开发框架,他们将其用于 MSR 开发——尽管该示例在代码中包含许多调试消息,但我们无法识别并将它们链接到任何已知项目。这使我们相信该框架是这些恶意软件作者的原创作品,并且已经花费了不可忽视的资源来开发它。该框架是一个包含各种类的扩展 C++ 代码库。 InvisiMole 的作者似乎不知道使用SMAP部分中描述的 PUSHF 和 POPF 指令设置 AC 标志的可能性,而是选择了在 MiDbgCopyMemory 内核函数中找到的一个非常复杂的 ROP 小工具,该小工具以特权 STAC 指令开头,专用于设置 AC 标志(参见图 6)。最重要的是,InvisiMole 在每个显式设置带有 AC 标志的 RFLAGS 寄存器的小工具之后使用 IRETQ 指令,这进一步稳定了漏洞利用。
图 6. InvisiMole 用于禁用 SMAP 缓解的 ROP 小工具
初始小工具直接跳转到 STAC 指令,该指令通过设置 AC 标志立即禁用 SMAP。由于这个小工具出现在 MiDbgCopyMemory 函数的中间,恶意软件会仔细准备堆栈和寄存器以安全地离开该函数。一旦 MiDbgCopyMemory 函数返回,ROP 链继续到 SWAPGS 小工具 [7] 以正确切换到内核模式,然后 WRMSR 小工具将 LSTAR MSR 设置回其原始值。此时,InvisiMole 将继续执行有效载荷,该有效载荷可能是导出的内核函数或加载的恶意驱动程序的入口点。
Driver loader 驱动程序加载技术相当复杂——InvisiMole 将首先安装一个“Driver loader”——另一个内核驱动程序模块,用于加载作为参数传递的恶意负载(又一个驱动程序)。为了初始化驱动程序加载器,InvisiMole 执行了几个单独的 MSR 漏洞利用,其中每个实例都带有一个专用的 ROP 链和一个 API 调用有效负载。恶意软件将首先执行 ExAllocatePoolWithTag 为加载程序分配一个可执行的内核内存缓冲区,然后在用户模式下准备映像以反映其在内核中的未来地址——部分被移动到它们的虚拟偏移量;解决了进口问题,并修复了重定位。映像准备好后,使用 ntoskrnl 模块中的 memcpy 将其从用户模式复制到分配的内核缓冲区。 为了在将代码复制到内核后将代码执行转移到加载器,InvisiMole 的作者还利用 MSR 漏洞并在加载器中设计了几个专用的 PE 导出(示例参见图 7),旨在处理来自用户模式系统的转换来电。它的工作方式与 ROP 链小工具非常相似——交换 GS 寄存器,交换用户模式和内核模式堆栈,将所有寄存器保存在堆栈上,恢复原始 LSTAR MSR 值,然后调用实际函数。一旦完成,这个过程就反过来了。
图 7. 通过更改 LSTAR MSR 调用的驱动程序加载模块中的导出函数
当加载程序在内核中正确初始化时,通过将 LSTAR MSR 更改为内核中的导出地址来执行名为 _Start64 的导出。在处理到内核的转换之后,_Start64 注册一个延迟例程,负责加载有效负载驱动程序,并返回到用户模式。延迟加载程序将尝试以“正确”方式初始化有效负载驱动程序——创建注册表项和内核驱动程序对象,执行所有必要的步骤以在系统中注册驱动程序,就像操作系统正在加载驱动程序本身一样,并且最终调用 IoCreateDriver。选择了正确的初始化方法,以便加载的有效负载驱动程序可以处理 I/O 请求数据包并使用 IOCTL 与用户模式模块进行通信。
Payload driver Payload driver提供 IOCTL 功能,用于禁用各种notification callbacks(参见图 8),主要旨在解除第三方安全解决方案。特定命令从用户模式模块传递。有趣的是,用户模式模块将尝试禁用内核中的 ESET 保护。
图 8. IOCTL handler in the InvisiMole payload driver
RobbinHood
在商业恶意软件中看到旨在覆盖尽可能多的人的 BYOVD 技术很少见,但 RobbinHood 勒索软件系列表明它可能仍然有用 [8]。 该勒索软件利用包含漏洞的 GIGABYTE 主板驱动程序 GDRV.SYS ( CVE-2018-19320;参见图 9 和图 10) 禁用 DSE 以安装其自己的恶意驱动程序。
图 9. RobbinHood 示例中的 GIODrv 驱动程序利用
禁用 DSE 的方式取决于 Windows 版本——在 Windows 7 和更早版本上,直接在 ntoskrnl 模块中修改 nt!g_CiEnabled 变量。在较新的 Windows 8 到 Windows 11 系统上,ci.dll 模块中的变量 ci!g_CiOptions 被修改。查找这个变量稍微复杂一些,看起来作者采用了一种在 GitHub 上提供的open-source project called DSEFix此外,从Windows 8.1开始,ci.dll中的变量受到PathcGuard的保护,篡改模块最终会导致系统蓝屏,即使变量被改回原来的值。 然后恶意驱动程序被用来结束一长串进程并删除它们的文件,主要集中在端点保护软件和其他实用程序上。由于终止进程是从内核模式完成的,因此能够绕过大多数的安全软件自我保护手段,并且该技术同试图从R3结束安全软件自我保护相比更有可能成功。
图 10. WriteVirtualMemory IOCTL handler in GIODrv
LoJax
2018 年,ESET 研究人员发现了first-ever UEFI rootkit used in the wild. 为了访问受害者的 UEFI 模块,该恶意软件利用了一个名为 RWEverything 的强大实用程序。 Microsoft 最近使用基于虚拟化的安全部分中描述的 HVCI 内存完整性功能直接在 Windows 10 和 11 中禁用了 RWEverything 驱动程序。
发现的漏洞 在我们的研究过程中,我们决定不仅要对现有漏洞进行分类,还要寻找新漏洞。我们设置了 YARA 规则来寻找具有特定功能和潜在漏洞指标的内核驱动程序。我们还创建了一个概念验证利用框架,用于测试新发现的驱动程序并确认它们是可被利用的。 我们检查了数百个符合我们标准的不同内核驱动程序,除了找到已经发现的驱动程序外,我们还发现了三个以前不知道易受攻击的驱动程序,其中一些包含几个不相关的错误。即使在几个独立的研究小组解决了这个领域之后,我们仍然能够找到新的漏洞,即使是来自信誉良好的供应商的驱动,这表明 Windows 驱动程序安全仍然是一个问题。 虽然我们正在寻找前几节中描述的各种漏洞,但发现具有 MSR 访问权限的漏洞是最容易的,最常见的原因是使用了放弃此功能的特殊特权指令 (RDMSR/WRMSR)。有趣的是,在许多情况下,此类驱动程序还包含其他类型的漏洞,例如任意物理或虚拟内存读写功能。
AMD μProf (CVE-2021-26334) 我们在 AMDPowerProfiler.sys 内核驱动程序中发现了一个 MSR 漏洞,该驱动程序是AMD μProf分析软件的一部分。 使该驱动程序脱颖而出的是,一旦安装了底层软件包,该驱动程序就会在每次系统启动时运行。未经过滤的 MSR IOCTL 访问加上缺少 FILE_DEVICE_SECURE_OPEN 标志(参见图 11)和开机自启动为攻击者提供了利用驱动程序的好机会,即使是作为非特权用户也是如此——与 BYOVD 方法相比,当攻击者需要自行加载驱动时,这是具有一个优势的方面
图 11. 没有 FILE_DEVICE_SECURE_OPEN 标志的 AMD uProf 内核驱动程序设备创建允许非管理员访问
另一方面,该软件是开发人员的小众程序,而不是分发到大量系统的软件包。我们尚未在驱动程序中发现任何其他漏洞。 易受攻击的 IOCTL 是 IOCTL_ACCESS_MSR (0x222030)。 AMD 承认了该漏洞 ( CVE-2021-26334 ) 并在 2021 年 11 月Patch Tuesday 版本中发布了修复程序。
Passmark software Passmark 是一家提供各种计算机基准测试和诊断工具的公司。为了在用户模式下实现这样的功能,需要通过利用内核模式驱动程序来访问许多低级系统功能。 Passmark 的 DirectIo32.sys 和 DirectIo64.sys 内核驱动程序是在多个供应商的应用程序(即 BurnInTest、PerformanceTest 和 OSForensics)之间共享和分发的通用框架。 该驱动程序包含直接的、未过滤的 MSR R/W 访问 ( CVE-2020-15480 )、映射物理内存 ( CVE-2020-15481 ) 以进行读写的能力,并且 IOCTL 处理程序还包含缓冲区溢出 ( CVE- 2020-15479 ) 由于在没有任何大小检查的情况下盲目地将任意大小的 IOCTL 输入缓冲区复制到堆栈上的局部变量。 Passmark 承认了这些漏洞,并在此后不久发布了一个修复版本。
CVE-2020-15479 当驱动程序接收到来自用户模式程序的 IOCTL 请求时,它将首先将请求的输入缓冲区复制到堆栈上的本地缓冲区中。memmove 的大小仅基于输入缓冲区的大小(参见图 12),不考虑堆栈缓冲区的容量。如果提供了足够大的 IOCTL 缓冲区,这可能会导致缓冲区溢出。IOCTL 处理函数中有多个未经检查的 memmove 调用,并且可以使用多个 IOCTL 来利用缓冲区溢出。
图 12. 易受攻击的 Passmark 驱动程序中的缓冲区溢出
CVE-2020-15480
此驱动程序提供通过 IOCTL 公开的 RDMSR 和 WRMSR 功能,允许非特权用户模式程序读取和写入任意 CPU MSR,而无需任何额外检查。易受攻击的 IOCTL 是 IOCTL_READ_MSR (0x80112060) 和 IOCTL_WRITE_MSR (0x80112088)。
CVE-2020-15481 物理内存映射功能通过单个控制代码公开 - IOCTL_MAP_PHYSICAL_MEMORY (0x80112044)。实现分为两部分:主要版本通过 ZwMapViewOfSection API 完成;如果由于某种原因此方法失败,该函数还通过 MmMapIoSpace 和 MmMapLockedPages 内核 API 实现辅助方法作为备份。两者都如图 13 所示。
图 13. Passmark 驱动程序中的物理内存 IOCTL 实现
Devid Espenschied PC Analyser
PC Analyzer 是另一个用于检查机器的各种详细信息的实用程序。与应用程序一起分发的 PCADRVX64.sys 内核驱动程序包含两个单独的漏洞 - 未过滤的 MSR 访问 ( CVE-2020-28921 ) 和读取和写入任意物理内存地址的能力 ( CVE-2020-28922 )。创建驱动程序设备时,未指定 FILE_DEVICE_SECURE_OPEN 标志,允许非特权用户检索驱动程序的句柄。 Devid Espenschied 承认了这些漏洞并发布了更新版本。
CVE-2020-28921 与以前的驱动程序一样,MSR 访问不受限制(参见图 14),并且 IOCTL 代码处理程序包含 FILE_ANY_ACCESS 标志,即使是非特权用户也可以利用该功能。
图 14. PC Analyzer 驱动程序中的 MSR IOCTL 实现
CVE-2020-28922
驱动程序的物理内存读取和写入功能是根据读取或写入请求的大小使用单独的 IOCTL 实现的。它提供了以下控制代码,它们都不会对请求所针对的内存地址进行任何检查: IOCTL_READ_PHYSICAL_MEMORY_BYTE(0x82002400)
IOCTL_READ_PHYSICAL_MEMORY_WORD(0x82002500)
IOCTL_READ_PHYSICAL_MEMORY_DWORD(0x82002600)
IOCTL_WRITE_PHYSICAL_MEMORY_BYTE(0x82002700)
IOCTL_WRITE_PHYSICAL_MEMORY_WORD(0x82002800)
IOCTL_WRITE_PHYSICAL_MEMORY_DWORD(0x82002900)
缓解措施 虽然我们已经提到了 CPU 和/或操作系统使用的几种机制,但它们中的大多数都可以通过一些巧妙的技术绕过,如果攻击者提前做好准备,它们中的大部分都不是很有效。在本节中,我们想提及一些在完全阻止滥用漏洞驱动程序方面实际上是有效的缓解措施。
基于虚拟化的安全性 基于虚拟化的安全性或 VBS 是 Windows 10 中引入的一项功能,它利用硬件虚拟化并使内核由管理程序沙盒化,以便通过各种保护来保护操作系统。 VBS 提供了多种保护功能,其中最突出的是 Hypervisor-Protected Code Integrity (HVCI),它也作为独立功能提供。HVCI 在内核中强制执行代码完整性,并且只允许执行签名代码。它还采用了黑名单功能,可以将由特定有效签名签名的已知代码列入黑名单,并且不允许运行或加载。已通过此方法列入黑名单的驱动程序之一是 RWEverything 实用程序。 HVCI 有效地防止易受攻击的驱动程序被滥用来执行未签名的内核代码或加载恶意驱动程序(无论使用何种利用方法),并且似乎恶意软件滥用易受攻击的驱动程序来加载恶意代码是微软实现此功能的主要动机之一: VBS 对防御真实攻击提供了显着的安全收益,包括我们去年看到的几种攻击,包括 RobbinHood 等人为操作的勒索软件攻击和 Trickbot 等复杂的恶意软件攻击,这些攻击采用了可以通过 HVCI 缓解的内核驱动程序和技术。我们的研究表明,与未启用 HVCI 的系统相比,启用 HVCI 的计算机向 Microsoft 365 Defender 报告检测到的活动恶意软件报告减少了 60%。Surface Book 3 于 2020 年 5 月发货,Surface Laptop Go 于 2020 年 10 月发货,用户可能没有注意到他们正在运行 VBS,因此基于the hood下的工作得到了更好的保护。[重点补充] 除了强制内核代码完整性之外,VBS 还保护重要的 MSR 并禁止对其进行任何更改。不出所料,这种保护也会影响 LSTAR MSR 并减轻上述所有漏洞利用可能性。 虽然 VBS 通常可以有效地防止 MSR 攻击和在内核中运行恶意代码,但这项新功能的采用非常有限,因为它有几个硬件要求,只有较新的机器才能满足。还有一些缺点,最显着的是性能下降,根据工作负载的不同,这可能非常明显。虽然一些基准测试估计特定视频游戏性能影响高达25% more detailed benchmarking by Tom’s Hardware根据具体的基准和硬件配置估计性能损失约为 5%(参见图 15),这仍然不是一个可以忽略的数量,可能会导致一些用户考虑关闭此功能。旧版驱动程序和软件也可能存在一些兼容性问题。随着 Windows 11 的发布,微软决定默认为所有兼容设备启用 HVCI。
图 15. Tom's Hardware 的 VBS 基准测试结果
第三方管理程序
与 Microsoft 的 VBS 类似,使用足够新的硬件,第三方安全解决方案可能会部署自己的自定义管理程序。在管理程序下运行操作系统可以详细监督机器的状态,并提供检查和拦截任何事件的可能性,包括执行特定指令。与 VBS 一样,这是有代价的,即性能和兼容性。
证书吊销 在现代 Windows 系统上,驱动程序需要具有基于“可信任”证书的有效签名。因此,撤销易受攻击的驱动程序的证书将是一种“解除”漏洞驱动威胁并在大多数情况下使其失去作用的简单方法。 可悲的是,撤销签名很少发生,在我们上述研究中记录的漏洞驱动程序中,没有一个漏洞驱动的签名被撤销。没有发生此类撤销的原因可能有很多,但主要原因可能是时间和成本。由于没有人要求撤销,从供应商的角度来看,要求撤销没有多大意义,因为这将是一个昂贵且耗时的过程。此外,签名证书通常在其他项目之间共享,因此由于单个驱动程序可能导致的撤销可能会阻碍每个项目的开发。 此外,在我们的研究中,我们了解到证书被吊销的驱动程序并不总是被阻止加载,而且这个问题比最初看起来要复杂得多。毕竟,撤销可能不是最简单的解决方案。
驱动程序黑名单 驱动程序黑名单是 Microsoft 和各种第三方安全产品供应商采用的一种做法。ESET 安全产品会检测到一些最臭名昭著的漏洞驱动程序,并在系统上发现时将其删除。微软还选择不仅通过其安全解决方案将驱动程序列入黑名单,而且还直接通过操作系统利用其 HVCI 缓解措施(这是基于虚拟化的安全性的一部分)。虽然黑名单是有效的,但它不是一种主动解决方案——只有以前发现的易受攻击的驱动程序才能被列入黑名单,而且必须由每个供应商手动完成。这意味着这种缓解措施将无法有效应对以前未知的、可能用于复杂 APT 攻击的零日驱动程序漏洞。 最突出的被列入黑名单的驱动程序可能是 Capcom “反作弊”驱动程序 Capcom.sys,它实现了一个 IOCTL,它在内核模式下简单地执行所提供缓冲区的内容(参见图 16)。为了能够执行从用户模式提供的缓冲区,它甚至会暂时禁用 SMEP! 一经发现,该驱动程序登上了多个头条,许多未签名的驱动程序加载工具都是基于滥用驱动程序的此功能而创建的。因此,该驱动程序最终被包括 Microsoft 和 ESET 在内的安全软件提供商拦截。
图 16. Capcom 反作弊驱动程序的代码片段
结论
包含漏洞的驱动程序长期以来一直是一个已知问题,并被游戏作弊社区和恶意软件作者滥用,虽然已经做出了一些努力来减轻影响,但它仍然是一场持续的战斗。似乎所有相关的责任方都想解决这个问题——我们联系的供应商在披露过程中非常积极主动,急于修复我们发现的漏洞。微软正试图从内部加强操作系统,最后但并非最不重要的一点是,第三方安全供应商正试图想出聪明的方法来检测和缓解这些驱动程序本身。 然而,似乎仍然缺少一点——一种通用的、统一的处理这些问题的方法,包括更彻底地“解除”漏洞驱动的威胁,无论是通过撤销或屏蔽他们的证书,还是安全公司采用的一些公开的、共享的黑名单。 |