{
	"id": "7a7d2585-31a8-48b5-95f5-15713096664e",
	"created_at": "2026-04-06T00:19:43.370764Z",
	"updated_at": "2026-04-10T13:12:30.894352Z",
	"deleted_at": null,
	"sha1_hash": "09a02342ca6e0063e4ea42ec41d84dc733e54643",
	"title": "Lazarus and the FudModule Rootkit: Beyond BYOVD with an Admin-to-Kernel Zero-Day",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 4223589,
	"plain_text": "Lazarus and the FudModule Rootkit: Beyond BYOVD with an\r\nAdmin-to-Kernel Zero-Day\r\nBy Jan VojtěšekAuthor at Avast Threat Labs\r\nArchived: 2026-04-05 15:02:24 UTC\r\nKey Points\r\nAvast discovered an in-the-wild admin-to-kernel exploit for a previously unknown zero-day vulnerability\r\nin the appid.sys AppLocker driver. \r\nThanks to Avast’s prompt report, Microsoft addressed this vulnerability as CVE-2024-21338 in the\r\nFebruary Patch Tuesday update. \r\nThe exploitation activity was orchestrated by the notorious Lazarus Group, with the end goal of\r\nestablishing a kernel read/write primitive. \r\nThis primitive enabled Lazarus to perform direct kernel object manipulation in an updated version of their\r\ndata-only FudModule rootkit, a previous version of which was analyzed by ESET and AhnLab. \r\nAfter completely reverse engineering this updated rootkit variant, Avast identified substantial\r\nadvancements in terms of both functionality and stealth, with four new – and three updated – rootkit\r\ntechniques. \r\nIn a key advancement, the rootkit now employs a new handle table entry manipulation technique in an\r\nattempt to suspend PPL (Protected Process Light) protected processes associated with Microsoft Defender,\r\nCrowdStrike Falcon, and HitmanPro. \r\nAnother significant step up is exploiting the zero-day vulnerability, where Lazarus previously utilized\r\nmuch noisier BYOVD (Bring Your Own Vulnerable Driver) techniques to cross the admin-to-kernel\r\nboundary. \r\nAvast’s investigation also recovered large parts of the infection chain leading up to the deployment of the\r\nrootkit, resulting in the discovery of a new RAT (Remote Access Trojan) attributed to Lazarus. \r\nTechnical details concerning the RAT and the initial infection vector will be published in a follow-up blog\r\npost, scheduled for release along with our Black Hat Asia 2024 briefing. \r\nIntroduction \r\nWhen it comes to Windows security, there is a thin line between admin and kernel. Microsoft’s security servicing\r\ncriteria have long asserted that “[a]dministrator-to-kernel is not a security boundary”, meaning that Microsoft\r\nreserves the right to patch admin-to-kernel vulnerabilities at its own discretion. As a result, the Windows security\r\nmodel does not guarantee that it will prevent an admin-level attacker from directly accessing the kernel. This isn’t\r\njust a theoretical concern. In practice, attackers with admin privileges frequently achieve kernel-level access by\r\nexploiting known vulnerable drivers, in a technique called BYOVD (Bring Your Own Vulnerable Driver). \r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 1 of 22\n\nMicrosoft hasn’t given up on securing the admin-to-kernel boundary though. Quite the opposite, it has made a\r\ngreat deal of progress in making this boundary harder to cross. Defense-in-depth protections, such as DSE (Driver\r\nSignature Enforcement) or HVCI (Hypervisor-Protected Code Integrity), have made it increasingly difficult for\r\nattackers to execute custom code in the kernel, forcing most to resort to data-only attacks (where they achieve\r\ntheir malicious objectives solely by reading and writing kernel memory). Other defenses, such as driver\r\nblocklisting, are pushing attackers to move to exploiting less-known vulnerable drivers, resulting in an increase in\r\nattack complexity. Although these defenses haven’t yet reached the point where we can officially call admin-to-kernel a security boundary (BYOVD attacks are still feasible, so calling it one would just mislead users into a\r\nfalse sense of security), they clearly represent steps in the right direction. \r\nFrom the attacker’s perspective, crossing from admin to kernel opens a whole new realm of possibilities. With\r\nkernel-level access, an attacker might disrupt security software, conceal indicators of infection (including files,\r\nnetwork activity, processes, etc.), disable kernel-mode telemetry, turn off mitigations, and more. Additionally, as\r\nthe security of PPL (Protected Process Light) relies on the admin-to-kernel boundary, our hypothetical attacker\r\nalso gains the ability to tamper with protected processes or add protection to an arbitrary process. This can be\r\nespecially powerful if lsass is protected with RunAsPPL as bypassing PPL could enable the attacker to dump\r\notherwise unreachable credentials.  \r\nFor more specific examples of what an attacker might want to achieve with kernel-level access, keep reading this\r\nblog – in the latter half, we will dive into all the techniques implemented in the FudModule rootkit. \r\nLiving Off the Land: Vulnerable Drivers Edition \r\nWith a seemingly growing number of attackers seeking to abuse some of the previously mentioned kernel\r\ncapabilities, defenders have no choice but to hunt heavily for driver exploits. Consequently, attackers wishing to\r\ntarget well-defended networks must also step up their game if they wish to avoid detection. We can broadly break\r\ndown admin-to-kernel driver exploits into three categories, each representing a trade-off between attack difficulty\r\nand stealth. \r\nN-Day BYOVD Exploits \r\nIn the simplest case, an attacker can leverage BYOVD to exploit a publicly known n-day vulnerability. This is\r\nvery easy to pull off, as there are plenty of public proof-of-concept exploits for various vulnerabilities. However,\r\nit’s also relatively straightforward to detect since the attacker must first drop a known vulnerable driver to the file\r\nsystem and then load it into the kernel, resulting in two great detection opportunities. What’s more, some systems\r\nmay have Microsoft’s vulnerable driver blocklist enabled, which would block some of the most common\r\nvulnerable drivers from loading. Previous versions of the FudModule rootkit could be placed in this category,\r\ninitially exploiting a known vulnerability in dbutil_2_3.sys and then moving on to targeting ene.sys in later\r\nversions. \r\nZero-Day BYOVD Exploits \r\nIn more sophisticated scenarios, an attacker would use BYOVD to exploit a zero-day vulnerability within a signed\r\nthird-party driver. Naturally, this requires the attacker to first discover such a zero-day vulnerability, which might\r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 2 of 22\n\ninitially seem like a daunting task. However, note that any exploitable vulnerability in any signed driver will do,\r\nand there is unfortunately no shortage of low-quality third-party drivers. Therefore, the difficulty level of\r\ndiscovering such a vulnerability might not be as high as it would initially seem. It might suffice to scan a\r\ncollection of drivers for known vulnerability patterns, as demonstrated by Carbon Black researchers who recently\r\nused bulk static analysis to uncover 34 unique vulnerabilities across more than 200 signed drivers. Such zero-day\r\nBYOVD attacks are notably stealthier than n-day attacks since defenders can no longer rely on hashes of known\r\nvulnerable drivers for detection. However, some detection opportunities still remain, as loading a random driver\r\nrepresents a suspicious event that might warrant deeper investigation. For an example of an attack belonging to\r\nthis category, consider the spyware vendor Candiru, which we caught exploiting a zero-day vulnerability in hw.sys\r\nfor the final privilege escalation stage of their browser exploit chain. \r\nBeyond BYOVD \r\nFinally, the holy grail of admin-to-kernel is going beyond BYOVD by exploiting a zero-day in a driver that’s\r\nknown to be already installed on the target machine. To make the attack as universal as possible, the most obvious\r\ntarget here would be a built-in Windows driver that’s already a part of the operating system.  \r\nDiscovering an exploitable vulnerability in such a driver is significantly more challenging than in the previous\r\nBYOVD scenarios for two reasons. First, the number of possible target drivers is vastly smaller, resulting in a\r\nmuch-reduced attack surface. Second, the code quality of built-in drivers is arguably higher than that of random\r\nthird-party drivers, making vulnerabilities much more difficult to find. It’s also worth noting that – while patching\r\ntends to be ineffective at stopping BYOVD attacks (even if a vendor patches their driver, the attacker can still\r\nabuse the older, unpatched version of the driver) – patching a built-in driver will make the vulnerability no longer\r\nusable for this kind of zero-day attacks. \r\nIf an attacker, despite all of these hurdles, manages to exploit a zero-day vulnerability in a built-in driver, they will\r\nbe rewarded with a level of stealth that cannot be matched by standard BYOVD exploitation. By exploiting such a\r\nvulnerability, the attacker is in a sense living off the land with no need to bring, drop, or load any custom drivers,\r\nmaking it possible for a kernel attack to be truly fileless. This not only evades most detection mechanisms but also\r\nenables the attack on systems where driver allowlisting is in place (which might seem a bit ironic, given that\r\nCVE-2024-21338 concerns an AppLocker driver).  \r\nWhile we can only speculate on Lazarus’ motivation for choosing this third approach for crossing the admin-to-kernel boundary, we believe that stealth was their primary motivation. Given their level of notoriety, they would\r\nhave to swap vulnerabilities any time someone burned their currently used BYOVD technique. Perhaps they also\r\nreasoned that, by going beyond BYOVD, they could minimize the need for swapping by staying undetected for\r\nlonger. \r\nCVE-2024-21338 \r\nAs far as zero-days go, CVE-2024-21338 is relatively straightforward to both understand and exploit. The\r\nvulnerability resides within the IOCTL (Input and Output Control) dispatcher in appid.sys , which is the central\r\ndriver behind AppLocker, the application whitelisting technology built into Windows. The vulnerable control code\r\n0x22A018 is designed to compute a smart hash of an executable image file. This IOCTL offers some flexibility\r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 3 of 22\n\nby allowing the caller to specify how the driver should query and read the hashed file. The problem is, this\r\nflexibility is achieved by expecting two kernel function pointers referenced from the IOCTL’s input buffer: one\r\ncontaining a callback pointer to query the hashed file’s size and the other a callback pointer to read the data to be\r\nhashed.  \r\nSince user mode would typically not be handling kernel function pointers, this design suggests the IOCTL may\r\nhave been initially designed to be invoked from the kernel. Indeed, while we did not find any legitimate user-mode callers, the IOCTL does get invoked by other AppLocker drivers. For instance, there is a\r\nZwDeviceIoControlFile call in applockerfltr.sys , passing SmpQueryFile and SmpReadFile for the\r\ncallback pointers. Aside from that, appid.sys itself also uses this functionality, passing AipQueryFileHandle\r\nand AipReadFileHandle (which are basically just wrappers over ZwQueryInformationFile and ZwReadFile ,\r\nrespectively). \r\nDespite this design, the vulnerable IOCTL remained accessible from user space, meaning that a user-space\r\nattacker could abuse it to essentially trick the kernel into calling an arbitrary pointer. What’s more, the attacker\r\nalso partially controlled the data referenced by the first argument passed to the invoked callback function. This\r\npresented an ideal exploitation scenario, allowing the attacker to call an arbitrary kernel function with a high\r\ndegree of control over the first argument. \r\nA WinDbg session with the triggered vulnerability, traced to the arbitrary callback invocation. Note that the\r\nattacker controls both the function pointer to be called ( 0xdeadbeefdeadbeef in this session) and the data pointed\r\nto by the first argument ( 0xbaadf00dbaadf00d ). \r\nIf exploitation sounds trivial, note that there are some constraints on what pointers this vulnerability allows an\r\nattacker to call. Of course, in the presence of SMEP (Supervisor Mode Execution Prevention), the attacker cannot\r\njust supply a user-mode shellcode pointer. What’s more, the callback invocation is an indirect call that may be\r\nsafeguarded by kCFG (Kernel Control Flow Guard), requiring that the supplied kernel pointers represent valid\r\nkCFG call targets. In practice, this does not prevent exploitation, as the attacker can just find some kCFG-compliant gadget function that would turn this into another primitive, such as a (limited) read/write. There are also\r\na few other constraints on the IOCTL input buffer that must be solved in order to reach the vulnerable callback\r\ninvocation. However, these too are relatively straightforward to satisfy, as the attacker only needs to fake some\r\nkernel objects and supply the right values so that the IOCTL handler passes all the necessary checks while at the\r\nsame time not crashing the kernel. \r\nThe vulnerable IOCTL is exposed through a device object named \\Device\\AppId . Breaking down the 0x22A018\r\ncontrol code and extracting the RequiredAccess field reveals that a handle with write access is required to call it.\r\nInspecting the device’s ACL (Access Control List; see the screenshot below), there are entries for local\r\nservice , administrators , and appidsvc . While the entry for administrators does not grant write access,\r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 4 of 22\n\nthe entry for local service does. Therefore, to describe CVE-2024-21338 more accurately, we should label it\r\nlocal service-to-kernel rather than admin-to-kernel. It’s also noteworthy that appid.sys might create two\r\nadditional device objects, namely \\Device\\AppidEDPPlugin and \\Device\\SrpDevice . Although these come with\r\nmore permissive ACLs, the vulnerable IOCTL handler is unreachable through them, rendering them irrelevant for\r\nexploitation purposes. \r\nAccess control entries of \\Device\\AppId, revealing that while local service is allowed write access, administrators\r\nare not.\r\nAs the local service account has reduced privileges compared to administrators, this also gives the vulnerability a\r\nsomewhat higher impact than standard admin-to-kernel. This might be the reason Microsoft characterized the\r\nCVE as Privileges Required: Low , taking into account that local service processes do not always\r\nnecessarily have to run at higher integrity levels. However, for the purposes of this blog, we still chose to refer to\r\nCVE-2024-21338 mainly as an admin-to-kernel vulnerability because we find it better reflects how it was used in\r\nthe wild – Lazarus was already running with elevated privileges and then impersonated the local service account\r\njust prior to calling the IOCTL. \r\nThe vulnerability was introduced in Win10 1703 (RS2/15063) when the 0x22A018 IOCTL handler was first\r\nimplemented. Older builds are not affected as they lack support for the vulnerable IOCTL. Interestingly, the\r\nLazarus exploit bails out if it encounters a build older than Win10 1809 (RS5/17763), completely disregarding\r\nthree perfectly vulnerable Windows versions. As for the later versions, the vulnerability extended all the way up to\r\nthe most recent builds, including Win11 23H2. There have been some slight changes to the IOCTL, including an\r\nextra argument expected in the input buffer, but nothing that would prevent exploitation.  \r\nWe developed a custom PoC (Proof of Concept) exploit and submitted it in August 2023 as part of a vulnerability\r\nreport to Microsoft, leading to an advisory for CVE-2024-21338 in the February Patch Tuesday update. The\r\nupdate addressed the vulnerability by adding an ExGetPreviousMode check to the IOCTL handler (see the patch\r\nbelow). This aims to prevent user-mode initiated IOCTLs from triggering the arbitrary callbacks. \r\nThe patched IOCTL handler. If feature 2959575357 is enabled, attempts to call the IOCTL with\r\nPreviousMode==UserMode should immediately result in STATUS_INVALID_DEVICE_REQUEST, failing to\r\neven reach AipSmartHashImageFile.\r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 5 of 22\n\nThough the vulnerability may only barely meet Microsoft’s security servicing criteria, we believe patching was\r\nthe right choice and would like to thank Microsoft for eventually addressing this issue. Patching will undoubtedly\r\ndisrupt Lazarus’ offensive operations, forcing them to either find a new admin-to-kernel zero-day or revert to\r\nusing BYOVD techniques. While discovering an admin-to-kernel zero-day may not be as challenging as\r\ndiscovering a zero-day in a more attractive attack surface (such as standard user-to-kernel, or even sandbox-to-kernel), we believe that finding one would still require Lazarus to invest significant resources, potentially\r\ndiverting their focus from attacking some other unfortunate targets. \r\nExploitation \r\nThe Lazarus exploit begins with an initialization stage, which performs a one-time setup for both the exploit and\r\nthe rootkit (both have been compiled into the same module). This initialization starts by dynamically resolving all\r\nnecessary Windows API functions, followed by a low-effort anti-debug check on PEB.BeingDebugged . Then, the\r\nexploit inspects the build number to see if it’s running on a supported Windows version. If so, it loads hardcoded\r\nconstants tailored to the current build. Interestingly, the choice of constants sometimes comes down to the update\r\nbuild revision (UBR), showcasing a high degree of dedication towards ensuring that the code runs cleanly across a\r\nwide range of target machines.  \r\nA decompiled code snippet, loading version-specific hardcoded constants. This particular example contains offsets\r\nand syscall numbers for Win10 1809.\r\nThe initialization process then continues with leaking the base addresses of three kernel modules: ntoskrnl ,\r\nnetio , and fltmgr . This is achieved by calling NtQuerySystemInformation using the\r\nSystemModuleInformation class. The KTHREAD address of the currently executing thread is also leaked in a\r\nsimilar fashion, by duplicating the current thread pseudohandle and then finding the corresponding kernel object\r\naddress using the SystemExtendedHandleInformation system information class. Finally, the exploit manually\r\nloads the ntoskrnl image into the user address space, only to scan for relative virtual addresses (RVAs) of some\r\nfunctions of interest. \r\nSince the appid.sys driver does not have to be already loaded on the target machine, the exploit may first have\r\nto load it itself. It chooses to accomplish this in an indirect way, by writing an event to one specific AppLocker-related ETW (Event Tracing for Windows) provider. Once appid.sys is loaded, the exploit impersonates the\r\nlocal service account using a direct syscall to NtSetInformationThread with the\r\nThreadImpersonationToken thread information class. By impersonating local service , it can now obtain a\r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 6 of 22\n\nread/write handle to \\Device\\AppId . With this handle, the exploit finally prepares the IOCTL input buffer and\r\ntriggers the vulnerability using the NtDeviceIoControlFile syscall.  \r\nDirect syscalls are heavily used throughout the exploit.\r\nThe exploit crafts the IOCTL input buffer in such a way that the vulnerable callback is essentially a gadget that\r\nperforms a 64-bit copy from the IOCTL input buffer to an arbitrary target address. This address was chosen to\r\ncorrupt the PreviousMode of the current thread. By ensuring the corresponding source byte in the IOCTL input\r\nbuffer is zero, the copy will clear the PreviousMode field, effectively resulting in its value being interpreted as\r\nKernelMode . Targeting PreviousMode like this is a widely popular exploitation technique, as corrupting this one\r\nbyte in the KTHREAD structure bypasses kernel-mode checks inside syscalls such as NtReadVirtualMemory or\r\nNtWriteVirtualMemory , allowing a user-mode attacker to read and write arbitrary kernel memory. Note that\r\nwhile this technique was mitigated on some Windows Insider Builds, this mitigation has yet to reach general\r\navailability at the time of writing. \r\nInterestingly, the exploit may attempt to trigger the vulnerable IOCTL twice. This is due to an extra argument that\r\nwas added in Win11 22H2. As a result, the IOCTL handler on newer builds expects the input buffer to be 0x20\r\nbytes in size while, previously, the expected size was only 0x18 . Rather than selecting the proper input buffer\r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 7 of 22\n\nsize for the current build, the exploit just tries calling the IOCTL twice: first with an input buffer size 0x18 then\r\n– if not successful – with 0x20 . This is a valid approach since the IOCTL handler’s first action is to check the\r\ninput buffer size, and if it doesn’t match the expected size, it would just immediately return\r\nSTATUS_INVALID_PARAMETER .  \r\nTo check if it was successful, the exploit employs the NtWriteVirtualMemory syscall, attempting to read the\r\ncurrent thread’s PreviousMode (Lazarus avoids using NtReadVirtualMemory , more on this later). If the exploit\r\nsucceeded, the syscall should return STATUS_SUCCESS , and the leaked PreviousMode byte should equal 0\r\n(meaning KernelMode ). Otherwise, the syscall should return an error status code, as it should be impossible to\r\nread kernel memory without a corrupted PreviousMode .  \r\nIn our exploit analysis, we deliberately chose to omit some key details, such as the choice of the callback gadget\r\nfunction. This decision was made to strike the right balance between helping defenders with detection but not\r\nmaking exploitation too widely accessible. For those requiring more information for defensive purposes, we may\r\nbe able to share additional details on a case-by-case basis. \r\nThe FudModule Rootkit\r\nThe entire goal of the admin-to-kernel exploit was to corrupt the current thread’s PreviousMode . This allows for\r\na powerful kernel read/write primitive, where the affected user-mode thread can read and write arbitrary kernel\r\nmemory using the Nt(Read|Write)VirtualMemory syscalls. Armed with this primitive, the FudModule rootkit\r\nemploys direct kernel object manipulation (DKOM) techniques to disrupt various kernel security mechanisms. It’s\r\nworth reiterating that FudModule is a data-only rootkit, meaning it executes entirely from user space and all the\r\nkernel tampering is performed through the read/write primitive.  \r\nThe first variants of the FudModule rootkit were independently discovered by AhnLab and ESET research teams,\r\nwith both publishing detailed analyses in September 2022. The rootkit was named after the FudModule.dll string\r\nused as the name in its export table. While this artifact is not present anymore, there is no doubt that what we\r\nfound is an updated version of the same rootkit. AhnLab’s report documented a sample from early 2022, which\r\nincorporated seven data-only rootkit techniques and was enabled through a BYOVD exploit for ene.sys. ESET’s\r\nreport examined a slightly earlier variant from late 2021, also featuring seven rootkit techniques but exploiting a\r\ndifferent BYOVD vulnerability in dbutil_2_3.sys. In contrast, our discovery concerns a sample featuring nine\r\nrootkit techniques and exploiting a previously unknown admin-to-kernel vulnerability. Out of these nine\r\ntechniques, four are new, three are improved, and two remain unchanged from the previous variants. This leaves\r\ntwo of the original seven techniques, which have been deprecated and are no longer present in the latest variant. \r\nEach rootkit technique is assigned a bit, ranging from 0x1 to 0x200 (the 0x20 bit is left unused in the current\r\nvariant). FudModule executes the techniques sequentially, in an ascending order of the assigned bits. The bits are\r\nused to report on the success of the individual techniques. During execution, FudModule will construct an integer\r\nvalue (named bitfield_techniques in the decompilation below), where only the bits corresponding to\r\nsuccessfully executed techniques will be set. This integer is ultimately written to a file named tem1245.tmp ,\r\nreporting on the rootkit’s success. Interestingly, we did not find this filename referenced in any other Lazarus\r\nsample, suggesting the dropped file is only inspected through hands-on-keyboard activity, presumably through a\r\nRAT (Remote Access Trojan) command. This supports our beliefs that FudModule is only loosely integrated into\r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 8 of 22\n\nthe rest of Lazarus’ malware ecosystem and that Lazarus is very careful about using the rootkit, only deploying it\r\non demand under the right circumstances. \r\nThe rootkit’s “main” function, executing the individual rootkit techniques. Note the missing 0x20 technique.\r\nBased on the large number of updates, it seems that FudModule remains under active development. The latest\r\nvariant appears more robust, avoiding some potentially problematic practices from the earlier variants. Since some\r\ntechniques target undocumented kernel internals in a way that we have not previously encountered, we believe\r\nthat Lazarus must be conducting their own kernel research. Further, though the rootkit is certainly technically\r\nsophisticated, we still identified a few bugs here and there. These may either limit the rootkit’s intended\r\nfunctionality or even cause kernel bug checks under the right conditions. While we find some of these bugs very\r\ninteresting and would love to share the details, we do not enjoy the idea of providing free bug reports to threat\r\nactors, so we will hold onto them for now and potentially share some information later if the bugs get fixed. \r\nInterestingly, FudModule utilizes the NtWriteVirtualMemory syscall for both reading and writing kernel memory,\r\neliminating the need to call NtReadVirtualMemory . This leverages the property that, when limited to a single\r\nvirtual address space, NtReadVirtualMemory and NtWriteVirtualMemory are basically inverse operations with\r\nrespect to the values of the source Buffer and the destination BaseAddress arguments. In other words, writing\r\nto kernel memory can be thought of as writing from a user-mode Buffer to a kernel-mode BaseAddress , while\r\nreading from kernel memory could be conversely achieved by swapping arguments, that is writing from a kernel-mode Buffer to a user-mode BaseAddress . Lazarus’ implementation takes advantage of this, which seems to\r\nbe an intentional design decision since most developers would likely prefer the more straightforward way of using\r\nNtReadVirtualMemory for reading kernel memory and NtWriteVirtualMemory for writing kernel memory. We\r\ncan only guess why Lazarus chose this approach, but this might be yet another stealth-enhancing feature. With\r\ntheir implementation, they only must use one suspicious syscall instead of two, potentially reducing the number\r\ndetection opportunities. \r\nDebug Prints \r\nBefore we delve into the actual rootkit techniques, there is one last thing worth discussing. To our initial surprise,\r\nLazarus left a handful of plaintext debug prints in the compiled code. Such prints are typically one of the best\r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 9 of 22\n\nthings that can happen to a malware researcher, because they tend to accelerate the reverse engineering process\r\nsignificantly. In this instance, however, some of the prints had the opposite effect, sometimes even making us\r\nquestion if we understood the code correctly.  \r\nAs an example, let us mention the string get rop function addresses failed . Assuming rop stands for return-oriented programming, this string would make perfect sense in the context of exploitation, if not for the fact that\r\nnot a single return address was corrupted in the exploit.  \r\nPlaintext debug strings found in the rootkit. The term vaccine is used to refer to security software.\r\nWhile written in English, the debug strings suggest their authors are not native speakers, occasionally even\r\npointing to their supposed Korean origin. This is best seen on the frequent usage of the term vaccine throughout\r\nthe rootkit. This had us scratching our heads at first, because it was unclear how vaccines would relate to the\r\nrootkit functionality. However, it soon became apparent that the term was used to refer to security software. This\r\nmight originate from a common Korean translation of antivirus (바이러스 백신), a compound word with the\r\nliteral meaning virus vaccine. Note that even North Korea’s “own” antivirus was called SiliVaccine, and to the\r\nbest of our knowledge, the term vaccine would not be used like this in other languages such as Japanese.\r\nAdditionally, this is not the first time Korean-speaking threat actors have used this term. For instance, AhnLab’s\r\nrecent report on Kimsuky mentions the following telltale command: \r\n  cmd.exe /U /c wmic /namespace:\\\\root\\securitycenter2 path antivirusproduct get displayname \u003e\r\nvaccine.txt\r\nAnother puzzle is the abbreviation pvmode , which we believe refers to PreviousMode . A Google search for\r\npvmode yields exactly zero relevant results, and we suspect most English speakers would choose different\r\nabbreviations, such as prvmode or prevmode . However, after consulting this with language experts, we learned\r\nthat using the abbreviation pvmode would be unusual for Korean speakers too. \r\nFinally, there is also the debug message disableV3Protection passed . Judging from the context, the rather\r\ngeneric term V3 here refers to AhnLab V3 Endpoint Security. Considering the geopolitical situation, North Korean\r\nhacker groups are likely well-acquainted with South Korean AhnLab, so it would make perfect sense that they\r\ninternally refer to them using such a non-specific shorthand. \r\n0x01 – Registry Callbacks \r\nThe first rootkit technique is designed to address registry callbacks. This is a documented Windows mechanism\r\nwhich allows security solutions to monitor registry operations. A security solution’s kernel-mode component can\r\ncall the CmRegisterCallbackEx routine to register a callback, which gets notified whenever a registry operation is\r\nperformed on the system. What’s more, since the callback is invoked synchronously, before (or after) the actual\r\noperation is performed, the callback can even block or modify forbidden/malicious operations. FudModule’s goal\r\nhere is to remove existing registry callbacks and thus disrupt security solutions that rely on this mechanism. \r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 10 of 22\n\nThe callback removal itself is performed by directly modifying some internal data structures managed by the\r\nkernel. This was also the case in the previous version, as documented by ESET and AhnLab. There, the rootkit\r\nfound the address of nt!CallbackListHead (which contains a doubly linked, circular list of all existing registry\r\ncallbacks) and simply emptied it by pointing it to itself. \r\nIn the current version of FudModule, this technique was improved to leave some selected callbacks behind,\r\nperhaps making the rootkit stealthier. This updated version starts the same as the previous one: by finding the\r\naddress of nt!CallbackListHead . This is done by resolving CmUnRegisterCallback (this resolution is\r\nperformed by name, through iterating over the export table of ntoskrnl in memory), scanning its function body\r\nfor the lea rcx,[nt!CallbackListHead] instruction, and then calculating the final address from the offset\r\nextracted from the instruction’s opcodes. \r\nWith the nt!CallbackListHead address, FudModule can iterate over the registry callback linked list. It inspects\r\neach entry and determines if the callback routine is implemented in ntoskrnl.exe , applockerfltr.sys , or\r\nbfs.sys . If it is, the callback is left untouched. Otherwise, the rootkit replaces the callback routine pointer with a\r\npointer to ObIsKernelHandle and then proceeds to unlink the callback entry. \r\n0x02 – Object Callbacks \r\nObject callbacks allow drivers to execute custom code in response to thread, process, and desktop handle\r\noperations. They are often used in self-defense, as they represent a convenient way to protect critical processes\r\nfrom being tampered with. Since the protection is enforced at the kernel level, this should protect even against\r\nelevated attackers, as long as they stay in user mode. Alternatively, object callbacks are also useful for monitoring\r\nand detecting suspicious activity.  \r\nWhatever the use case, object callbacks can be set up using the ObRegisterCallbacks routine. FudModule\r\nnaturally attempts to do the exact opposite: that is to remove all registered object callbacks. This could let it\r\nbypass self-defense mechanisms and evade object callback-based detection/telemetry. \r\nThe implementation of this rootkit technique has stayed the same since the previous version, so there is no need to\r\ngo into too much detail. First, the rootkit scans the body of the ObGetObjectType routine to obtain the address of\r\nnt!ObTypeIndexTable . This contains an array of pointers to _OBJECT_TYPE structures, each of which represents\r\na distinct object type, such as Process , Token , or SymbolicLink . FudModule iterates over this array (skipping\r\nthe first two special-meaning elements) and inspects each _OBJECT_TYPE.CallbackList , which contains a doubly\r\nlinked list of object callbacks registered for the particular object type. The rootkit then empties the CallbackList\r\nby making each node’s forward and backward pointer point to itself. \r\n0x04 – Process, Thread, and Image Kernel Callbacks \r\nThis next rootkit technique is designed to disable three more types of kernel callbacks: process, thread, and image\r\ncallbacks. As their names suggest, these are used to execute custom kernel code whenever a new process is\r\ncreated, a new thread spawned, or a new image loaded (e.g. a DLL loaded into a process). These callbacks are\r\nextremely useful for detecting malicious activity. For instance, process callbacks allow AVs and EDRs to perform\r\nvarious checks on each new process that is to be created. Registering these callbacks is very straightforward. All\r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 11 of 22\n\nthat is needed is to pass the new callback routine as an argument to PsSetCreateProcessNotifyRoutine ,\r\nPsSetCreateThreadNotifyRoutine , or PsSetLoadImageNotifyRoutine . These routines also come in their\r\nupdated Ex variants, or even Ex2 in the case of PsSetCreateProcessNotifyRoutineEx2 . \r\nProcess, thread, and image callbacks are managed by the kernel in an almost identical way, which allows\r\nFudModule to use essentially the same code to disable all three of them. We find that this code has not changed\r\nmuch since the previous version, with the main difference being new additions to the list of drivers whose\r\ncallbacks are left untouched.  \r\nFudModule first finds the addresses of nt!PspNotifyEnableMask , nt!PspLoadImageNotifyRoutine ,\r\nnt!PspCreateThreadNotifyRoutine , and nt!PspCreateProcessNotifyRoutine . These are once again obtained\r\nby scanning the code of exported routines, with the exact scanning method subject to some variation based on the\r\nWindows build number. Before any modification is performed, the rootkit clears nt!PspNotifyEnableMask and\r\nsleeps for a brief amount of time. This mask contains a bit field of currently enabled callback types, so clearing it\r\ndisables all callbacks. While some EDR bypasses would stop here, FudModule’s goal is not to disable all\r\ncallbacks indiscriminately, so the modification of nt!PspNotifyEnableMask is only temporary, and FudModule\r\neventually restores it back to its original value. We believe the idea behind this temporary modification is to\r\ndecrease the chance of a race condition that could potentially result in a bug check. \r\nAll three of the above nt!Psp(LoadImage|CreateThread|CreateProcess)NotifyRoutine globals are organized as\r\nan array of _EX_FAST_REF pointers to _EX_CALLBACK_ROUTINE_BLOCK structures (at least that’s the name used in\r\nReactOS, Microsoft does not share a symbol name here). FudModule iterates over all these structures and checks\r\nif _EX_CALLBACK_ROUTINE_BLOCK.Function (the actual callback routine pointer) is implemented in one of the\r\nbelow-whitelisted modules. If it is, the pointer will get appended to a new array that will be used to replace the\r\noriginal one. This effectively removes all callbacks except for those implemented in one of the below-listed\r\nmodules. \r\nKernel modules that are allowed during the removal of process, thread, and image callbacks.\r\n0x08 – Minifilter Drivers \r\nFile system minifilters provide a mechanism for drivers to intercept file system operations. They are used in a\r\nwide range of scenarios, including encryption, compression, replication, monitoring, antivirus scanning, or file\r\nsystem virtualization. For instance, an encryption minifilter would encrypt the data before it is written to the\r\nstorage device and, conversely, decrypt the data after it is read. FudModule is trying to get rid of all the\r\nmonitoring and antivirus minifilters while leaving the rest untouched (after all, some minifilters are crucial to keep\r\nthe system running). The choice about which minifilters to keep and which to remove is based mainly on the\r\nminifilter’s altitude, an integer value that is used to decide the processing order in case there are multiple\r\nminifilters 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\r\ndistinguish anti-malware minifilters from the rest. \r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 12 of 22\n\nIn its previous version, FudModule disabled minifilters by directly patching their filter functions’ prologues. This\r\nwould be considered very unusual today, with HVCI (Hypervisor-Protected Code Integrity) becoming more\r\nprevalent, even turned on by default on Windows 11. Since HVCI is a security feature designed to prevent the\r\nexecution of arbitrary code in the kernel, it would stand in the way of FudModule trying to patch the filter\r\nfunction. This forced Lazarus to completely reimplement this rootkit technique, so the current version of\r\nFudModule disables file system minifilters in a brand-new data-only attack. \r\nThis attack starts by resolving FltEnumerateFilters and using it to find FltGlobals.FrameList.rList . This is\r\na linked list of FLTMGR!_FLTP_FRAME structures, each representing a single filter manager frame. From here,\r\nFudModule follows another linked list at _FLTP_FRAME.AttachedVolumes.rList . This linked list consists of\r\nFLTMGR!_FLT_VOLUME structures, describing minifilters attached to a particular file system volume. Interestingly,\r\nthe rootkit performs a sanity check to make sure that the pool tag associated with the _FLT_VOLUME allocation is\r\nequal to FMvo . With the sanity check satisfied, FudModule iterates over\r\n_FLT_VOLUME.Callbacks.OperationsLists , which is an array of linked lists of FLTMGR!_CALLBACK_NODE\r\nstructures, indexed by IRP major function codes. For instance, OperationsLists[IRP_MJ_READ] is a linked list\r\ndescribing all filters attached to the read operation on a particular volume. \r\nFudModule making sure the pool tag of a _FLT_VOLUME chunk is equal to FMvo.\r\nFor each _CALLBACK_NODE , FudModule obtains the corresponding FLTMGR!_FLT_INSTANCE and\r\nFLTMGR!_FLT_FILTER structures and uses them to decide whether to unlink the callback node. The first check is\r\nbased on the name of the driver behind the filter. If it is hmpalert.sys (associated with the HitmanPro anti-malware solution), the callback will get immediately unlinked. Conversely, the callback is preserved if the driver’s\r\nname matches an entry in the following list: \r\nKernel modules that are allowlisted to preserve their file system minifilters.\r\nIf there was no driver name match, FudModule uses _FLT_FILTER.DefaultAltitude to make its ultimate\r\ndecision. Callbacks are unlinked if the default altitude belongs either to the range [320000, 329999] (defined as\r\nFSFilter Anti-Virus by Microsoft) or the range [360000, 389999] ( FSFilter Activity Monitor ). Besides\r\nunlinking the callback nodes, FudModule also wipes the whole _FLT_INSTANCE.CallbackNodes array in the\r\ncorresponding _FLT_INSTANCE structures. \r\n0x10 – Windows Filtering Platform \r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 13 of 22\n\nWindows Filtering Platform (WFP) is a documented set of APIs designed for host-based network traffic filtering.\r\nThe WFP API offers capabilities for deep packet inspection as well as for modification or dropping of packets at\r\nvarious layers of the network stack. This is very useful functionality, so it serves as a foundation for a lot of\r\nWindows network security software, including intrusion detection/prevention systems, firewalls, and network\r\nmonitoring tools. The WFP API is accessible both in user and kernel space, with the kernel part offering more\r\npowerful functionality. Specifically, the kernel API allows for installing so-called callout drivers, which can\r\nessentially hook into the network stack and perform arbitrary actions on the processed network traffic. FudModule\r\nis trying to interfere with the installed callout routines in an attempt to disrupt the security they provide.  \r\nThis rootkit technique is executed only when Kaspersky drivers ( klam.sys , klif.sys , klwfp.sys ,\r\nklwtp.sys , klboot.sys ) are present on the targeted system and at the same time Symantec/Broadcom drivers\r\n( symevnt.sys , bhdrvx64.sys , srtsp64.sys ) are absent. This check appears to be a new addition in the current\r\nversion of FudModule. In other aspects, our analysis revealed that the core idea of this technique matches the\r\nfindings described by ESET researchers during their analysis of the previous version. \r\nInitially, FudModule resolves netio!WfpProcessFlowDelete to locate the address of netio!gWfpGlobal . As the\r\nname suggests, this is designed to store WFP-related global variables. Although its exact layout is undocumented,\r\nit is not hard to find the build-specific offset where a pointer to an array of WFP callout structures is stored (with\r\nthe length of this array stored at an offset immediately preceding the pointer). FudModule follows this pointer and\r\niterates over the array, skipping all callouts implemented in ndu.sys , tcpip.sys , mpsdrv.sys , or wtd.sys .\r\nFor the remaining callouts, FudModule accesses the callout structure’s flags and sets the flag stored in the least\r\nsignificant bit. While the callout structure itself is undocumented, this particular 0x01 flag is documented in\r\nanother structure, where it is called FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW . The documentation reads “if this\r\nflag is specified, the filter engine calls the callout driver’s classifyFn2 callout function only if there is a context\r\nassociated with the data flow”. In other words, setting this flag will conditionally disable the callout in cases\r\nwhere no flow context is available (see the implementation of netio!IsActiveCallout below). \r\nThe meaning of the FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW flag can be nicely seen in\r\nnetio!IsActiveCallout. If this flag is set and no flow context can be obtained, IsActiveCallout will return false (see\r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 14 of 22\n\nthe highlighted part of the condition).\r\nWhile this rootkit technique has the potential to interfere with some WFP callouts, it will not be powerful enough\r\nto disrupt all of them. Many WFP callouts registered by security vendors already have the\r\nFWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW flag set by design, so they will not be affected by this technique at all.\r\nGiven the initial driver check, it seems like this technique might be targeted directly at Kaspersky. While\r\nKaspersky does install dozens of WFP callouts, about half of those are designed for processing flows and already\r\nhave the FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW flag set. Since we refrained from reverse engineering our\r\ncompetitor’s products, the actual impact of this rootkit technique remains unclear. \r\n0x20 – Missing \r\nSo far, the rootkit techniques we analyzed were similar to those detailed by ESET in their paper on the earlier\r\nrootkit variant. But starting from now, we are getting into a whole new territory. The 0x20 technique, which used\r\nto deal with Event Tracing for Windows (ETW), has been deprecated, leaving the 0x20 bit unused. Instead, there\r\nare two new replacement techniques that target ETW, indexed with the bits 0x40 and 0x80 . The indexing used\r\nto end at 0x40 , which was a technique to obstruct forensic analysis by disabling prefetch file creation. However,\r\nnow the bits go all the way up to 0x200 , with two additional new techniques that we will delve into later in this\r\nblog. \r\n0x40 – Event Tracing for Windows: System Loggers\r\nEvent Tracing for Windows (ETW) serves as a high-performance mechanism dedicated to tracing and logging\r\nevents. In a nutshell, its main purpose is to connect providers (who generate some log events) with consumers\r\n(who process the generated events). Consumers can define which events they would like to consume, for instance,\r\nby selecting some specific providers of interest. There are providers built into the operating system, like\r\nMicrosoft-Windows-Kernel-Process which generates process-related events, such as process creation or\r\ntermination. However, third-party applications can also define their custom providers.  \r\nWhile many built-in providers are not security-related, some generate events useful for detection purposes. For\r\ninstance, the Microsoft-Windows-Threat-Intelligence provider makes it possible to watch for suspicious\r\nevents, such as writing another process’ memory. Furthermore, various security products take advantage of ETW\r\nby defining their custom providers and consumers. FudModule tampers with ETW internals in an attempt to\r\nintercept suspicious events and thus evade detection. \r\nThe main idea behind this rootkit technique is to disable system loggers by zeroing out\r\nEtwpActiveSystemLoggers . The specific implementation of how this address is found varies based on the target\r\nWindows version. On newer builds, the nt!EtwSendTraceBuffer routine is resolved first and used to find\r\nnt!EtwpHostSiloState . This points to an _ETW_SILODRIVERSTATE structure, and using a hardcoded build-specific offset, the rootkit can access _ETW_SILODRIVERSTATE.SystemLoggerSettings.EtwpActiveSystemLoggers .\r\nOn older builds, the rootkit first scans the entire ntoskrnl .text section, searching for opcode bytes specific to\r\nthe EtwTraceKernelEvent prologue. The rootkit then extracts the target address from the mov ebx,\r\ncs:EtwpActiveSystemLoggers instruction that immediately follows. \r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 15 of 22\n\nTo understand the technique’s impact, we can take a look at how EtwpActiveSystemLoggers is used in the kernel.\r\nAccessed on a bit-by-bit basis, its least significant eight bits might be set in the EtwpStartLogger routine. This\r\nindicates that the value itself is a bit field, with each bit signifying whether a particular system logger is active.\r\nLooking at the other references to EtwpActiveSystemLoggers , a clear pattern emerges. After its value is read,\r\nthere tends to be a loop guarded by a bsf instruction (bit scan forward). Inside the loop tends to be a call to an\r\nETW-related routine that might generate a log event. The purpose of this loop is to iterate over the set bits of\r\nEtwpActiveSystemLoggers . When the rootkit clears all the bits, the body of the loop will never get executed,\r\nmeaning the event will not get logged. \r\nExample decompilation of EtwpTraceKernelEventWithFilter. After the rootkit zeroes out\r\nEtwpActiveSystemLoggers, EtwpLogKernelEvent will never get called from inside the loop since the condition\r\nguarding the loop will always evaluate to zero.\r\n0x80 – Event Tracing for Windows: Provider GUIDs \r\nComplementing the previous technique, the 0x80 technique is also designed to blind ETW, however using a\r\ndifferent approach. While the 0x40 technique was quite generic – aiming to disable all system loggers – this\r\ntechnique operates in a more surgical fashion. It contains a hardcoded list of 95 GUIDs, each representing an\r\nidentifier for some specific ETW provider. The rootkit iterates over all these GUIDs and attempts to disable the\r\nrespective providers. While this approach requires the attackers to invest some effort into assembling the list of\r\nGUIDs, it also offers them a finer degree of control over which ETW providers they will eventually disrupt. This\r\nallows them to selectively target providers that pose a higher detection risk and ignore the rest to minimize the\r\nrootkit’s impact on the target system. \r\nThis technique starts by obtaining the address of EtwpHostSiloState (or EtwSiloState on older builds). If\r\nEtwpHostSiloState was already resolved during the previous technique, the rootkit just reuses the address. If\r\nnot, the rootkit follows the reference chain PsGetCurrentServerSiloName -\u003e PsGetCurrentServerSiloGlobals -\r\n\u003e PspHostSiloGlobals -\u003e EtwSiloState . In both scenarios, the result is that the rootkit just obtained a pointer\r\nto an _ETW_SILODRIVERSTATE structure, which contains a member named EtwpGuidHashTable . As the name\r\nsuggests, this is a hash table holding ETW GUIDs ( _ETW_GUID_ENTRY ).  \r\nFudModule then iterates over its hardcoded list of GUIDs and attempts to locate each of them in the hash table.\r\nAlthough the hash table internals are officially undocumented, Yarden Shafir provided a nice description in her\r\nblog on exploiting an ETW vulnerability. In a nutshell, the hash is computed by just splitting the 128-bit GUID\r\ninto four 32-bit parts and XORing them together. By ANDing the hash with 0x3F , an index of the relevant hash\r\nbucket ( _ETW_HASH_BUCKET ) can be obtained. The bucket contains three linked lists of _ETW_GUID_ENTRY\r\nstructures, each designated for a different type of GUIDs. FudModule always opts for the first one\r\n( EtwTraceGuidType ) and traverses it, looking for the relevant _ETW_GUID_ENTRY structure. \r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 16 of 22\n\nWith a pointer to _ETW_GUID_ENTRY corresponding to a GUID of interest, FudModule proceeds to clear\r\n_ETW_GUID_ENTRY.ProviderEnableInfo.IsEnabled . The purpose of this modification seems self-explanatory:\r\nFudModule is trying to disable the ETW provider. To better understand how this works, let’s examine\r\nnt!EtwEventEnabled (see the decompiled code below). This is a routine that often serves as an if condition\r\nbefore nt!EtwWrite (or nt!EtwWriteEx ) gets called.  \r\nLooking at the decompilation, there are two return 1 statements. Setting ProviderEnableInfo.IsEnabled to\r\nzero ensures that the first one is never reached. However, the second return statement could still potentially\r\nexecute. To make sure this doesn’t happen, the rootkit also iterates over all _ETW_REG_ENTRY structures from the\r\n_ETW_GUID_ENTRY.RegListHead linked list. For each of them, it makes a single doubleword write to zero out four\r\nmasks, namely EnableMask , GroupEnableMask , HostEnableMask , and HostGroupEnableMask (or only\r\nEnableMask and GroupEnableMask on older builds, where the latter two masks were not yet introduced).  \r\nDecompilation of nt!EtwEventEnabled. After the rootkit has finished its job, this routine will always return false\r\nfor events related to the targeted GUIDs. This is because the rootkit cleared both\r\n_ETW_GUID_ENTRY.ProviderEnableInfo.IsEnabled and _ETW_REG\r\nClearing these masks also has an additional effect beyond making EtwEventEnabled always return false .\r\nThese four are all also checked in EtwWriteEx and this modification effectively neutralizes this routine, as when\r\nno mask is set for a particular event registration object, execution will never proceed to a lower-level routine\r\n( nt!EtwpEventWriteFull ) where the bulk of the actual event writing logic is implemented. \r\n0x100 – Image Verification Callbacks \r\nImage verification callbacks are yet another callback mechanism disrupted by FudModule. Designed similarly to\r\nprocess/thread/image callbacks, image verification callbacks are supposed to get invoked whenever a new driver\r\nimage is loaded into kernel memory. This represents useful functionality for anti-malware software, which can\r\nleverage them to blocklist known malicious or vulnerable drivers (though there might be some problems with this\r\nblocking approach as the callbacks get invoked asynchronously). Furthermore, image verification callbacks also\r\noffer a valuable source of telemetry, providing visibility into suspicious driver load events. The callbacks can be\r\nregistered using the SeRegisterImageVerificationCallback routine, which is publicly undocumented. As a\r\nresult of this undocumented nature, the usage here is limited mainly to deep-rooted anti-malware software. For\r\ninstance, Windows Defender registers a callback named WdFilter!MpImageVerificationCallback . \r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 17 of 22\n\nAs the kernel internally manages image verification callbacks in a similar fashion to some of the other callbacks\r\nwe already explored, the rootkit’s removal implementation will undoubtedly seem familiar. First, the rootkit\r\nresolves the nt!SeRegisterImageVerificationCallback routine and scans its body to locate\r\nnt!ExCbSeImageVerificationDriverInfo . Dereferencing this, it obtains a pointer to a _CALLBACK_OBJECT\r\nstructure, which holds the callbacks in the _CALLBACK_OBJECT.RegisteredCallbacks linked list. This list consists\r\nof _CALLBACK_REGISTRATION structures, where the actual callback function pointer can be found in\r\n_CALLBACK_REGISTRATION.CallbackFunction . FudModule clears the entire list by making the\r\nRegisteredCallbacks head LIST_ENTRY point directly to itself. Additionally, it also walks the original linked\r\nlist and similarly short-circuits each individual _CALLBACK_REGISTRATION entry in the list. \r\nThis rootkit technique is newly implemented in the current version of FudModule, and we can only speculate on\r\nthe motivation here. It seems to be designed to help avoid detection when loading either a vulnerable or a\r\nmalicious driver. However, it might be hard to understand why Lazarus should want to load an additional driver if\r\nthey already have control over the kernel. It would make little sense for them to load a vulnerable driver, as they\r\nalready established their kernel read/write primitive by exploiting a zero-day in a preinstalled Windows driver.\r\nFurther, even if they were exploiting a vulnerable driver in the first place (as was the case in the previous version\r\nof FudModule), it would be simply too late to unlink the callback now. By the time this rootkit technique executes,\r\nthe image verification callback for the vulnerable driver would have already been invoked. Therefore, we believe\r\nthe most likely explanation is that the threat actors are preparing the grounds for loading some malicious driver\r\nlater. Perhaps the idea is that they just want to be covered in case they decide to deploy some additional kernel-mode payload in the future. \r\n0x200 – Direct Attacks on Security Software \r\nThe rootkit techniques we explored up to this point were all somewhat generic. Each targeted some security-related system component and, through it, indirectly interfered with all security software that relied on the\r\ncomponent. In contrast, this final technique goes straight to the point and aims to directly disable specific security\r\nsoftware. In particular, the targeted security solutions are AhnLab V3 Endpoint Security, Windows Defender,\r\nCrowdStrike Falcon, and HitmanPro. \r\nThe attack starts with the rootkit obtaining the address of its own _EPROCESS structure. This is done using\r\nNtDuplicateHandle to duplicate the current process pseudohandle and then calling NtQuerySystemInformation\r\nto get SystemExtendedHandleInformation . With the extended handle information, the rootkit looks for an entry\r\ncorresponding to the duplicated handle and obtains the _EPROCESS pointer from there. Using\r\nNtQuerySystemInformation to leak kernel pointers is a well-known technique that Microsoft aims to restrict by\r\ngradually building up mitigations. However, attackers capable of enabling SeDebugPrivilege at high integrity\r\nlevels are out of scope of these mitigations, so FudModule can keep using this technique, even on the upcoming\r\n24H2 builds. With the _EPROCESS pointer, FudModule disables mitigations by zeroing out\r\n_EPROCESS.MitigationFlags . Then, it also clears the EnableHandleExceptions flag from\r\n_EPROCESS.ObjectTable.Flags . We believe this is meant to increase stability in case something goes wrong later\r\nduring the handle table entry manipulation technique that we will describe shortly.  \r\nRegarding the specific technique used to attack the security solutions, AhnLab is handled differently than the other\r\nthree targets. FudModule first checks if AhnLab is even running, by traversing the ActiveProcessLinks linked\r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 18 of 22\n\nlist and looking for a process named asdsvc.exe (AhnLab Smart Defense Service) with\r\n_EPROCESS.Token.AuthenticationId set to SYSTEM_LUID . If such a process is found, FudModule clears its\r\n_EPROCESS.Protection byte, effectively toggling off PPL protection for the process. While this asdsvc.exe\r\nprocess is under usual circumstances meant to be protected at the standard PsProtectedSignerAntimalware level,\r\nthis modification makes it just a regular non-protected process. This opens it up to further attacks from user mode,\r\nwhere now even other privileged, yet non-protected processes could be able to tamper with it. However, we\r\nsuspect the main idea behind this technique might be to disrupt the link between AhnLab’s user-mode and kernel-mode components. By removing the service’s PPL protection, the kernel-mode component might no longer\r\nrecognize it as a legitimate AhnLab component. However, this is just a speculation as we didn’t test the real\r\nimpact of this technique. \r\nHandle Table Entry Manipulation \r\nThe technique employed to attack Defender, CrowdStrike, and HitmanPro is much more intriguing: FudModule\r\nattempts to suspend them using a new handle table entry manipulation technique. To better understand this\r\ntechnique, let’s begin with a brief background on handle tables. When user-mode code interacts with kernel\r\nobjects such as processes, files, or mutexes, it typically doesn’t work with the objects directly. Instead, it\r\nreferences them indirectly through handles. Internally, the kernel must be able to translate the handle to the\r\ncorresponding object, and this is where the handle table comes in. This per-process table, available at\r\n_EPROCESS.ObjectTable.TableCode , serves as a mapping from handles to the underlying objects. Organized as an\r\narray, it is indexed by the integer value of the handle. Each element is of type _HANDLE_TABLE_ENTRY and contains\r\ntwo crucial pieces of information: a (compressed) pointer to the object’s header ( nt!_OBJECT_HEADER ) and access\r\nbits associated with the handle. \r\nDue to this handle design, kernel object access checks are typically split into two separate logical steps. The first\r\nstep happens when a process attempts to acquire a handle (such as opening a file with CreateFile ). During this\r\nstep, the current thread’s token is typically checked against the target object’s security descriptor to ensure that the\r\nthread is allowed to obtain a handle with the desired access mask. The second check takes place when a process\r\nperforms an operation using an already acquired handle (such as writing to a file with WriteFile ). This typically\r\nonly involves verifying that the handle is powerful enough (meaning it has the right access bits) for the requested\r\noperation.  \r\nFudModule executes as a non-protected process, so it theoretically shouldn’t be able to obtain a powerful handle\r\nto a PPL-protected process such as the CrowdStrike Falcon Service. However, leveraging the kernel read/write\r\nprimitive, FudModule has the ability to access the handle table directly. This allows it to craft a custom handle\r\ntable entry with control over both the referenced object and the access bits. This way, it can conjure an arbitrary\r\nhandle to any object, completely bypassing the check typically needed for handle acquisition. What’s more, if it\r\nsets the handle’s access bits appropriately, it will also satisfy the subsequent handle checks when performing its\r\ndesired operations. \r\nTo prepare for the handle table entry manipulation technique, FudModule creates a dummy thread that just puts\r\nitself to sleep immediately. The thread itself is not important. What is important is that by calling CreateThread ,\r\nthe rootkit just obtained a thread handle with THREAD_ALL_ACCESS rights. This handle is the one that will have its\r\nhandle table entry manipulated. Since it already has very powerful access bits, the rootkit will not even have to\r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 19 of 22\n\ntouch its _HANDLE_TABLE_ENTRY.GrantedAccessBits . All it needs to do is overwrite\r\n_HANDLE_TABLE_ENTRY.ObjectPointerBits to redirect the handle to an arbitrary object of its choice. This will\r\nmake the handle reference that object and enable the rootkit to perform privileged operations on it. Note that\r\nObjectPointerBits is not the whole pointer to the object: it only represents 44 bits of the 64-bit pointer. But\r\nsince the _OBJECT_HEADER pointed to by ObjectPointerBits is guaranteed to be aligned (meaning the least\r\nsignificant four bits must be zero) and in kernel address space (meaning the most significant sixteen bits must be\r\n0xFFFF ), the remaining 20 bits can be easily inferred. \r\nA dummy thread whose handle will be the subject of handle table entry manipulation.\r\nThe specific processes targeted by this technique are MsSense.exe , MsMpEng.exe , CSFalconService.exe , and\r\nhmpalert.exe . FudModule first finds their respective _EPROCESS structures, employing the same algorithm as it\r\ndid to find the AhnLab service. Then, it performs a sanity check to ensure that the dummy thread handle is not too\r\nhigh by comparing it with _EPROCESS.ObjectTable.NextHandleNeedingPool (which holds information on the\r\nmaximum possible handle value given the current handle table allocation size). With the sanity check satisfied,\r\nFudModule accesses the handle table itself ( EPROCESS.ObjectTable.TableCode ) and modifies the dummy\r\nthread’s _HANDLE_TABLE_ENTRY so that it points to the _OBJECT_HEADER of the target _EPROCESS . Finally, the\r\nrootkit uses the redirected handle to call NtSuspendProcess , which will suspend the targeted process.  \r\nIt might seem odd that the manipulated handle used to be a thread handle, but now it’s being used as a process\r\nhandle. In practice, there is nothing wrong with this since the handle table itself holds no object type information.\r\nThe object type is stored in _OBJECT_HEADER.TypeIndex so when the rootkit redirected the handle, it also\r\neffectively changed the handle object type. As for the access bits, the original THREAD_ALL_ACCESS gets\r\nreinterpreted in the new context as PROCESS_ALL_ACCESS since both constants share the same underlying value. \r\nThe manipulated dummy thread handle (0x168), now referencing a process object.\r\nThough suspending the target process might initially appear to be a completed job, FudModule doesn’t stop here.\r\nAfter taking five seconds of sleep, it also attempts to iterate over all the threads in the target process, suspending\r\nthem one by one. When all threads are suspended, FudModule uses NtResumeProcess to resume the suspended\r\nprocess. At this point, while the process itself is technically resumed, its individual threads remain suspended,\r\nmeaning the process is still effectively in a suspended state. We can only speculate why Lazarus implemented\r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 20 of 22\n\nprocess suspension this way, but it seems like an attempt to make the technique stealthier. After all, a suspended\r\nprocess is much more conspicuous than just several threads with increased suspend counts. \r\nTo enumerate threads, FudModule calls NtQuerySystemInformation with the\r\nSystemExtendedHandleInformation class. Iterating over the returned handle information, FudModule searches\r\nfor thread handles from the target process. The owner process is checked by comparing the PID of the target\r\nprocess with SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX.UniqueProcessId and the type is checked by comparing\r\nSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX.ObjectTypeIndex with the thread type index, which was previously\r\nobtained using NtQueryObject to get ObjectTypesInformation . For each enumerated thread (which might\r\ninclude some threads multiple times, as there might be more than one open handle to the same thread),\r\nFudModule manipulates the dummy thread handle so that it points to the enumerated thread and suspends it by\r\ncalling SuspendThread on the manipulated handle. Finally, after all threads are suspended and the process\r\nresumed, FudModule restores the manipulated handle to its original state, once again referencing the dummy sleep\r\nthread. \r\nConclusion \r\nThe Lazarus Group remains among the most prolific and long-standing advanced persistent threat actors. Though\r\ntheir signature tactics and techniques are well-recognized by now, they still occasionally manage to surprise us\r\nwith an unexpected level of technical sophistication. The FudModule rootkit serves as the latest example,\r\nrepresenting one of the most complex tools Lazarus holds in their arsenal. Recent updates examined in this blog\r\nshow Lazarus’ commitment to keep actively developing this rootkit, focusing on improvements in both stealth and\r\nfunctionality. \r\nWith their admin-to-kernel zero-day now burned, Lazarus is confronted with a significant challenge. They can\r\neither discover a new zero-day exploit or revert to their old BYOVD techniques. Regardless of their choice, we\r\nwill continue closely monitoring their activity, eager to see how they will cope with these new circumstances. \r\nIndicators of Compromise (IoCs) \r\nA YARA rule for the latest FudModule variant is available at\r\nhttps://github.com/avast/ioc/tree/master/FudModule#yara.\r\nJan Vojtěšek\r\nAuthor at Avast Threat Labs\r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 21 of 22\n\nSource: https://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nhttps://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/\r\nPage 22 of 22",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia",
		"ETDA"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/"
	],
	"report_names": [
		"lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day"
	],
	"threat_actors": [
		{
			"id": "34eea331-d052-4096-ae03-a22f1d090bd4",
			"created_at": "2025-08-07T02:03:25.073494Z",
			"updated_at": "2026-04-10T02:00:03.709243Z",
			"deleted_at": null,
			"main_name": "NICKEL ACADEMY",
			"aliases": [
				"ATK3 ",
				"Black Artemis ",
				"COVELLITE ",
				"CTG-2460 ",
				"Citrine Sleet ",
				"Diamond Sleet ",
				"Guardians of Peace",
				"HIDDEN COBRA ",
				"High Anonymous",
				"Labyrinth Chollima ",
				"Lazarus Group ",
				"NNPT Group",
				"New Romanic Cyber Army Team",
				"Temp.Hermit ",
				"UNC577 ",
				"Who Am I?",
				"Whois Team",
				"ZINC "
			],
			"source_name": "Secureworks:NICKEL ACADEMY",
			"tools": [
				"Destover",
				"KorHigh",
				"Volgmer"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "191d7f9a-8c3c-442a-9f13-debe259d4cc2",
			"created_at": "2022-10-25T15:50:23.280374Z",
			"updated_at": "2026-04-10T02:00:05.305572Z",
			"deleted_at": null,
			"main_name": "Kimsuky",
			"aliases": [
				"Kimsuky",
				"Black Banshee",
				"Velvet Chollima",
				"Emerald Sleet",
				"THALLIUM",
				"APT43",
				"TA427",
				"Springtail"
			],
			"source_name": "MITRE:Kimsuky",
			"tools": [
				"Troll Stealer",
				"schtasks",
				"Amadey",
				"GoBear",
				"Brave Prince",
				"CSPY Downloader",
				"gh0st RAT",
				"AppleSeed",
				"Gomir",
				"NOKKI",
				"QuasarRAT",
				"Gold Dragon",
				"PsExec",
				"KGH_SPY",
				"Mimikatz",
				"BabyShark",
				"TRANSLATEXT"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "760f2827-1718-4eed-8234-4027c1346145",
			"created_at": "2023-01-06T13:46:38.670947Z",
			"updated_at": "2026-04-10T02:00:03.062424Z",
			"deleted_at": null,
			"main_name": "Kimsuky",
			"aliases": [
				"G0086",
				"Emerald Sleet",
				"THALLIUM",
				"Springtail",
				"Sparkling Pisces",
				"Thallium",
				"Operation Stolen Pencil",
				"APT43",
				"Velvet Chollima",
				"Black Banshee"
			],
			"source_name": "MISPGALAXY:Kimsuky",
			"tools": [
				"xrat",
				"QUASARRAT",
				"RDP Wrapper",
				"TightVNC",
				"BabyShark",
				"RevClient"
			],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "732597b1-40a8-474c-88cc-eb8a421c29f1",
			"created_at": "2025-08-07T02:03:25.087732Z",
			"updated_at": "2026-04-10T02:00:03.776007Z",
			"deleted_at": null,
			"main_name": "NICKEL GLADSTONE",
			"aliases": [
				"APT38 ",
				"ATK 117 ",
				"Alluring Pisces ",
				"Black Alicanto ",
				"Bluenoroff ",
				"CTG-6459 ",
				"Citrine Sleet ",
				"HIDDEN COBRA ",
				"Lazarus Group",
				"Sapphire Sleet ",
				"Selective Pisces ",
				"Stardust Chollima ",
				"T-APT-15 ",
				"TA444 ",
				"TAG-71 "
			],
			"source_name": "Secureworks:NICKEL GLADSTONE",
			"tools": [
				"AlphaNC",
				"Bankshot",
				"CCGC_Proxy",
				"Ratankba",
				"RustBucket",
				"SUGARLOADER",
				"SwiftLoader",
				"Wcry"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "c8bf82a7-6887-4d46-ad70-4498b67d4c1d",
			"created_at": "2025-08-07T02:03:25.101147Z",
			"updated_at": "2026-04-10T02:00:03.846812Z",
			"deleted_at": null,
			"main_name": "NICKEL KIMBALL",
			"aliases": [
				"APT43 ",
				"ARCHIPELAGO ",
				"Black Banshee ",
				"Crooked Pisces ",
				"Emerald Sleet ",
				"ITG16 ",
				"Kimsuky ",
				"Larva-24005 ",
				"Opal Sleet ",
				"Ruby Sleet ",
				"SharpTongue ",
				"Sparking Pisces ",
				"Springtail ",
				"TA406 ",
				"TA427 ",
				"THALLIUM ",
				"UAT-5394 ",
				"Velvet Chollima "
			],
			"source_name": "Secureworks:NICKEL KIMBALL",
			"tools": [
				"BabyShark",
				"FastFire",
				"FastSpy",
				"FireViewer",
				"Konni"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "38f8da87-b4ba-474b-83e6-5b04d8fb384b",
			"created_at": "2024-02-02T02:00:04.032871Z",
			"updated_at": "2026-04-10T02:00:03.532955Z",
			"deleted_at": null,
			"main_name": "Caramel Tsunami",
			"aliases": [
				"SOURGUM",
				"Candiru"
			],
			"source_name": "MISPGALAXY:Caramel Tsunami",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "a2b92056-9378-4749-926b-7e10c4500dac",
			"created_at": "2023-01-06T13:46:38.430595Z",
			"updated_at": "2026-04-10T02:00:02.971571Z",
			"deleted_at": null,
			"main_name": "Lazarus Group",
			"aliases": [
				"Operation DarkSeoul",
				"Bureau 121",
				"Group 77",
				"APT38",
				"NICKEL GLADSTONE",
				"G0082",
				"COPERNICIUM",
				"Moonstone Sleet",
				"Operation GhostSecret",
				"APT 38",
				"Appleworm",
				"Unit 121",
				"ATK3",
				"G0032",
				"ATK117",
				"NewRomanic Cyber Army Team",
				"Nickel Academy",
				"Sapphire Sleet",
				"Lazarus group",
				"Hastati Group",
				"Subgroup: Bluenoroff",
				"Operation Troy",
				"Black Artemis",
				"Dark Seoul",
				"Andariel",
				"Labyrinth Chollima",
				"Operation AppleJeus",
				"COVELLITE",
				"Citrine Sleet",
				"DEV-0139",
				"DEV-1222",
				"Hidden Cobra",
				"Bluenoroff",
				"Stardust Chollima",
				"Whois Hacking Team",
				"Diamond Sleet",
				"TA404",
				"BeagleBoyz",
				"APT-C-26"
			],
			"source_name": "MISPGALAXY:Lazarus Group",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "32a223a8-3c79-4146-87c5-8557d38662ae",
			"created_at": "2022-10-25T15:50:23.703698Z",
			"updated_at": "2026-04-10T02:00:05.261989Z",
			"deleted_at": null,
			"main_name": "Lazarus Group",
			"aliases": [
				"Lazarus Group",
				"Labyrinth Chollima",
				"HIDDEN COBRA",
				"Guardians of Peace",
				"NICKEL ACADEMY",
				"Diamond Sleet"
			],
			"source_name": "MITRE:Lazarus Group",
			"tools": [
				"RawDisk",
				"Proxysvc",
				"BADCALL",
				"FALLCHILL",
				"WannaCry",
				"MagicRAT",
				"HOPLIGHT",
				"TYPEFRAME",
				"Dtrack",
				"HotCroissant",
				"HARDRAIN",
				"Dacls",
				"KEYMARBLE",
				"TAINTEDSCRIBE",
				"AuditCred",
				"netsh",
				"ECCENTRICBANDWAGON",
				"AppleJeus",
				"BLINDINGCAN",
				"ThreatNeedle",
				"Volgmer",
				"Cryptoistic",
				"RATANKBA",
				"Bankshot"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "71a1e16c-3ba6-4193-be62-be53527817bc",
			"created_at": "2022-10-25T16:07:23.753455Z",
			"updated_at": "2026-04-10T02:00:04.73769Z",
			"deleted_at": null,
			"main_name": "Kimsuky",
			"aliases": [
				"APT 43",
				"Black Banshee",
				"Emerald Sleet",
				"G0086",
				"G0094",
				"ITG16",
				"KTA082",
				"Kimsuky",
				"Larva-24005",
				"Larva-25004",
				"Operation Baby Coin",
				"Operation Covert Stalker",
				"Operation DEEP#DRIVE",
				"Operation DEEP#GOSU",
				"Operation Kabar Cobra",
				"Operation Mystery Baby",
				"Operation Red Salt",
				"Operation Smoke Screen",
				"Operation Stealth Power",
				"Operation Stolen Pencil",
				"SharpTongue",
				"Sparkling Pisces",
				"Springtail",
				"TA406",
				"TA427",
				"Thallium",
				"UAT-5394",
				"Velvet Chollima"
			],
			"source_name": "ETDA:Kimsuky",
			"tools": [
				"AngryRebel",
				"AppleSeed",
				"BITTERSWEET",
				"BabyShark",
				"BoBoStealer",
				"CSPY Downloader",
				"Farfli",
				"FlowerPower",
				"Gh0st RAT",
				"Ghost RAT",
				"Gold Dragon",
				"GoldDragon",
				"GoldStamp",
				"JamBog",
				"KGH Spyware Suite",
				"KGH_SPY",
				"KPortScan",
				"KimJongRAT",
				"Kimsuky",
				"LATEOP",
				"LOLBAS",
				"LOLBins",
				"Living off the Land",
				"Lovexxx",
				"MailPassView",
				"Mechanical",
				"Mimikatz",
				"MoonPeak",
				"Moudour",
				"MyDogs",
				"Mydoor",
				"Network Password Recovery",
				"PCRat",
				"ProcDump",
				"PsExec",
				"ReconShark",
				"Remote Desktop PassView",
				"SHARPEXT",
				"SWEETDROP",
				"SmallTiger",
				"SniffPass",
				"TODDLERSHARK",
				"TRANSLATEXT",
				"Troll Stealer",
				"TrollAgent",
				"VENOMBITE",
				"WebBrowserPassView",
				"xRAT"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "f32df445-9fb4-4234-99e0-3561f6498e4e",
			"created_at": "2022-10-25T16:07:23.756373Z",
			"updated_at": "2026-04-10T02:00:04.739611Z",
			"deleted_at": null,
			"main_name": "Lazarus Group",
			"aliases": [
				"APT-C-26",
				"ATK 3",
				"Appleworm",
				"Citrine Sleet",
				"DEV-0139",
				"Diamond Sleet",
				"G0032",
				"Gleaming Pisces",
				"Gods Apostles",
				"Gods Disciples",
				"Group 77",
				"Guardians of Peace",
				"Hastati Group",
				"Hidden Cobra",
				"ITG03",
				"Jade Sleet",
				"Labyrinth Chollima",
				"Lazarus Group",
				"NewRomanic Cyber Army Team",
				"Operation 99",
				"Operation AppleJeus",
				"Operation AppleJeus sequel",
				"Operation Blockbuster: Breach of Sony Pictures Entertainment",
				"Operation CryptoCore",
				"Operation Dream Job",
				"Operation Dream Magic",
				"Operation Flame",
				"Operation GhostSecret",
				"Operation In(ter)caption",
				"Operation LolZarus",
				"Operation Marstech Mayhem",
				"Operation No Pineapple!",
				"Operation North Star",
				"Operation Phantom Circuit",
				"Operation Sharpshooter",
				"Operation SyncHole",
				"Operation Ten Days of Rain / DarkSeoul",
				"Operation Troy",
				"SectorA01",
				"Slow Pisces",
				"TA404",
				"TraderTraitor",
				"UNC2970",
				"UNC4034",
				"UNC4736",
				"UNC4899",
				"UNC577",
				"Whois Hacking Team"
			],
			"source_name": "ETDA:Lazarus Group",
			"tools": [
				"3CX Backdoor",
				"3Rat Client",
				"3proxy",
				"AIRDRY",
				"ARTFULPIE",
				"ATMDtrack",
				"AlphaNC",
				"Alreay",
				"Andaratm",
				"AngryRebel",
				"AppleJeus",
				"Aryan",
				"AuditCred",
				"BADCALL",
				"BISTROMATH",
				"BLINDINGCAN",
				"BTC Changer",
				"BUFFETLINE",
				"BanSwift",
				"Bankshot",
				"Bitrep",
				"Bitsran",
				"BlindToad",
				"Bookcode",
				"BootWreck",
				"BottomLoader",
				"Brambul",
				"BravoNC",
				"Breut",
				"COLDCAT",
				"COPPERHEDGE",
				"CROWDEDFLOUNDER",
				"Castov",
				"CheeseTray",
				"CleanToad",
				"ClientTraficForwarder",
				"CollectionRAT",
				"Concealment Troy",
				"Contopee",
				"CookieTime",
				"Cyruslish",
				"DAVESHELL",
				"DBLL Dropper",
				"DLRAT",
				"DRATzarus",
				"DRATzarus RAT",
				"Dacls",
				"Dacls RAT",
				"DarkComet",
				"DarkKomet",
				"DeltaCharlie",
				"DeltaNC",
				"Dembr",
				"Destover",
				"DoublePulsar",
				"Dozer",
				"Dtrack",
				"Duuzer",
				"DyePack",
				"ECCENTRICBANDWAGON",
				"ELECTRICFISH",
				"Escad",
				"EternalBlue",
				"FALLCHILL",
				"FYNLOS",
				"FallChill RAT",
				"Farfli",
				"Fimlis",
				"FoggyBrass",
				"FudModule",
				"Fynloski",
				"Gh0st RAT",
				"Ghost RAT",
				"Gopuram",
				"HARDRAIN",
				"HIDDEN COBRA RAT/Worm",
				"HLOADER",
				"HOOKSHOT",
				"HOPLIGHT",
				"HOTCROISSANT",
				"HOTWAX",
				"HTTP Troy",
				"Hawup",
				"Hawup RAT",
				"Hermes",
				"HotCroissant",
				"HotelAlfa",
				"Hotwax",
				"HtDnDownLoader",
				"Http Dr0pper",
				"ICONICSTEALER",
				"Joanap",
				"Jokra",
				"KANDYKORN",
				"KEYMARBLE",
				"Kaos",
				"KillDisk",
				"KillMBR",
				"Koredos",
				"Krademok",
				"LIGHTSHIFT",
				"LIGHTSHOW",
				"LOLBAS",
				"LOLBins",
				"Lazarus",
				"LightlessCan",
				"Living off the Land",
				"MATA",
				"MBRkiller",
				"MagicRAT",
				"Manuscrypt",
				"Mimail",
				"Mimikatz",
				"Moudour",
				"Mydoom",
				"Mydoor",
				"Mytob",
				"NACHOCHEESE",
				"NachoCheese",
				"NestEgg",
				"NickelLoader",
				"NineRAT",
				"Novarg",
				"NukeSped",
				"OpBlockBuster",
				"PCRat",
				"PEBBLEDASH",
				"PLANKWALK",
				"POOLRAT",
				"PSLogger",
				"PhanDoor",
				"Plink",
				"PondRAT",
				"PowerBrace",
				"PowerRatankba",
				"PowerShell RAT",
				"PowerSpritz",
				"PowerTask",
				"Preft",
				"ProcDump",
				"Proxysvc",
				"PuTTY Link",
				"QUICKRIDE",
				"QUICKRIDE.POWER",
				"Quickcafe",
				"QuiteRAT",
				"R-C1",
				"ROptimizer",
				"Ratabanka",
				"RatabankaPOS",
				"Ratankba",
				"RatankbaPOS",
				"RawDisk",
				"RedShawl",
				"Rifdoor",
				"Rising Sun",
				"Romeo-CoreOne",
				"RomeoAlfa",
				"RomeoBravo",
				"RomeoCharlie",
				"RomeoCore",
				"RomeoDelta",
				"RomeoEcho",
				"RomeoFoxtrot",
				"RomeoGolf",
				"RomeoHotel",
				"RomeoMike",
				"RomeoNovember",
				"RomeoWhiskey",
				"Romeos",
				"RustBucket",
				"SHADYCAT",
				"SHARPKNOT",
				"SIGFLIP",
				"SIMPLESEA",
				"SLICKSHOES",
				"SORRYBRUTE",
				"SUDDENICON",
				"SUGARLOADER",
				"SheepRAT",
				"SierraAlfa",
				"SierraBravo",
				"SierraCharlie",
				"SierraJuliett-MikeOne",
				"SierraJuliett-MikeTwo",
				"SimpleTea",
				"SimplexTea",
				"SmallTiger",
				"Stunnel",
				"TAINTEDSCRIBE",
				"TAXHAUL",
				"TFlower",
				"TOUCHKEY",
				"TOUCHMOVE",
				"TOUCHSHIFT",
				"TOUCHSHOT",
				"TWOPENCE",
				"TYPEFRAME",
				"Tdrop",
				"Tdrop2",
				"ThreatNeedle",
				"Tiger RAT",
				"TigerRAT",
				"Trojan Manuscript",
				"Troy",
				"TroyRAT",
				"VEILEDSIGNAL",
				"VHD",
				"VHD Ransomware",
				"VIVACIOUSGIFT",
				"VSingle",
				"ValeforBeta",
				"Volgmer",
				"Vyveva",
				"W1_RAT",
				"Wana Decrypt0r",
				"WanaCry",
				"WanaCrypt",
				"WanaCrypt0r",
				"WannaCry",
				"WannaCrypt",
				"WannaCryptor",
				"WbBot",
				"Wcry",
				"Win32/KillDisk.NBB",
				"Win32/KillDisk.NBC",
				"Win32/KillDisk.NBD",
				"Win32/KillDisk.NBH",
				"Win32/KillDisk.NBI",
				"WinorDLL64",
				"Winsec",
				"WolfRAT",
				"Wormhole",
				"YamaBot",
				"Yort",
				"ZetaNile",
				"concealment_troy",
				"http_troy",
				"httpdr0pper",
				"httpdropper",
				"klovbot",
				"sRDI"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775434783,
	"ts_updated_at": 1775826750,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/09a02342ca6e0063e4ea42ec41d84dc733e54643.pdf",
		"text": "https://archive.orkl.eu/09a02342ca6e0063e4ea42ec41d84dc733e54643.txt",
		"img": "https://archive.orkl.eu/09a02342ca6e0063e4ea42ec41d84dc733e54643.jpg"
	}
}