Navigation X
ALERT
Click here to register with a few steps and explore all our cool stuff we have to offer!



   398

FudModule Rootkit: Beyond BYOVD with an Admin-to-Kernel Zero-Day

by angelbanker - 02 March, 2024 - 12:56 PM
This post is by a banned member (angelbanker) - Unhide
149
Posts
20
Threads
2 Years of service
#1
(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.
 
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]

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
 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]
direct-syscalls:
[Image: direct-syscall.png]
 All three of the above 
Code:
nt!Psp(LoadImage|CreateThread|CreateProcess)NotifyRoutine
 globals are organized as an array of 
Code:
_EX_FAST_REF
 pointers to 
Code:
_EX_CALLBACK_ROUTINE_BLOCK
 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 
Code:
_EX_CALLBACK_ROUTINE_BLOCK.Function
 (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. 
Code:
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.sys

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 
Code:
FltEnumerateFilters
 and using it to find 
Code:
FltGlobals.FrameList.rList
. This is a linked list of 
Code:
FLTMGR!_FLTP_FRAME
 structures, each representing a single filter manager frame. From here, FudModule follows another linked list at 
Code:
_FLTP_FRAME.AttachedVolumes.rList
. This linked list consists of 
Code:
FLTMGR!_FLT_VOLUME
 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 
Code:
_FLT_VOLUME
 allocation is equal to 
Code:
FMvo
. With the sanity check satisfied, FudModule iterates over 
Code:
_FLT_VOLUME.Callbacks.OperationsLists
, which is an array of linked lists of 
Code:
FLTMGR!_CALLBACK_NODE
 structures, indexed by IRP major function codes. For instance, 
Code:
OperationsLists[IRP_MJ_READ]
 is a linked list describing all filters attached to the 
Code:
read
 operation on a particular volume. 

pool-check:
[Image: 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.TableCode
, 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 
Code:
_HANDLE_TABLE_ENTRY
 and contains two crucial pieces of information: a (compressed) pointer to the object’s header (
Code:
nt!_OBJECT_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 
Code:
CreateFile
). 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 
Code:
WriteFile
). 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 
Code:
CreateThread
, the rootkit just obtained a thread handle with 
Code:
THREAD_ALL_ACCESS
 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 
Code:
_HANDLE_TABLE_ENTRY.GrantedAccessBits
. All it needs to do is overwrite 
Code:
_HANDLE_TABLE_ENTRY.ObjectPointerBits
 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 
Code:
ObjectPointerBits
 is not the whole pointer to the object: it only represents 44 bits of the 64-bit pointer. But since the 
Code:
_OBJECT_HEADER
 pointed to by 
Code:
ObjectPointerBits
 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 
Code:
0xFFFF
), the remaining 20 bits can be easily inferred. 

[Image: sleep-thread.png]

 

This is a bump
This post is by a banned member (angelbanker) - Unhide
149
Posts
20
Threads
2 Years of service
Bumped #2
This is a bump
This post is by a banned member (angelbanker) - Unhide
149
Posts
20
Threads
2 Years of service
Bumped #3
This is a bump
This post is by a banned member (angelbanker) - Unhide
149
Posts
20
Threads
2 Years of service
Bumped #4
This is a bump
This post is by a banned member (angelbanker) - Unhide
149
Posts
20
Threads
2 Years of service
Bumped #5
This is a bump

Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
or
Sign in
Already have an account? Sign in here.


Forum Jump:


Users browsing this thread: 1 Guest(s)