OP 02 March, 2024 - 12:56 PM
(This post was last modified: 12 March, 2024 - 08:23 PM by angelbanker. Edited 1 time in total.)
Avast has discovered an admin/kernel exploit related to a previously unknown zero-day vulnerability in the AppID.sys AppLocker driver.
Thanks to Avast's operational report, Microsoft has addressed this vulnerability as CVE-2024-21338 in the February Patch Tuesday update.
The exploitation effort was organized by the notorious Lazarus Group with the ultimate goal of creating a kernel read/write primitive.
This primitive allowed Lazarus to perform direct manipulation of kernel objects in an updated version of the data-only FudModule rootkit, a previous version of which was analyzed by ESET and AhnLab.
After completely reverse engineering this updated rootkit variant, Avast found significant improvements in terms of functionality and stealth, offering four new and three updated rootkit methods.
A key development is that the rootkit now uses a new technique to manipulate handle table entries in an attempt to kill PPL (Protected Process Light) processes associated with Microsoft Defender, CrowdStrike Falcon and HitmanPro.
Another important step forward is the use of a zero-day vulnerability, where Lazarus previously used much noisier BYOVD (bring your own vulnerable driver) methods to cross the boundary between the administrator and the kernel.
Avast's investigation also uncovered a significant portion of the infection chain leading to the deployment of the rootkit, leading to the discovery of a new RAT (remote access trojan) attributed to Lazarus.
Technical details regarding the RAT and the initial infection vector will be published in a future blog post scheduled to be released alongside our Black Hat Asia 2024 briefing.
![[Image: appid-device-acl.png]](https://i.ibb.co/N9wfZCy/appid-device-acl.png)
We developed a custom PoC (Proof of Concept) exploit and submitted it in August 2023 as part of a vulnerability report to Microsoft, leading to an advisory for CVE-2024-21338 in the February Patch Tuesday update. The update addressed the vulnerability by adding an
check to the IOCTL handler (see the patch below). This aims to prevent user-mode initiated IOCTLs from triggering the arbitrary callbacks.
![[Image: patch-diaphora-1-1024x332.png]](https://i.ibb.co/4SmjJL5/patch-diaphora-1-1024x332.png)
direct-syscalls:
![[Image: direct-syscall.png]](https://i.ibb.co/GWLkJ5J/direct-syscall.png)
All three of the above
globals are organized as an array of
pointers to
structures (at least that’s the name used in ReactOS, Microsoft does not share a symbol name here). FudModule iterates over all these structures and checks if
(the actual callback routine pointer) is implemented in one of the below-whitelisted modules. If it is, the pointer will get appended to a new array that will be used to replace the original one. This effectively removes all callbacks except for those implemented in one of the below-listed modules.
0x08 – Minifilter Drivers File system minifilters provide a mechanism for drivers to intercept file system operations. They are used in a wide range of scenarios, including encryption, compression, replication, monitoring, antivirus scanning, or file system virtualization. For instance, an encryption minifilter would encrypt the data before it is written to the storage device and, conversely, decrypt the data after it is read. FudModule is trying to get rid of all the monitoring and antivirus minifilters while leaving the rest untouched (after all, some minifilters are crucial to keep the system running). The choice about which minifilters to keep and which to remove is based mainly on the minifilter’s altitude, an integer value that is used to decide the processing order in case there are multiple minifilters attached to the same operation. Microsoft defines altitude ranges that should be followed by well-behaved minifilters. Unfortunately, these ranges also represent a very convenient way for FudModule to distinguish anti-malware minifilters from the rest.
In its previous version, FudModule disabled minifilters by directly patching their filter functions’ prologues. This would be considered very unusual today, with HVCI (Hypervisor-Protected Code Integrity) becoming more prevalent, even turned on by default on Windows 11. Since HVCI is a security feature designed to prevent the execution of arbitrary code in the kernel, it would stand in the way of FudModule trying to patch the filter function. This forced Lazarus to completely reimplement this rootkit technique, so the current version of FudModule disables file system minifilters in a brand-new data-only attack.
This attack starts by resolving
and using it to find
. This is a linked list of
structures, each representing a single filter manager frame. From here, FudModule follows another linked list at
. This linked list consists of
structures, describing minifilters attached to a particular file system volume. Interestingly, the rootkit performs a sanity check to make sure that the pool tag associated with the
allocation is equal to
. With the sanity check satisfied, FudModule iterates over
, which is an array of linked lists of
structures, indexed by IRP major function codes. For instance,
is a linked list describing all filters attached to the
operation on a particular volume.
pool-check:
![[Image: pooltag-check.png]](https://i.ibb.co/FDrPL36/pooltag-check.png)
Handle Table Entry Manipulation
The technique employed to attack Defender, CrowdStrike, and HitmanPro is much more intriguing: FudModule attempts to suspend them using a new handle table entry manipulation technique. To better understand this technique, let’s begin with a brief background on handle tables. When user-mode code interacts with kernel objects such as processes, files, or mutexes, it typically doesn’t work with the objects directly. Instead, it references them indirectly through handles. Internally, the kernel must be able to translate the handle to the corresponding object, and this is where the handle table comes in. This per-process table, available at
, serves as a mapping from handles to the underlying objects. Organized as an array, it is indexed by the integer value of the handle. Each element is of type
and contains two crucial pieces of information: a (compressed) pointer to the object’s header (
) and access bits associated with the handle. Due to this handle design, kernel object access checks are typically split into two separate logical steps. The first step happens when a process attempts to acquire a handle (such as opening a file with
). During this step, the current thread’s token is typically checked against the target object’s security descriptor to ensure that the thread is allowed to obtain a handle with the desired access mask. The second check takes place when a process performs an operation using an already acquired handle (such as writing to a file with
). This typically only involves verifying that the handle is powerful enough (meaning it has the right access bits) for the requested operation. FudModule executes as a non-protected process, so it theoretically shouldn’t be able to obtain a powerful handle to a PPL-protected process such as the CrowdStrike Falcon Service. However, leveraging the kernel read/write primitive, FudModule has the ability to access the handle table directly. This allows it to craft a custom handle table entry with control over both the referenced object and the access bits. This way, it can conjure an arbitrary handle to any object, completely bypassing the check typically needed for handle acquisition. What’s more, if it sets the handle’s access bits appropriately, it will also satisfy the subsequent handle checks when performing its desired operations.
To prepare for the handle table entry manipulation technique, FudModule creates a dummy thread that just puts itself to sleep immediately. The thread itself is not important. What is important is that by calling
, the rootkit just obtained a thread handle with
rights. This handle is the one that will have its handle table entry manipulated. Since it already has very powerful access bits, the rootkit will not even have to touch its
. All it needs to do is overwrite
to redirect the handle to an arbitrary object of its choice. This will make the handle reference that object and enable the rootkit to perform privileged operations on it. Note that
is not the whole pointer to the object: it only represents 44 bits of the 64-bit pointer. But since the
pointed to by
is guaranteed to be aligned (meaning the least significant four bits must be zero) and in kernel address space (meaning the most significant sixteen bits must be
), the remaining 20 bits can be easily inferred.
![[Image: sleep-thread.png]](https://i.ibb.co/pxNKkgg/sleep-thread.png)
This is a bump
Thanks to Avast's operational report, Microsoft has addressed this vulnerability as CVE-2024-21338 in the February Patch Tuesday update.
The exploitation effort was organized by the notorious Lazarus Group with the ultimate goal of creating a kernel read/write primitive.
This primitive allowed Lazarus to perform direct manipulation of kernel objects in an updated version of the data-only FudModule rootkit, a previous version of which was analyzed by ESET and AhnLab.
After completely reverse engineering this updated rootkit variant, Avast found significant improvements in terms of functionality and stealth, offering four new and three updated rootkit methods.
A key development is that the rootkit now uses a new technique to manipulate handle table entries in an attempt to kill PPL (Protected Process Light) processes associated with Microsoft Defender, CrowdStrike Falcon and HitmanPro.
Another important step forward is the use of a zero-day vulnerability, where Lazarus previously used much noisier BYOVD (bring your own vulnerable driver) methods to cross the boundary between the administrator and the kernel.
Avast's investigation also uncovered a significant portion of the infection chain leading to the deployment of the rootkit, leading to the discovery of a new RAT (remote access trojan) attributed to Lazarus.
Technical details regarding the RAT and the initial infection vector will be published in a future blog post scheduled to be released alongside our Black Hat Asia 2024 briefing.
Code:
NTSTATUS __fastcall AppHashComputeImageHashInternal(
__int64 user_controlled_buffer,
__int64 (__fastcall **user_controlled_ptr)(__int64, __int128 *),
unsigned int a3,
__int64 a4)
{
...
status = (*user_controlled_ptr)(user_controlled_buffer, &v42);
if ( status < 0 )
return status;
...
}![[Image: appid-device-acl.png]](https://i.ibb.co/N9wfZCy/appid-device-acl.png)
We developed a custom PoC (Proof of Concept) exploit and submitted it in August 2023 as part of a vulnerability report to Microsoft, leading to an advisory for CVE-2024-21338 in the February Patch Tuesday update. The update addressed the vulnerability by adding an
Code:
ExGetPreviousMode![[Image: patch-diaphora-1-1024x332.png]](https://i.ibb.co/4SmjJL5/patch-diaphora-1-1024x332.png)
direct-syscalls:
![[Image: direct-syscall.png]](https://i.ibb.co/GWLkJ5J/direct-syscall.png)
All three of the above
Code:
nt!Psp(LoadImage|CreateThread|CreateProcess)NotifyRoutineCode:
_EX_FAST_REFCode:
_EX_CALLBACK_ROUTINE_BLOCKCode:
_EX_CALLBACK_ROUTINE_BLOCK.FunctionCode:
ntoskrnl.exe Code:
ahcache.sys Code:
mmcss.sys Code:
cng.sys Code:
ksecdd.sys Code:
tcpip.sys Code:
iorate.sys Code:
ci.dll Code:
dxgkrnl.sys Code:
peauth.sys Code:
wtd.sys0x08 – Minifilter Drivers File system minifilters provide a mechanism for drivers to intercept file system operations. They are used in a wide range of scenarios, including encryption, compression, replication, monitoring, antivirus scanning, or file system virtualization. For instance, an encryption minifilter would encrypt the data before it is written to the storage device and, conversely, decrypt the data after it is read. FudModule is trying to get rid of all the monitoring and antivirus minifilters while leaving the rest untouched (after all, some minifilters are crucial to keep the system running). The choice about which minifilters to keep and which to remove is based mainly on the minifilter’s altitude, an integer value that is used to decide the processing order in case there are multiple minifilters attached to the same operation. Microsoft defines altitude ranges that should be followed by well-behaved minifilters. Unfortunately, these ranges also represent a very convenient way for FudModule to distinguish anti-malware minifilters from the rest.
In its previous version, FudModule disabled minifilters by directly patching their filter functions’ prologues. This would be considered very unusual today, with HVCI (Hypervisor-Protected Code Integrity) becoming more prevalent, even turned on by default on Windows 11. Since HVCI is a security feature designed to prevent the execution of arbitrary code in the kernel, it would stand in the way of FudModule trying to patch the filter function. This forced Lazarus to completely reimplement this rootkit technique, so the current version of FudModule disables file system minifilters in a brand-new data-only attack.
This attack starts by resolving
Code:
FltEnumerateFiltersCode:
FltGlobals.FrameList.rListCode:
FLTMGR!_FLTP_FRAMECode:
_FLTP_FRAME.AttachedVolumes.rListCode:
FLTMGR!_FLT_VOLUMECode:
_FLT_VOLUMECode:
FMvoCode:
_FLT_VOLUME.Callbacks.OperationsListsCode:
FLTMGR!_CALLBACK_NODECode:
OperationsLists[IRP_MJ_READ]Code:
readpool-check:
![[Image: pooltag-check.png]](https://i.ibb.co/FDrPL36/pooltag-check.png)
Handle Table Entry Manipulation
The technique employed to attack Defender, CrowdStrike, and HitmanPro is much more intriguing: FudModule attempts to suspend them using a new handle table entry manipulation technique. To better understand this technique, let’s begin with a brief background on handle tables. When user-mode code interacts with kernel objects such as processes, files, or mutexes, it typically doesn’t work with the objects directly. Instead, it references them indirectly through handles. Internally, the kernel must be able to translate the handle to the corresponding object, and this is where the handle table comes in. This per-process table, available at
Code:
_EPROCESS.ObjectTable.TableCodeCode:
_HANDLE_TABLE_ENTRYCode:
nt!_OBJECT_HEADERCode:
CreateFileCode:
WriteFileTo prepare for the handle table entry manipulation technique, FudModule creates a dummy thread that just puts itself to sleep immediately. The thread itself is not important. What is important is that by calling
Code:
CreateThreadCode:
THREAD_ALL_ACCESSCode:
_HANDLE_TABLE_ENTRY.GrantedAccessBitsCode:
_HANDLE_TABLE_ENTRY.ObjectPointerBitsCode:
ObjectPointerBitsCode:
_OBJECT_HEADERCode:
ObjectPointerBitsCode:
0xFFFF![[Image: sleep-thread.png]](https://i.ibb.co/pxNKkgg/sleep-thread.png)
This is a bump