{
	"id": "76bcb3b7-feab-4059-a8f0-14a223842078",
	"created_at": "2026-04-06T00:10:07.757044Z",
	"updated_at": "2026-04-10T13:11:58.867462Z",
	"deleted_at": null,
	"sha1_hash": "9839a714808e02dfe206f20b5ad15a569ea2165b",
	"title": "The Story of Jian - How APT31 Stole and Used an Unknown Equation Group 0-Day - Check Point Research",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 214036,
	"plain_text": "The Story of Jian - How APT31 Stole and Used an Unknown\r\nEquation Group 0-Day - Check Point Research\r\nBy Eyal Itkin\r\nPublished: 2021-02-22 · Archived: 2026-04-05 18:08:51 UTC\r\nResearch by: Eyal Itkin and Itay Cohen\r\nThere is a theory which states that if anyone will ever manage to steal and use nation-grade cyber tools, any\r\nnetwork would become untrusted, and the world would become a very dangerous place to live in.\r\nThere is another theory which states that this has already happened.\r\nWhat would you say if we told you that a foreign group managed to steal an American nuclear submarine? That\r\nwould definitely be a bad thing, and would quickly reach every headline.\r\nHowever, for cyber weapons – although their impact could be just as devastating – it`s usually a different story.\r\nCyber weapons are digital and volatile by nature. Stealing them and transferring from one continent to another,\r\ncan be as simple as sending an email. They are also very obscure, and their mere existence is a closely guarded\r\nsecret. That is exactly why, as opposed to a nuclear submarine, stealing a cyber-weapon can easily go under the\r\nradar and become a fact known only to a selected few.\r\nThe implications of such a scenario can be devastating, as the world have already experienced with the case of the\r\nShadow Brokers leak, in which a mysterious group have decided to publicly publish a wide range of cyber\r\nweapons allegedly developed by the Tailored Access Operations (TAO) unit of the NSA – also referred to as the\r\n‘Equation Group’.\r\nThe Shadow Brokers leak lead to some of the biggest cyber outbreaks in history – the most famous of which was\r\nthe WannaCry attack causing hundreds of millions of dollars in damages to organizations across the globe – and\r\nwhich its implications are still relevant even 3 years after it happened.\r\nThe Shadow brokers leak however, just gave us a taste of some of the possible implications such a cyber-theft can\r\ncause. Many important questions still remain – could this have also happened before? And if so, who is behind it\r\nand what did they use it for?\r\nOur recent research aims to shed more light on this topic, and reveal conclusive evidence that such a leak did\r\nactually take place years before the Shadow Brokers leak, resulting in US developed cyber tools reaching the\r\nhands of a Chinese group which repurposed them in order to attack US targets.\r\nKey Findings\r\nThe caught-in-the-wild exploit of CVE-2017-0005, a 0-Day attributed by Microsoft to the Chinese APT31\r\n(Zirconium), is in fact a replica of an Equation Group exploit code-named “EpMe.”\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 1 of 37\n\nAPT31 had access to EpMe’s files, both their 32-bits and 64-bits versions, more than 2 years before the\r\nShadow Brokers leak.\r\nThe exploit was replicated by the APT during 2014 to form “Jian”, and used since at least 2015, until\r\nfinally caught and patched in March 2017.\r\nThe APT31 exploit was reported to Microsoft by Lockheed Martin’s Computer Incident Response Team,\r\nhinting at a possible attack against an American target.\r\nThe framework containing the EpMe exploit is dated to 2013, and contains 4 Windows Privilege Escalation\r\nexploits overall, two of which were 0-Days at the time of the framework’s development.\r\nOne of the 0-Days in the framework, code-named “EpMo”, was never publicly discussed, and was patched\r\nby Microsoft with no apparent CVE-ID in May 2017. This was seemingly in response to the Shadow\r\nBrokers leak.\r\nFigure 1: Timeline of the events detailing the story of EpMe / Jian / CVE-2017-0005.\r\nIntroduction\r\nIn the last few months, our malware and vulnerability researchers focused on recent Windows Privilege Escalation\r\nexploits attributed to Chinese actors. During this investigation, we managed to unravel the hidden story behind\r\n“Jian”, a 0-Day exploit that was previously attributed to APT31 (Zirconium), and show its true origins.\r\nIn this blog we show that CVE-2017-0005, a Windows Local-Privilege-Escalation (LPE) vulnerability that was\r\nattributed to a Chinese APT, was replicated based on an Equation Group exploit for the same vulnerability that\r\nthe APT was able to access. “EpMe”, the Equation Group exploit for CVE-2017-0005, is one of 4 different LPE\r\nexploits included in the DanderSpritz attack framework. EpMe dates back to at least 2013 – four years before\r\nAPT31 was caught exploiting this vulnerability in the wild.\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 2 of 37\n\nThis isn’t the first documented case of a Chinese APT repurposing an Equation Group exploit.  In the Bemstour\r\ncase, discussed by both Symantec and our own research team, the main assumption was that APT3 (Buckeye)\r\nsniffed the EternalRomance exploit from network traffic, and later upgraded it to the equivalent of EternalSynergy\r\nusing an additional APT3 vulnerability. In the present case, however, we have strong evidence that APT31 had\r\naccess to the actual exploit files of Equation Group, in both their 32-bits and 64-bits versions.\r\nIn the following sections we introduce the 4 different Windows LPE exploits included in the DanderSpritz\r\nframework, and reveal an additional exploit code named “EpMo.” This exploit was patched in May 2017,\r\nprobably as part of the follow-up fixes for the Shadow Brokers “Lost in Translation” leak of Equation Group\r\ntools. While the vulnerability was fixed, we failed to identify the associated CVE-ID. To our knowledge, this is\r\nthe first public mention of the existence of this additional Equation Group vulnerability.\r\nBackground\r\nAs part of our ongoing research on Windows LPE exploits, and tracking exploit authors, we started analyzing\r\nexploits attributed to Chinese APTs. As CVE-2019-0803 was recently mentioned in the NSA list of top 25\r\nvulnerabilities used by Chinese actors, we decided this was a good place to start. After we finished documenting\r\nall the information we gathered on this unique exploit, originally a 0-Day attributed to Chinese actors, we went on\r\nto the next Chinese-attributed exploit in our list: CVE-2017-0005.\r\nIn our review of Microsoft’s report on the vulnerability that was caught exploited in the wild and was attributed to\r\nZirconium (APT31), we found a few interesting details:\r\nThe exploit was caught and reported to Microsoft by Lockheed Martin’s Computer Incident Response\r\nTeam.\r\nThe exploit uses a multi-staged packer, which appears identical to the one we saw used by CVE-2019-\r\n0803.\r\nFigure 2: Comparison between the packer of CVE-2017-0005 (left) and that of CVE-2019-0803 (right).\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 3 of 37\n\nArmed with these two leads, and already familiar with the packer used by these exploits, we set out to find the\r\ndescribed exploit of CVE-2017-0005.\r\nAfter we obtained a 64-bit sample of the CVE-2017-0005 exploit, we verified it against the information described\r\nby Microsoft in their blog. Not only did it match, when ignoring the random page allocation, both samples use the\r\nsame addresses (same lower 3 nibbles).\r\nFigure 3: Comparison between Microsoft’s sample (left) and ours (right).\r\nComparing CVE-2017-0005 and CVE-2019-0803\r\nIn the following section, we describe in detail some of the characteristics of the packer and the loader used in\r\nCVE-2017-0005 and CVE-2019-0803, and highlight their commonalities and differences.\r\nJian, the exploit of CVE-2017-0005, was shipped in a DLL named Add.dll . It contained an interesting PDB path\r\nsuggesting that it was written in 2015 under a project named “rundll32_getadmin”.\r\nF:\\\\code\\\\2015\\\\rundll32_getadmin\\\\Add\\\\x64\\\\Release\\\\Add.pdb\r\nWhen we checked the Time Date Stamp of the binary in the file header, we saw that the DLL was compiled on\r\nWed May 06 02:08:24 2015 , which fits nicely with the folder name from the PDB. An additional timestamp on\r\nthe export directory points to the exact same date. Speaking of the export directory, the DLL has a single exported\r\nfunction named “AddByGod”, which, as we will learn soon, is the entry function of the packer.\r\nThe decryption routine is very straightforward. The packer starts by allocating memory for the encrypted code and\r\ncopies it to the newly allocated buffer. It then allocates a buffer with PAGE_EXECUTE_READWRITE protection to store\r\nthe decrypted code. After the buffers are allocated, the packer checks if a string argument, which will be used as a\r\ndecryption key, was passed to the AddByGod function. Next, the packer uses the AES256 algorithm with a SHA1\r\nderived key of the passed argument to decrypt the encrypted code. If the decryption is successful, the decrypted\r\ncode is executed and a second stage payload runs. Luckily, we managed to obtain the password that was needed to\r\nexecute the binary and decrypt the encrypted payload.\r\nrundll32.exe Add.dll AddByGod [password]\r\nThe second stage begins with a typical shellcode technique, searching the module’s header for the address of\r\nkernel32.dll and dynamically retrieving a pointer to the GetProcAddress export function. Next, the program\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 4 of 37\n\ndecompresses another Portable Executable (PE) and jumps to its entry point. The decompressed PE, which is the\r\n3rd stage in the loading sequence, has intentionally corrupted headers. It does basic loading operations and then\r\nbegins with a reflective loading of an embedded executable (yes, another one). The loaded PE is the last stage in\r\nthe loading sequence and is responsible for executing the exploit.\r\nIt’s interesting to mention that the compilation time of the embedded binary — the exploit itself — goes back to\r\nOctober 2014. This suggests that the attackers used this 0-day in 2014, almost three years before it became\r\npublicly available in the Shadow Brokers leak and was fixed by Microsoft.\r\nFigure 4: The execution flow of the loaders used for CVE-2017-0005 and CVE-2019-0803.\r\nAs can be seen in the figure above, the packer used for CVE-2019-0803 is very similar to the one used in CVE-2017-0005. In fact, the flow is almost identical. The file was compiled on September 18, 2018, and is also\r\ninternally named “Add.dll”. Like the previously packed exploit, CVE-2019-0803 also has an export function\r\nnamed “AddByGod” and contains debug information:\r\nC:\\Users\\sms2056\\Desktop\\Add（未修改dll‘）\\x64\\Release\\Add.pdb\r\nUnlike the previous sample, this one uses a different decryption password and needs an additional argument when\r\nrunning (used in later stages). The execution flow then continues exactly as we observed in the previous sample\r\nwith one exception: after the program decompresses a PE payload and jumps to its entry point, it does not have a\r\n4th stage of another embedded PE, but simply begins the exploitation stage.\r\nWe looked for more samples that use this or a similar variant of the packer we described, and found multiple\r\nsamples and malware families that have used it for many years. All of the malware are clearly and exclusively\r\nattributed to Chinese-affiliated attack groups. Adding this conclusion to the contextual information we have,\r\nMicrosoft’s independent attribution of CVE-2017-0005 to a Chinese APT, and NSA’s attribution of CVE-2019-\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 5 of 37\n\n0803 to “Chinese State-Sponsored Actors”, make us believe that the exploit of CVE-2017-0005 was indeed used\r\nby attackers that are part of a Chinese group.\r\nJian – CVE-2017-0005\r\nWhen analyzing Jian, we noticed the following interesting characteristics.\r\nOperating System (OS) Version Context\r\nThe exploit creates a rich version context that includes multiple fields, each representing a different characteristic\r\nof the target’s operating system. This extensive context isn’t typical of the Chinese-attributed exploits we\r\npreviously analyzed and looks like some sort of a utility/framework. This is even more suspicious, as some fields\r\nin the context aren’t even initialized (marked in red), and overall only three of them are used by the exploit itself\r\n(marked in blue).\r\nFigure 5: Rich version information, as collected by Jian.\r\nJust for comparison, the exploit of CVE-2019-0803 supported only a single Windows version and used the\r\nhardcoded version-dependent constants for Windows Server 2008 R2. Alibaba even reported that the tool’s file\r\nname was 2008.dll , leaving no doubt about the tool’s intended target.\r\nGlobal Configuration Table\r\nThe OS version enum is used as an index for a global configuration table. This is a classic example of using such\r\nan enum when one needs a version-dependent configuration. The configuration table itself looks like a promising\r\nartifact that might appear in additional exploits by the same authors.\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 6 of 37\n\nWe created detection signatures and looked for samples that contain this configuration table. Our search query\r\nresulted in the following samples:\r\nMcl_NtElevation_EpMe_GrSa.dll   (x86) –\r\n292fe1fc7d350cc7b970da0f308d22089cd36ab552e5659e3cfb0d9690166628\r\nMcl_NtElevation_EpMo_GrSa.dll (x64) –\r\n1537cad1d2c5154e142af775ed555d6168d528bbe40b31f451efa92c9e4f02de\r\nThe naming convention of the files and their context immediately caught us by surprise. We recognized them as\r\npart of the Shadow Brokers’ “Lost in Translation” leak of Equation Group tools. Equation Group is the name\r\ngiven to an APT group which is believed to be the Tailored Access Operations (TAO) unit of the NSA. How did\r\nour search for extremely-unique artifacts extracted from a Chinese 0-Day exploit that was patched in March\r\n2017 show results of leaked Equation Group tools from 2013? To answer this question, we started to dive deep\r\nand analyze the information we found.\r\nLost In Translation\r\nBefore we describe our analysis, we want to give a brief history of The Shadow Brokers group and their leaks of\r\nEquation Group tools. We believe that understanding the nature of the leak, and especially the timeline, is crucial\r\nfor understanding what happened next.\r\nThe Shadow Brokers is a mystery group of hackers that first appeared on August 12, 2016, when they invited the\r\npublic to participate in an auction of Equation Group’s “Cyber Weapons.” Since then, the group started to leak\r\nmore and more files over a period of several months. One of these leaks, called “Lost in Translation”, emerged in\r\nApril 2017, and is well known for releasing Equation Group’s notorious exploits such as Eternal Blue.\r\nOne of the main components in this leak is DanderSpritz, Equation Group’s post-exploitation framework that\r\ncontains a wide variety of tools for persistence, reconnaissance, lateral movement, bypassing Antivirus engines,\r\nand more. The framework is very modular and provides the operator many capabilities to access victims’\r\ncomputers. During the recent months, we revisited the DanderSpritz framework, reverse-engineered some of its\r\nmodules and implants, and plan to publish a detailed publication dedicated to the framework and our\r\nfindings.\r\nOur project of profiling exploit authors focuses on Windows LPE exploits, like CVE-2017-0005 whose artifacts\r\nwe searched. As common in post-exploitation frameworks, DanderSpritz and the Lost In Translation leak also\r\ncontain LPE exploits, and two of them matched our query.\r\nWe now present a brief overview of some of the LPE exploits that were attributed to the Equation Group and their\r\nconnection to the leaked DanderSpritz framework.\r\nHistory of Equation Group LPE Exploits\r\nPrivLib and the Houston Disk\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 7 of 37\n\nThe term “PrivLib” is often used when referring to a Privilege Escalation module embedded inside a given\r\nEquation Group implant. PrivLib contains a selected set of Windows LPE exploits chosen from the Equation\r\nGroup arsenal, and all of them are wrapped using a thin wrapper known by its “prkMtx” unique mutex.\r\nIn 2015, Kaspersky reported a set of Windows LPEs embedded inside a booby-trapped disk given away at a\r\nHouston scientific convention. The exploits, attributed to Equation Group, were all 0-Day at the time of\r\ndevelopment, and some even dated as far back as 2008. All in all, the Houston Disk contained a PrivLib version\r\nthat executes a set of 3 exploits one after the other, until the desired privileges are acquired.\r\nHere is a list of the exploits included in the disk, according to their execution order:\r\n1. MS09-025 (Fanny / Stuxnet)\r\n2. CVE-2013-3128\r\n3. CVE-2011-3402\r\nNote: The CVEs listed here don’t match those mentioned originally by Kaspersky in their report. First,\r\nKaspersky’s researchers weren’t sure about the CVE-IDs to begin with, marking them as “possibly.” Second, we\r\nfound additional information regarding the latter two exploits, which helped shed light on more probable CVE-IDs for each. More details about the CVE-ID identification can be found later on under the respective sections\r\ndescribing each exploit.\r\nDanderSpritz NtElevation\r\nDanderSpritz is a modular post-exploitation framework that contains dozens of different interdependent modules.\r\nFor example, some modules do not run unless specific modules are not executed first, and others require special\r\nprivileges or artifacts to run. Some of the modules require privileges of a SYSTEM account to run. For this to\r\nhappen, DanderSpritz executes a set of modules named ‘NtElevation’ that are responsible for elevating the\r\nprivileges of the implant running on the victim’s computer.\r\nFigure 6: An\r\nexample for the dependencies of the PasswordDump module, including NtElevation .\r\nThese privilege escalation modules are the ones we caught when we queried for Jian’s global configuration table.\r\nAnd they were not alone. We also found a couple of more Local Privilege Escalation exploits from the\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 8 of 37\n\nNtElevation series.\r\nWhile the Eternal* exploits received a lot of attention, and rightly so, mentions of the NtElevation exploits were\r\nsomehow missing. We couldn’t find any online reference that points to the existence of the NtElevation module as\r\npart of the Equation Group arsenal or even as part of the “Shadow Brokers Exploits”, nor any reference to the\r\nfollowing 4 exploit code names.\r\nElEi\r\nErNi\r\nEpMo\r\nEpMe\r\nNote: Equation Group’s exploits are known to have code names that are abbreviated using 4 letters. For example,\r\nEternal Blue and Eternal Romance are internally referred to as ETBL and ETRO . Similarly, the Local Privilege\r\nEscalation exploits we discussed have their own code names, as listed above.\r\nDespite our attempts, we couldn’t manage to trace back the full code names for these exploits. However, the\r\nnaming convention suggests that EpMo and EpMe are of the same type or that they exploit vulnerabilities in the\r\nsame module, just like the Eternal* exploits (EternalBlue, EternalRomance, etc). This conclusion does make\r\nsense as our single search query found both of these exploits.\r\nWhen we analyzed the DanderSpritz NtElevation API, we found the checks that each module deploys to declare\r\nthat the exploit is indeed supported. When combined with the original patch dates Kaspersky estimated for the two\r\nfont exploits from the Houston Disk, this new information helped us make a better estimate of the inner workings\r\nof each CVE-ID.\r\nWe thoroughly analyzed the found exploits and tried to match each exploit file to its respective CVE-ID. These are\r\nthe results of our analysis and our conclusions.\r\nElEi – CVE-2011-3402\r\nHouston Disk: 3rd in the execution order.\r\nSupported DanderSpritz Windows Versions: Windows 2000 to Windows 7, inclusive.\r\nThe exploit also contains an additional check that win32k.sys is dated to before November 23, 2011. This is a\r\nclear indication of CVE-2011-3402, which is the only font vulnerability that was fixed in December 2011. The gap\r\nin the dates is explained by the fact that Microsoft compiled the patched driver on the mentioned date.\r\nWe are aware that CVE-2011-3402 was originally spotted as a 0-Day that was exploited in the wild, and was\r\nfound in Duqu (1.0). Currently, we can only point out this interesting CVE-ID match, but we have not yet studied\r\nit further or compared the two exploits, as these font exploits are outside of the scope of our research, which\r\nfocuses on the unknown DanderSpritz exploits and their connection to CVE-2017-0005.\r\nWe do recommend this lead for a future work publication and invite security researchers worldwide to examine\r\nthis connection.\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 9 of 37\n\nErNi – CVE-2013-3128\r\nHouston Disk: 2nd in the execution order.\r\nSupported DanderSpritz Windows Versions: Only Windows 2000.\r\nThe exploit also contains an additional check that ATMFD.dll is of the exact version “5.0.2.227”. As the Houston\r\nDisk exploit supported additional versions, we aren’t fully sure why the version range was narrowed down in\r\nDanderSpritz. Compared to ElEi , there is no indicative patch check, which may be because the DanderSpritz\r\nfiles are dated to mid-2013, which is prior to the patch that was identified by Kaspersky and is dated to October\r\n2013.\r\nWe chose CVE-2013-3128 instead of CVE-2013-3894 because this vulnerability is an OpenType Font\r\nvulnerability, which correlates with the exploit at hand. This identification should be taken with a grain of salt as\r\nnone of these CVE-IDs were actually marked as “exploited in the wild.” The reason we chose this CVE-ID is\r\nmerely because it is mentioned in the Patch Tuesday cited by Kaspersky. As with ElEi , further study of these\r\nfont exploits is more than welcome.\r\nUser Mode Print Driver (UMPD) 101\r\nBasic analysis of both EpMo and EpMe found them to be GDI User-Mode-Print-Driver (UMPD) related, which\r\nexplains why we found them when searching for a GDI UMPD related artifact from Jian. Before diving into the\r\nexploits, we first provide some background on what exactly is a User-Mode-Print-Driver.\r\nThe Windows operating system supports the option of rendering most of the needed graphics for a given print job\r\nin user-mode, in contrast to the traditional implementation of such drivers inside the Windows kernel. The\r\narchitecture of deploying such a User-Mode-Print-Driver (UMPD) is shown below.\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 10 of 37\n\nFigure\r\n7: UMPD architecture, based on figures from this Black-Hat Europe talk.\r\nSupporting such a data flow dictates that the kernel is aware of the user’s UMPD device and can forward it a set of\r\nrequests, depending on the types that the driver declared to support. As is explained in more detail in this excellent\r\nBlack Hat Europe 2020 talk focusing on UMPD, allowing for user-mode callbacks, invoked from the kernel, is a\r\nsure recipe for security vulnerabilities.\r\nIn the next few sections, we explain in detail how each Equation Group exploit uses the UMPD, and which\r\nvulnerabilities in this mechanism were exploited.\r\nEpMo – Analysis\r\nHouston Disk: N/A.\r\nSupported DanderSpritz Windows Versions: Windows 2000 to Windows Server 2008 R2, inclusive.\r\nRoot Cause\r\nAfter we finished reverse engineering the rich context and utilities exposed as part of the DanderSpritz framework\r\nand API, the vulnerability itself was quite simple. A short analysis revealed that this is probably a NULL-Deref\r\nvulnerability, as the NULL page is allocated, and the shellcode is immediately copied to it, as can be seen below:\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 11 of 37\n\nFigure 8: Preparation of the NULL-page, as part of the EpMo exploit.\r\nAs this is a NULL-Deref vulnerability, we can immediately rule out CVE-2017-0005, as the stack trace shown in\r\nMicrosoft’s blog has nothing to do with the NULL page. This means that this is possibly another vulnerability\r\nfound and exploited by Equation Group in 2013. With that out of the way, it is time to understand what triggers\r\nthis NULL-Deref vulnerability.\r\nOur first hint as to the identity of the affected module, which we expect to be the UMPD, can be found in this\r\nclassic example of the use of the OS version enum field:\r\nFigure 9: Using OS version enum to query for the ppClientPrinterThunk callback index.\r\nAfter the version-dependent index of the callback is fetched, the callback itself is replaced with the attacker’s fake\r\nClientPrinterThunk callback.\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 12 of 37\n\nFigure 10: Replacing the KernelCallbackEntry with the attacker’s ClientPrinterThunk .\r\nBingo! The exploit indeed makes use of a fake ClientPrinterThunk . Let’s dig in and analyze the exploit logic\r\ninside this fake callback.\r\nThe callback itself is a thin wrapper that forwards the gdi_ctx and the original argument to a function that is\r\nvery similar to Windows’s own GdiPrinterThunk . As a matter of fact, the code of the exploit is very modular,\r\nand each supported driver command is handled by its own virtual handler implemented in the gdi_ctx class.\r\nAside from the chosen set of implemented handlers, there is no real logic in this function.\r\nFigure 11: Driver command types that are handled by the exploit’s user-mode driver.\r\nWhile analyzing this function, we stumbled upon the GDI configuration array that originally pointed us to this\r\nexploit sample. Now, placed in the right context, we can easily deduce the role of this configuration array. It holds\r\nthe print driver’s INDEX_LAST value for each version of the target operating system.\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 13 of 37\n\nFigure 12: Global INDEX_LAST configuration table, as used by the driver.\r\nAs can be seen above, this configuration value is crucial for the driver’s logic as it represents the total number of\r\ndispatched functions that should be handled by the driver.\r\nNow that we understood the overall flow of the exploit, and the structure of the User-Mode-Print-Driver (UMPD),\r\ntracing the root cause of the vulnerability proved to be a relatively simple task. The driver implemented special\r\nhandlers only for the following basic command types:\r\nFigure 13: List of driver-supported command types.\r\nOn top of these commands, there is one additional supported command, with the os-dependent value of\r\nINDEX_LAST + 4 :\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 14 of 37\n\nFigure 14: Handler for the DrvFN command type.\r\nIn this command, we initialize an array that tells the operating system which function handlers we support. The\r\nattackers chose to mark all of the functions as “supported” except for 3 specific function handlers:\r\nDrvStartDoc (0x23)\r\nDrvEnableSurface (0x03)\r\nDrvDisableSurface (0x04)\r\nPlease pay close attention to DrvEnableSurface . The syscall that triggers the vulnerability is NtGdiStartDoc ,\r\nwhich is responsible for starting the print job. However, to do so, the vulnerable function\r\nwin32k!PDEVOBJ::bMakeSurface() is invoked and tries to create a surface, exactly the operation that isn’t\r\nsupported by our driver. Here is a debugging output from the vulnerable function:\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 15 of 37\n\nFigure 15: Debugger output inside the vulnerable function showing the missing handler entry.\r\nWhile the entry for DrvDisablePDEV (0x02) exists, and points to the correct Windows function, the adjacent entry\r\nfor DrvEnableSurface (0x03) contains only zeros.\r\nFrom this point, the vulnerability is clear. The vulnerable function assumes that our driver supports this handler,\r\nfetches the empty entry from the struct, and invokes NULL as the function responsible for enabling the surface.\r\nThe figure below shows the full stack trace, right at the point in which the control flow is passed to the shellcode\r\nthat the attacker stored at address 0x0:\r\n01 8aeb8c88 8fbae3f6 win32k!PDEVOBJ::bMakeSurface+0x43\r\n02 8aeb8cb0 8fbae94c win32k!GreStartDocInternal+0x7e\r\n03 8aeb8d1c 82a4f42a win32k!NtGdiStartDoc+0x2ff\r\n04 8aeb8d1c 000f0813 (T) nt!KiFastCallEntry+0x12a\r\n05 0022eed0 10008118 (T) 0xf0813\r\n06 0022ef18 10006f53 Mcl_NtElevation_EpMo_GrSa+0x8118\r\n07 0022ef28 10006fc3 Mcl_NtElevation_EpMo_GrSa+0x6f53\r\n08 0022ef44 10007af4 Mcl_NtElevation_EpMo_GrSa+0x6fc3\r\n09 0022ef74 10006ce5 Mcl_NtElevation_EpMo_GrSa+0x7af4\r\n0a 0022efcc 10004a31 Mcl_NtElevation_EpMo_GrSa+0x6ce5\r\n0b 0022f324 100038c0 Mcl_NtElevation_EpMo_GrSa+0x4a31\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 16 of 37\n\n0c 0022f338 10003a7b Mcl_NtElevation_EpMo_GrSa+0x38c0\r\n0d 0022f370 10002adf Mcl_NtElevation_EpMo_GrSa+0x3a7b\r\n0e 0022f3d8 77d5af24 Mcl_NtElevation_EpMo_GrSa+0x2adf\r\n00 8aeb8c6c 8fa42330 0x0 01 8aeb8c88 8fbae3f6 win32k!PDEVOBJ::bMakeSurface+0x43 02 8aeb8cb0\r\n8fbae94c win32k!GreStartDocInternal+0x7e 03 8aeb8d1c 82a4f42a win32k!NtGdiStartDoc+0x2ff 04 8aeb8d1c\r\n000f0813 (T) nt!KiFastCallEntry+0x12a 05 0022eed0 10008118 (T) 0xf0813 06 0022ef18 10006f53\r\nMcl_NtElevation_EpMo_GrSa+0x8118 07 0022ef28 10006fc3 Mcl_NtElevation_EpMo_GrSa+0x6f53 08\r\n0022ef44 10007af4 Mcl_NtElevation_EpMo_GrSa+0x6fc3 09 0022ef74 10006ce5\r\nMcl_NtElevation_EpMo_GrSa+0x7af4 0a 0022efcc 10004a31 Mcl_NtElevation_EpMo_GrSa+0x6ce5 0b\r\n0022f324 100038c0 Mcl_NtElevation_EpMo_GrSa+0x4a31 0c 0022f338 10003a7b\r\nMcl_NtElevation_EpMo_GrSa+0x38c0 0d 0022f370 10002adf Mcl_NtElevation_EpMo_GrSa+0x3a7b 0e\r\n0022f3d8 77d5af24 Mcl_NtElevation_EpMo_GrSa+0x2adf\r\n00 8aeb8c6c 8fa42330 0x0\r\n01 8aeb8c88 8fbae3f6 win32k!PDEVOBJ::bMakeSurface+0x43\r\n02 8aeb8cb0 8fbae94c win32k!GreStartDocInternal+0x7e\r\n03 8aeb8d1c 82a4f42a win32k!NtGdiStartDoc+0x2ff\r\n04 8aeb8d1c 000f0813 (T) nt!KiFastCallEntry+0x12a\r\n05 0022eed0 10008118 (T) 0xf0813\r\n06 0022ef18 10006f53 Mcl_NtElevation_EpMo_GrSa+0x8118\r\n07 0022ef28 10006fc3 Mcl_NtElevation_EpMo_GrSa+0x6f53\r\n08 0022ef44 10007af4 Mcl_NtElevation_EpMo_GrSa+0x6fc3\r\n09 0022ef74 10006ce5 Mcl_NtElevation_EpMo_GrSa+0x7af4\r\n0a 0022efcc 10004a31 Mcl_NtElevation_EpMo_GrSa+0x6ce5\r\n0b 0022f324 100038c0 Mcl_NtElevation_EpMo_GrSa+0x4a31\r\n0c 0022f338 10003a7b Mcl_NtElevation_EpMo_GrSa+0x38c0\r\n0d 0022f370 10002adf Mcl_NtElevation_EpMo_GrSa+0x3a7b\r\n0e 0022f3d8 77d5af24 Mcl_NtElevation_EpMo_GrSa+0x2adf\r\nThe Patch\r\nMicrosoft fixed this vulnerability in May 2017, one month after the Shadow Brokers’s Lost in Translation leak.\r\nHowever, we failed to find a CVE-ID that refers to this fix. The patch itself addresses the exact flaw in the\r\nvulnerable function win32k!PDEVOBJ::bMakeSurface() . It adds a sanity check after the handler is fetched from\r\nthe struct, and before it is invoked by the function. If the entry is NULL, the function aborts.\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 17 of 37\n\nFigure 16: Patched version now checks the function handler before invoking it.\r\nTo conclude, the EpMo Equation Group exploit is a NULL-Deref in GDI’s UMPD module, and is therefore not\r\nan exploit for CVE-2017-0005. It was patched by Microsoft in May 2017, and we couldn’t find a clear CVE-ID\r\nassociated with it.\r\nNow that we better understand the framework’s API, and have a better understanding of the UMPD module, it is\r\ntime to focus on the next exploit – EpMe .\r\nJust to recap, we found both of these exploits when searching for an artifact from Jian, APT31’s exploit for CVE-2017-0005. As EpMo is a different vulnerability that originates from the same module, our hope was that EpMe\r\ndoes indeed exploit CVE-2017-0005. Time to analyze it and find out.\r\nEpMe – Analysis\r\nHouston Disk: N/A.\r\nSupported DanderSpritz Windows Versions: Windows XP to Windows 8, inclusive.\r\nRoot Cause\r\nArmed with our newly acquired knowledge about the UMPD module, we started analyzing the EpMe exploit. The\r\nexploit itself shares a lot of code with EpMo, thus allowing us to easily focus on the exploit-specific logic that is\r\nunique to EpMe. While the initialization phase of this exploit is longer and involves a lot of GDI-related\r\nbootstrapping ( DrawStream() , finding the wanted Display, etc.), the actual flow that hijacks the control flow is\r\nrelatively simple.\r\nAfter the bootstrap is finished, the exploit triggers a call to the NtGdiBitBlt syscall. This initiates a chain of\r\nevents in the Windows kernel and eventually passes the flow back to our user-mode callback ( DrvBitBlt() )\r\nregistered by our UMPD. Here lies the heart of the exploit.\r\nOur function allocates a new Rbrush using NtGdiBRUSHOBJ_pvAllocRbrush() , whose sole purpose is to allow\r\nUMPD implementations to allocate themselves an Rbrush and couple it with a BRUSHOBJ . As a direct result, it\r\nalso means that the Rbrush is allocated in user-mode, using EngAllocUserMemEx() . Storing it in user-mode\r\nmeans that we can access it and craft the struct’s content. And so, the attackers corrupted the Rbrush to point at a\r\nset of fake GDI objects that were forged on a local stack buffer inside the callback.\r\nTo hijack the control flow, the attackers chose to use a Palette and crafted it so that\r\nPALETTE.pfnGetNearestFromPalentry points to their shellcode, exactly as Microsoft pointed out in their blog on\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 18 of 37\n\nthe caught-in-the-wild exploit. After everything is built, the callback invokes the NtGdiEngBitBlt syscall with a\r\nrop4 parameter of 0xCCAA . This specific syscall was chosen because of two key features:\r\nThe user passes to it a BRUSHOBJ .\r\nA rop4 value of 0xCCAA means the kernel directly accesses the user-controlled Rbrush from within the\r\nsupplied BRUSHOBJ .\r\nMore specifically, a Stream is extracted from the fully-controlled Rbrush and is forwarded on to\r\nEngDrawStream() , causing the unsuspecting kernel function to use our fully crafted Stream.\r\nFigure 17: Control flow of the EpMe exploit of CVE-2017-0005.\r\nThis chain of functions gradually uses all of the GDI objects that we’ve crafted in our user-mode callback,\r\neventually leading to XLATEOBJ_iXlate() . This last function invokes our crafted\r\nPALETTE.pfnGetNearestFromPalentry function pointer, thus hijacking the control flow and triggering the\r\nexecution of our shellcode.\r\nTo summarize, the root cause for this vulnerability is based on the complex design involved in supporting UMPD,\r\nand the need to allocate objects for it in user-mode. The vulnerability itself lies inside EngBitBlt() , which\r\nblindly trusts and directly uses our crafted Rbrush and the set of fake GDI objects it points to. Not only does this\r\nvulnerability give an attacker a powerful exploit primitive, but it also points at a design issue in the Windows\r\nkernel. As long as there is a function somewhere in the kernel that directly accesses a user-supplied Rbrush , it\r\nalso blindly trusts all the values that it points to and that are fully controlled by the user.\r\nThe Patch – CVE-2017-0005\r\nAnother important conclusion we drew from analyzing the exploited vulnerability is that we now know for sure\r\nthat EpMe exploits CVE-2017-0005. On top of our analysis of both the Equation Group and APT31 exploits, the\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 19 of 37\n\nEpMe exploit aligns perfectly with the details reported in Microsoft’s blog on CVE-2017-0005. And if that wasn’t\r\nenough, the exploit indeed stopped working after Microsoft’s March 2017 patch, the patch that addressed the said\r\nvulnerability.\r\nThe patch itself is rather straightforward: EngBitBlt() with a rop4 value of 0xCCAA no longer supports the\r\noption to draw a Stream, an action that demands extracting a Stream from the user-supplied Rbrush . By\r\nremoving this feature altogether, Microsoft completely eliminated the vulnerable code flow.\r\nBefore:\r\nFigure 18: Vulnerable win32k.sys , supports both EngDrawStream() and EngTransparentBlt() .\r\nAfter:\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 20 of 37\n\nFigure 19: Patched win32k.sys , no longer supports EngDrawStream() .\r\nIt is important to remember that two APTs exploiting the same vulnerability (CVE-2017-0005) could just be a\r\ncoincidence. When this happens to security researchers, such a case is often referred to as a “bug-collision.” It’s\r\npossible that researchers on both sides found this vulnerability independently, and it doesn’t necessarily mean that\r\nthere is a real connection between the tools.\r\nWe now compare the two exploit samples, Jian and EpMe, and see if we can spot any connection between them\r\naside from them exploiting the same vulnerability.\r\nEpMe vs Jian\r\nSimilar Version Context\r\nAt the beginning of our research, we saw that Jian uses a context that holds multiple fields about the version of the\r\ntarget’s operating system. Used fields are marked in blue, and uninitialized fields are marked in red.\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 21 of 37\n\nFigure 20: Rich version information, as collected by Jian.\r\nNow, when we review the version context used by all exploits shared by the DanderSpritz framework, we can see\r\nthe following, very similar, structure:\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 22 of 37\n\nFigure 21: Version context used by\r\nDanderSpritz and shared by all Equation Group exploits.\r\nThe fields that are marked in red in Jian were marked again in the sample from the Equation Group exploits. As\r\ncan be seen, one field is still unused in all 4 DanderSpritz exploits, but the other field is heavily used and holds the\r\nhandle for the mapped version of NTOS kernel. It is hard to miss the wide similarity between the two structures,\r\nup to the order and size of the first 9 fields, even including the size of the unused field in between.\r\nThe changes between the two configuration structures are that Equation Group’s configuration contains more\r\nfields, mostly used for security mitigation policies, that are relevant for Windows 8 systems and higher. The last\r\ndifference between the structures is in the field specifying the architecture of the target’s kernel, which for some\r\nreason was negated in Jian. Anyway, this field was never used by the exploit.\r\nOverall, having a Chinese-attributed exploit use a version context is uncommon. Having one that is nearly\r\nidentical to the version context used by the entire DanderSpritz NtElevation module can’t be a coincidence.\r\nSame Memory Layout\r\nAt the heart of the exploits lies a single function that populates a buffer with the various fake GDI objects, which\r\nis pointed to by our user-mode Rbrush object. Not only do both exploits use a single function for the\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 23 of 37\n\nconstruction of all of these fake objects, but the memory layout of the objects in the argument buffer is also\r\nidentical.\r\nFigure 22:\r\nConstruction of the fake GDI objects, as done in Jian.\r\nWhen we analyzed the code of the Equation Group exploit, we used it to recreate a source code Proof-Of-Concept\r\n(POC). The result is the following beautified and labeled code:\r\nvoid populate_buffer_and_brush(char * pBuffer, HBRUSH hbrush)\r\nmemset(pBuffer, 0, 0x200);\r\nmemset(\u0026pBuffer[0x200], 0, 0xA8);\r\nmemset(\u0026pBuffer[0x2A8], 0, 0x30);\r\nmemset(\u0026pBuffer[0x2D8], 0, 0x10);\r\n*(DWORD *)( pBuffer + 0x18) = 2; // 0x14 - 0x1C: flPal\r\n*(size_t *)(pBuffer + 0x80) = pBuffer + 0x2A8; // 0x80 - 0x88: apalColor\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 24 of 37\n\n// Brush (DRAWSTREAMINFO)\r\nsize_t * pBrush = (size_t*)hbrush;\r\npBrush[3] = pBuffer + 0x29C; // pptlDstOffset - Pointer to 0\r\npBrush[4] = pBuffer + 0x208; // pxloSrcToBGRA\r\npBrush[5] = pBuffer + 0x208; // pxloDstToBGRA\r\npBrush[6] = pBuffer + 0x208; // pxloBGRAToDst \u003c-- We use this one (offset 0x30)\r\npBrush[7] = 60; // ulStreamLength - 60\r\npBrush[8] = pBuffer + 0x260; // pvStream - Pointer to our built \"Stream\"\r\n*(size_t *)(pBuffer + 0x200) = hbrush;\r\n*(size_t *)(pBuffer + 0x230) = pBuffer; // ppalSrc\r\n*(size_t *)(pBuffer + 0x238) = pBuffer; // ppalDst \u003c-- We use this one (offset 0x30)\r\n*(size_t *)(pBuffer + 0x240) = pBuffer; // ppalDstDC\r\n// 0x260 - 0x2A8: Our \"Stream\"\r\n*(DWORD *)(pBuffer + 0x260) = 9; // DS_NINEGRIDID (ulCmdID)\r\n*(DWORD *)(pBuffer + 0x26C) = 1; // rclDst.right = 0x01\r\n*(DWORD *)(pBuffer + 0x270) = 1; // rclDst.bottom = 0x01\r\n*(DWORD *)(pBuffer + 0x27C) = 80; // rclSrc.right = 0x50\r\n*(DWORD *)(pBuffer + 0x280) = 80; // rclSrc.bottom = 0x50\r\n*(DWORD *)(pBuffer + 0x284) = 4; // ngi.flFlags := DSDNG_PERPIXELALPHA (4)\r\n// 0x2A8: Palette Color Table\r\n*(DWORD *)(pBuffer + 0x2CC) = 100;\r\n*(size_t *)(pBuffer + 0x2D8) = AllocMemoryPage(0x10000);\r\n*(size_t *)(pBuffer + 0x2E0) = g_pRtlCopyUnicodeString;\r\nvoid populate_buffer_and_brush(char * pBuffer, HBRUSH hbrush) { memset(pBuffer, 0, 0x200);\r\nmemset(\u0026pBuffer[0x200], 0, 0xA8); memset(\u0026pBuffer[0x2A8], 0, 0x30); memset(\u0026pBuffer[0x2D8], 0, 0x10); //\r\n0x00: PALETTE *(DWORD *)( pBuffer + 0x18) = 2; // 0x14 - 0x1C: flPal *(size_t *)(pBuffer + 0x80) = pBuffer\r\n+ 0x2A8; // 0x80 - 0x88: apalColor // Brush (DRAWSTREAMINFO) size_t * pBrush = (size_t*)hbrush;\r\npBrush[3] = pBuffer + 0x29C; // pptlDstOffset - Pointer to 0 pBrush[4] = pBuffer + 0x208; // pxloSrcToBGRA\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 25 of 37\n\npBrush[5] = pBuffer + 0x208; // pxloDstToBGRA pBrush[6] = pBuffer + 0x208; // pxloBGRAToDst \u003c-- We use\r\nthis one (offset 0x30) pBrush[7] = 60; // ulStreamLength - 60 pBrush[8] = pBuffer + 0x260; // pvStream - Pointer\r\nto our built \"Stream\" // Second Struct *(size_t *)(pBuffer + 0x200) = hbrush; // 0x208: _XLATE *(size_t *)\r\n(pBuffer + 0x230) = pBuffer; // ppalSrc *(size_t *)(pBuffer + 0x238) = pBuffer; // ppalDst \u003c-- We use this one\r\n(offset 0x30) *(size_t *)(pBuffer + 0x240) = pBuffer; // ppalDstDC // 0x260 - 0x2A8: Our \"Stream\" *(DWORD\r\n*)(pBuffer + 0x260) = 9; // DS_NINEGRIDID (ulCmdID) *(DWORD *)(pBuffer + 0x26C) = 1; // rclDst.right =\r\n0x01 *(DWORD *)(pBuffer + 0x270) = 1; // rclDst.bottom = 0x01 *(DWORD *)(pBuffer + 0x27C) = 80; //\r\nrclSrc.right = 0x50 *(DWORD *)(pBuffer + 0x280) = 80; // rclSrc.bottom = 0x50 *(DWORD *)(pBuffer +\r\n0x284) = 4; // ngi.flFlags := DSDNG_PERPIXELALPHA (4) // 0x2A8: Palette Color Table *(DWORD *)\r\n(pBuffer + 0x2CC) = 100; // Fourth Struct *(size_t *)(pBuffer + 0x2D8) = AllocMemoryPage(0x10000); *(size_t\r\n*)(pBuffer + 0x2E0) = g_pRtlCopyUnicodeString; }\r\nvoid populate_buffer_and_brush(char * pBuffer, HBRUSH hbrush)\r\n{\r\n memset(pBuffer, 0, 0x200);\r\n memset(\u0026pBuffer[0x200], 0, 0xA8);\r\n memset(\u0026pBuffer[0x2A8], 0, 0x30);\r\n memset(\u0026pBuffer[0x2D8], 0, 0x10);\r\n // 0x00: PALETTE\r\n *(DWORD *)( pBuffer + 0x18) = 2; // 0x14 - 0x1C: flPal\r\n *(size_t *)(pBuffer + 0x80) = pBuffer + 0x2A8; // 0x80 - 0x88: apalColor\r\n // Brush (DRAWSTREAMINFO)\r\n size_t * pBrush = (size_t*)hbrush;\r\n pBrush[3] = pBuffer + 0x29C; // pptlDstOffset - Pointer to 0\r\n pBrush[4] = pBuffer + 0x208; // pxloSrcToBGRA\r\n pBrush[5] = pBuffer + 0x208; // pxloDstToBGRA\r\n pBrush[6] = pBuffer + 0x208; // pxloBGRAToDst \u003c-- We use this one (offset 0x30)\r\n pBrush[7] = 60; // ulStreamLength - 60\r\n pBrush[8] = pBuffer + 0x260; // pvStream - Pointer to our built \"Stream\"\r\n // Second Struct\r\n *(size_t *)(pBuffer + 0x200) = hbrush;\r\n // 0x208: _XLATE\r\n *(size_t *)(pBuffer + 0x230) = pBuffer; // ppalSrc\r\n *(size_t *)(pBuffer + 0x238) = pBuffer; // ppalDst \u003c-- We use this one (offset 0x30)\r\n *(size_t *)(pBuffer + 0x240) = pBuffer; // ppalDstDC\r\n // 0x260 - 0x2A8: Our \"Stream\"\r\n *(DWORD *)(pBuffer + 0x260) = 9; // DS_NINEGRIDID (ulCmdID)\r\n *(DWORD *)(pBuffer + 0x26C) = 1; // rclDst.right = 0x01\r\n *(DWORD *)(pBuffer + 0x270) = 1; // rclDst.bottom = 0x01\r\n *(DWORD *)(pBuffer + 0x27C) = 80; // rclSrc.right = 0x50\r\n *(DWORD *)(pBuffer + 0x280) = 80; // rclSrc.bottom = 0x50\r\n *(DWORD *)(pBuffer + 0x284) = 4; // ngi.flFlags := DSDNG_PERPIXELALPHA (4)\r\n // 0x2A8: Palette Color Table\r\n *(DWORD *)(pBuffer + 0x2CC) = 100;\r\n // Fourth Struct\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 26 of 37\n\n*(size_t *)(pBuffer + 0x2D8) = AllocMemoryPage(0x10000);\r\n *(size_t *)(pBuffer + 0x2E0) = g_pRtlCopyUnicodeString;\r\n}\r\nAside from the added struct at the end of the buffer, which uses RtlCopyUnicodeString , the memory layout of\r\nthe objects inside the argument buffer was completely identical.\r\nAs we also labeled the different objects, we can see that the important part is the references from one object to\r\nanother, and not the location in which they are stored in the buffer itself. And yet, as if by magic, both exploits\r\nshare this memory layout.\r\nShared Constants\r\nOne more advantage of our recreated code POC for EpMe is that it enabled us to play around with various\r\nconstants used throughout the exploit, such as:\r\nGUI Window Name – Originally “h”.\r\nPoint locations – One of which was originally (100, 100).\r\nPrint Job ID – Originally 5.\r\nDriver Name / Document Name – A weird Unicode string is shown below.\r\nFigure 23: Weird Unicode string, later used as both the driver and document names.\r\nNeedless to say, none of the above were related to the vulnerability itself, and changing them didn’t affect the\r\nexploit at all. They are simply hardcoded constants chosen by the original developers of the exploit.\r\nThe interesting thing is, both EpMe and the Jian use the exact same hardcoded constants.  The fact that all of\r\nthese constants are shared between the two samples, even the weird looking Unicode string above, just shows that\r\none of the exploits was most probably copied from the other.\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 27 of 37\n\nFigure 24: Jian containing the same constants as the Equation Group exploit.\r\nIt is also possible that both parties were inspired by some unknown 3rd-party implementation that used all of these\r\nconstants. Alas, we failed to find any evidence for the existence of such a module. We must say that the odds of\r\nthis scenario are rather slim, especially when taking into account the weird-looking Unicode string.\r\nComparison Conclusion\r\nThe meaning of all of this is pretty simple:\r\nOne APT found the vulnerability and developed an exploit for it.\r\nAnother APT caught it and replicated it for their own use.\r\nWhile both of them deserve full credit for these remarkable achievements, we still want to find out who copied\r\nfrom whom. Time to attribute the exploit.\r\nExploit Attribution – Who was the original developer?\r\nWeird Looking Unicode String\r\nTo the eyes of a Western researcher, the Unicode string used for both the print driver name and the name of the\r\nprinted document looks foreign. And indeed, we can surely say that the string “屁썟“ doesn’t look like an obvious\r\nchoice for native English speakers.\r\nWe therefore consulted with colleagues around the world who are fluent in Chinese, Korean and Japanese, and\r\nasked for their opinion about these two symbols. The unanimous answer we received declared that there is no\r\nlanguage in which these symbols make sense. In each language, only one symbol has a meaning, and in any case\r\ndoesn’t make sense as part of a two-symbol phrase. We also checked for a meaning for the symbols created from\r\ninverting the order of the original bytes, and the result was the same.\r\nSo this is probably not a Chinese phrase used by the original developers of the exploit, but what is it?\r\nOur main hypothesis is based on the op-sec of the developers. Aside from names of DLL files and imported\r\nfunctions, it is very rare to find any string inside Equation Group samples. Even the name of the created window\r\nis only “h”, not exactly a long string that could be used by YARA rules so as to “sign” the binary. Faced with the\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 28 of 37\n\nneed to use a Unicode string that is surely longer than a single ASCII char string, we believe that the developers\r\nchose to use a pattern that matches their needs:\r\nUnicode-enough for the Windows API.\r\nNot a real string that might be traced by security researchers / solutions.\r\nIf we look closely at the chosen Unicode string, we can see that it actually makes more sense as an x64 assembly\r\nsnippet:\r\n41 5C pop r12 5F pop rdi C3 retn\r\n41 5C pop r12\r\n5F pop rdi\r\nC3 retn\r\nAs a matter of fact, this byte sequence is actually a very popular assembly snippet, found almost 150 times just in\r\nntdll.dll . Choosing such a popular assembly sequence for a “Unicode string” achieves all of the stated goals.\r\nFinally, the string can also be randomly generated and lacks any meaning whatsoever.\r\nWindow Name – “h”\r\nAs we just mentioned in the previous section, the GUI Window name used in both of the exploits is “h”. What\r\nmay seem like a randomly selected short string actually has quite a history behind it. Since the earliest PrivLib\r\nversion we managed to find, dated to 2008, all of the Equation Group exploits that we’ve analyzed used the exact\r\nsame string when a window name was needed. And this string was always “h”.\r\nAs a matter of fact, all of the 3 exploits included in the Houston Disk used the exact same global string when\r\ncreating their window:\r\nFigure 25: Global string used as the window name in all Houston Disk exploits.\r\nThis is one small indication that the original authors of the exploits could indeed have been Equation Group.\r\nHowever, as this artifact could also be just a coincidence, we now review additional aspects of the exploits.\r\nQuirks in Jian\r\nWindows 2000 support\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 29 of 37\n\nClose examination of the vulnerable function shows us that Windows 2000 was never vulnerable, as can be seen\r\nbelow:\r\nFigure 26: win32k.sys  from Windows 2000, just before the version reached End-of-Life.\r\nDespite Windows 2000 not being vulnerable, the UMPD code in Jian has special cases for Windows 2000, and\r\nWindows 2000 is part of the OS Version enum.\r\nFigure 27: Jian’s logic for supporting Windows 2000, inside the UMPD module.\r\nThe interesting issue is that according to the exploit configurations of Equation Group, EpMe doesn’t support\r\nWindows 2000. The minimal supported version is Windows XP, which aligns perfectly with the vulnerable\r\nWindows versions.\r\nThe fact that Equation Group built proper frameworks means that the UMPD module was shared between EpMe\r\nand EpMo. The variation between the exploits is based on exploit-specific logic that was implemented inside\r\nvirtual handlers that are invoked by the generic UMPD module. Because EpMo supports Windows 2000, so does\r\nthe UMPD module, which explains why EpMe might seem to support this version of Windows.\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 30 of 37\n\nFigure 28: Support for Windows 2000 in the shared UMPD module of EpMo and EpMe.\r\nIf we assume for a moment that APT31 was the original developer of the exploit for CVE-2017-0005, why would\r\nthey even attempt to add support for Windows 2000? Windows 2000 was never vulnerable in the first place. To be\r\nclear, we have no indication that the actors had their own version of the EpMo exploit or anything similar,\r\nmeaning we have no indication they ever needed such Windows 2000 support for any other tool / exploit.\r\nA far more probable scenario is that APT31 copied the exploit from Equation Group. It is likely that the threat\r\ngroup’s developers probably didn’t fully understand the limitations of the exploit, and so left the Windows 2000\r\nspecific code untouched. An old relic inherited from the EpMo exploit of which APT31 wasn’t even aware of or\r\ncare about.\r\nEnum value rotation\r\nFor some unknown reason, Jian contains the syscall definitions for a 32-bit exploit, on top of those needed for the\r\n64-bit exploit. While they aren’t used in practice, as the sample is 64-bit, they still give us a glimpse of how their\r\n32-bit exploit would have looked.\r\nWe can see that Jian’s 32-bit logic for each syscall ID once again matches that of the Equation Group sample, up\r\nto the level of adjusting some IDs based on the refined Service Pack Major Number.\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 31 of 37\n\nFigure 29: Jian’s logic for configuring 32-bit syscalls, using a refined Service Pack value.\r\nThe problem is, if we check the actual syscall numbers for Windows XP Service Pack 0 and Service Pack 1, we\r\ncan see that the condition for setting the value of SP_delta is flawed. It was correct for the Equation Group\r\nexploit, but is not correct here as APT31 modified the wSpMajor_refined value during the exploit’s initialization.\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 32 of 37\n\nFigure 30: Jian’s rotation of almost all wSpMajor values.\r\nThis value update is even stranger, as the Equation Group exploits have no mention of it whatsoever:\r\nFigure 31: Equation Group exploit setting the value of wSpMajor_refined .\r\nYou might ask, “Why would someone perform the above value rotation?”  The answer is actually rather simple.\r\nFrom our past analyses of several exploits attributed to Chinese-affiliated actors, we saw that the developers have\r\na habit of using the value 0 as a marker for “illegal value.” This can be clearly seen as all Service Pack values\r\nabove 6 are mapped back to the value 0, which marks them as “illegal.” This was also the case for the OS Version\r\nEnum, which was fully incremented by 1, making Windows NT use a value of 1 instead of 0, and reserving the\r\nsacred value of 0 to mark an error state.\r\nAnd yet, this time the developers used only a partial rotation for the Service Pack value, causing a collision with\r\nthe legitimate value for Service Pack 0 which for some reason they didn’t remap to “1”. This means that 0 is\r\nsimultaneously an illegal value that shouldn’t be supported, and a legitimate value that is crucial for configuring\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 33 of 37\n\nthe correct syscall numbers. The correct adjustment should probably have been to increment all values by 1, map\r\nthe illegal values to 0, and adjust the syscall check to wSpMajor_refined != 1 .\r\nOnce again, we see a weird pattern. Even under the premise that Chinese exploits should reserve the value 0 for\r\nillegal values, the code still looks odd. A developer writing this exploit from scratch would probably have just\r\nincremented the wSpMajor_refined value by 1, while remembering that in future checks Service Pack 0 is\r\nmarked with the value 1. Instead, as if not to break an existing piece of code, the syscall initialization still checks\r\nfor 0, and this value is simultaneously both valid and illegal at the same time.\r\nA more probable explanation is that the original code was the Equation Group version, and that the developers\r\naffiliated with Chinese attack groups were afraid to break it, thus going only half-way in remapping the values.\r\nThis fear of breaking the code also reflects on their poor understanding of the overall exploit.\r\nDebug string in the trigger function\r\nJian contains a debug string “int the overflow!!!” that can be found inside UMPD’s DrvBitBlt() , the callback\r\nresponsible for triggering the vulnerability.\r\nFigure 32: APT31 debug string inside the trigger function.\r\nAs we already established, the exploited vulnerability is not an “overflow” vulnerability. While the string may hint\r\nat either a “buffer overflow” or an “integer overflow”, none of them have any connection to the user-mode\r\ncallback design issue that was actually exploited.\r\nWhile it may just be a language barrier issue, this is yet another possible clue that the attackers behind Jian didn’t\r\nproperly understand the true nature of the exploited vulnerability.\r\nAttribution Conclusion\r\nTogether with additional artifacts that match Equation Group artifacts and habits shared between all exploits even\r\nas far back as 2008, we can safely conclude the following:\r\nEquation Group’s EpMe exploit, existing since at least 2013, is the original exploit for the vulnerability\r\nlater labeled CVE-2017-0005.\r\nSomewhere around 2014, APT31 managed to capture both the 32-bit and 64-bit samples of the EpMe\r\nEquation Group exploit.\r\nThey replicated them to construct “Jian”, and used this new version of the exploit alongside their unique\r\nmulti-staged packer.\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 34 of 37\n\nJian was caught by Lockheed Martin’s IRT and reported to Microsoft, which patched the vulnerability in\r\nMarch 2017 and labeled it CVE-2017-0005.\r\nTimeline\r\nBelow is a timeline of the events surrounding both exploit versions of what began as EpMe (Equation Group) and\r\nwas eventually patched by Microsoft as CVE-2017-0005 (APT31).\r\nFigure 33: Timeline of the events detailing the story of EpMe / Jian / CVE-2017-0005.\r\nIn greater detail:\r\n2008/2009 – Early Equation Group exploit tools: PrivLib / Houston Disk.\r\n2013 – DanderSpritz NtElevation exploits: ElEi, ErNi, EpMo, EpMe.\r\nOctober 27, 2014 – Early timestamp from the embedded PE – cloned EpMe.\r\nMay 6, 2015 – Multiple indicators that the complete APT31 tool was compiled in 2015.\r\nAugust 13, 2016 – Initial Shadow Brokers publication.\r\nJanuary 8, 2017 – Shadow Brokers leak a directory structure of their files, clearly indicating the possession\r\nof DanderSpritz and Eternal* exploits.\r\nFebruary 14, 2017 – Patch Tuesday is cancelled, merged with March’s fixes.\r\nMarch 14, 2017 – Patch Tuesday – Fixed CVE-2017-0005 and 1st round of critical Equation Group\r\nexploits included in the to be published “Lost in Translation” SB leak.\r\nMarch 27, 2017 – Microsoft publishes the blog on CVE-2017-0005 that was reported by Lockheed Martin,\r\nand attributed it to a Chinese APT (Zirconium / APT31).\r\nApril 14, 2017 – Lost in Translation leak is published.\r\nMay 9, 2017 – Patch Tuesday: Second round of Equation Group patches includes a silent fix for the EpMo\r\nEquation Group exploit.\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 35 of 37\n\nSummary\r\nWe began with analyzing “Jian”, the Chinese (APT31 / Zirconium) exploit for CVE-2017-0005, which was\r\nreported by Lockheed Martin’s Computer Incident Response Team. To our surprise, we found out that this APT31\r\nexploit is in fact a reconstructed version of an Equation Group exploit called “EpMe”. This means that an\r\nEquation Group exploit was eventually used by a Chinese-affiliated group, probably against American targets.\r\nThis isn’t the first documented case of a Chinese APT using an Equation Group 0-Day. The first was when APT3\r\nused their own version of EternalSynergy (called UPSynergy), after acquiring the Equation Group\r\nEternalRomance exploit. However, in the UPSynergy case, the consensus among our group of security researchers\r\nas well as in Symantec was that the Chinese exploit was reconstructed from captured network traffic.\r\nThe case of EpMe / Jian is different, as we clearly showed that Jian was constructed from the actual 32-bits and\r\n64-bits versions of the Equation Group exploit. This means that in this scenario, the Chinese APT acquired the\r\nexploit samples themselves, in all of their supported versions. Having dated APT31’s samples to 3 years prior to\r\nthe Shadow Broker’s “Lost in Translation” leak, our estimate is that these Equation Group exploit samples could\r\nhave been acquired by the Chinese APT in one of these ways:\r\nCaptured during an Equation Group network operation on a Chinese target.\r\nCaptured during an Equation Group operation on a 3rd-party network which was also monitored by the\r\nChinese APT.\r\nCaptured by the Chinese APT during an attack on Equation Group infrastructure.\r\nWhile reviewing the NtElevation exploits used in Equation Group’s DanderSpritz post-exploitation framework,\r\nwe found 4 Windows LPE exploits. The first two NtElevation exploits were font vulnerabilities that were\r\npreviously discussed as part of the Houston disk (an earlier sample attributed to Equation Group). In addition,\r\nEpMe (CVE-2017-0005) was mentioned and patched when Jian was caught, even if at that point in time the true\r\norigins of it weren’t yet known.\r\nFinally, although EpMo was indeed patched by Microsoft in May 2017, we couldn’t trace the CVE-ID that was\r\nassigned to the patched vulnerability. Not only that, to our knowledge, our publication is the first to even mention\r\nthe existence of this Equation Group exploit, even though it was publicly accessible on GitHub for the last 4 years.\r\nThese are our new additions to the attribution map:\r\nEpMe (CVE-2017-0005) – An Equation Group exploit that was cloned by APT31, thus causing CVE-2017-0005 to be attributed to the latter, instead of to Equation Group.\r\nEpMo – An additional Equation Group exploit that was never discussed before.\r\nJian – APT31’s cloned version of EpMe, which was caught-in-the-wild by Lockheed Martin’s IRT.\r\nCVE-2019-0803 – Attributed by multiple sources to a “Chinese State-Sponsored Actor.” We showed that it\r\nshares the same exploit loader (and tool API) as APT31’s Jian.\r\nAppendix – IOC Table\r\nJian – CVE-2017-0005:\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 36 of 37\n\nJian: AE512F13136774B4AAB79EBCC378927143BE77181E3B256E6F9940CE73696DE4\r\nCVE-2019-0803:\r\ntools.dll: 68A3710765DA1886F00E40F2D5E02776D224C77AEA114CD22C3A6204A7FAD363\r\n2008.dll: 279320EE5C3B2DA4364AFBACBE5286EC4EED9AB5E887D4E0B9AAB2EB618BC539\r\nEquation Group Exploits:\r\nNote: There are several variants of each exploit in the leak. The following are single examples of each exploit.\r\nHouston Disk: 868EB363F32BEACD8BCDC7A114E020D4CFE67913A15275F4E7493D87DB643FF2\r\nDanderSpritz – ElEi: C99FFACBA6D6689F7934E6E912E36EFCC4BD6A09C8A4D1E43BB27C3AFD131882\r\nDanderSpritz – ErNi: E4FBF75ABF928CD1C9073656A61755FD3F0C25DC2E7922FB5073E1F64E5E9161\r\nDanderSpritz – EpMo: 1537CAD1D2C5154E142AF775ED555D6168D528BBE40B31F451EFA92C9E4F02DE\r\nDanderSpritz – EpMe (CVE-2017-0005):\r\n634A80E37E4B32706AD1EA4A2FF414473618A8C42A369880DB7CC127C0EB705E\r\nSource: https://research.checkpoint.com/2021/the-story-of-jian/\r\nhttps://research.checkpoint.com/2021/the-story-of-jian/\r\nPage 37 of 37\n\nThe exploit 0803. uses a multi-staged packer, which appears identical to the one we saw used by CVE-2019-\nFigure 2: Comparison between the packer of CVe-2017-0005 (left) and that of CVe-2019-0803 (right).\n   Page 3 of 37   \n\nmemset(\u0026pBuffer[0x2D8], *(DWORD *)( pBuffer + 0, 0x10); 0x18) = 2; // 0x14 - 0x1C: flPal\n*(size_t *)(pBuffer + 0x80) = pBuffer + 0x2A8; // 0x80 -0x88: apalColor\n    Page 24 of 37",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"ETDA",
		"MITRE"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://research.checkpoint.com/2021/the-story-of-jian/"
	],
	"report_names": [
		"the-story-of-jian"
	],
	"threat_actors": [
		{
			"id": "b740943a-da51-4133-855b-df29822531ea",
			"created_at": "2022-10-25T15:50:23.604126Z",
			"updated_at": "2026-04-10T02:00:05.259593Z",
			"deleted_at": null,
			"main_name": "Equation",
			"aliases": [
				"Equation"
			],
			"source_name": "MITRE:Equation",
			"tools": null,
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "d90307b6-14a9-4d0b-9156-89e453d6eb13",
			"created_at": "2022-10-25T16:07:23.773944Z",
			"updated_at": "2026-04-10T02:00:04.746188Z",
			"deleted_at": null,
			"main_name": "Lead",
			"aliases": [
				"Casper",
				"TG-3279"
			],
			"source_name": "ETDA:Lead",
			"tools": [
				"Agentemis",
				"BleDoor",
				"Cobalt Strike",
				"CobaltStrike",
				"RbDoor",
				"RibDoor",
				"Winnti",
				"cobeacon"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "d4f7cf97-9c98-409c-8b95-b80d14c576a5",
			"created_at": "2022-10-25T16:07:24.561104Z",
			"updated_at": "2026-04-10T02:00:05.03343Z",
			"deleted_at": null,
			"main_name": "Shadow Brokers",
			"aliases": [],
			"source_name": "ETDA:Shadow Brokers",
			"tools": [],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "171b85f2-8f6f-46c0-92e0-c591f61ea167",
			"created_at": "2023-01-06T13:46:38.830188Z",
			"updated_at": "2026-04-10T02:00:03.114926Z",
			"deleted_at": null,
			"main_name": "The Shadow Brokers",
			"aliases": [
				"Shadow Brokers",
				"ShadowBrokers",
				"The ShadowBrokers",
				"TSB"
			],
			"source_name": "MISPGALAXY:The Shadow Brokers",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "aacd5cbc-604b-4b6e-9e58-ef96c5d1a784",
			"created_at": "2023-01-06T13:46:38.953463Z",
			"updated_at": "2026-04-10T02:00:03.159523Z",
			"deleted_at": null,
			"main_name": "APT31",
			"aliases": [
				"JUDGMENT PANDA",
				"BRONZE VINEWOOD",
				"Red keres",
				"Violet Typhoon",
				"TA412"
			],
			"source_name": "MISPGALAXY:APT31",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "13354d3f-3f40-44ec-b42a-3cda18809005",
			"created_at": "2022-10-25T15:50:23.275272Z",
			"updated_at": "2026-04-10T02:00:05.36519Z",
			"deleted_at": null,
			"main_name": "APT3",
			"aliases": [
				"APT3",
				"Gothic Panda",
				"Pirpi",
				"UPS Team",
				"Buckeye",
				"Threat Group-0110",
				"TG-0110"
			],
			"source_name": "MITRE:APT3",
			"tools": [
				"OSInfo",
				"schtasks",
				"PlugX",
				"LaZagne",
				"SHOTPUT",
				"RemoteCMD"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "761d1fb2-60e3-46f0-9f1c-c8a9715967d4",
			"created_at": "2023-01-06T13:46:38.269054Z",
			"updated_at": "2026-04-10T02:00:02.90356Z",
			"deleted_at": null,
			"main_name": "APT3",
			"aliases": [
				"GOTHIC PANDA",
				"TG-0110",
				"Buckeye",
				"Group 6",
				"Boyusec",
				"BORON",
				"BRONZE MAYFAIR",
				"Red Sylvan",
				"Brocade Typhoon"
			],
			"source_name": "MISPGALAXY:APT3",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "08623296-52be-4977-8622-50efda44e9cc",
			"created_at": "2023-01-06T13:46:38.549387Z",
			"updated_at": "2026-04-10T02:00:03.020003Z",
			"deleted_at": null,
			"main_name": "Equation Group",
			"aliases": [
				"Tilded Team",
				"EQGRP",
				"G0020"
			],
			"source_name": "MISPGALAXY:Equation Group",
			"tools": [
				"TripleFantasy",
				"GrayFish",
				"EquationLaser",
				"EquationDrug",
				"DoubleFantasy"
			],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "2d9fbbd7-e4c3-40e5-b751-27af27c8610b",
			"created_at": "2024-05-01T02:03:08.144214Z",
			"updated_at": "2026-04-10T02:00:03.674763Z",
			"deleted_at": null,
			"main_name": "PLATINUM COLONY",
			"aliases": [
				"Equation Group "
			],
			"source_name": "Secureworks:PLATINUM COLONY",
			"tools": [
				"DoubleFantasy",
				"EquationDrug",
				"EquationLaser",
				"Fanny",
				"GrayFish",
				"TripleFantasy"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "9e6186dd-9334-4aac-9957-98f022cd3871",
			"created_at": "2022-10-25T15:50:23.357398Z",
			"updated_at": "2026-04-10T02:00:05.368552Z",
			"deleted_at": null,
			"main_name": "ZIRCONIUM",
			"aliases": [
				"APT31",
				"Violet Typhoon"
			],
			"source_name": "MITRE:ZIRCONIUM",
			"tools": null,
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "e0fed6e6-a593-4041-80ef-694261825937",
			"created_at": "2022-10-25T16:07:23.593572Z",
			"updated_at": "2026-04-10T02:00:04.680752Z",
			"deleted_at": null,
			"main_name": "Equation Group",
			"aliases": [
				"APT-C-40",
				"G0020",
				"Platinum Colony",
				"Tilded Team"
			],
			"source_name": "ETDA:Equation Group",
			"tools": [
				"Bvp47",
				"DEMENTIAWHEEL",
				"DOUBLEFANTASY",
				"DanderSpritz",
				"DarkPulsar",
				"DoubleFantasy",
				"DoubleFeature",
				"DoublePulsar",
				"Duqu",
				"EQUATIONDRUG",
				"EQUATIONLASER",
				"EQUESTRE",
				"Flamer",
				"GRAYFISH",
				"GROK",
				"OddJob",
				"Plexor",
				"Prax",
				"Regin",
				"Skywiper",
				"TRIPLEFANTASY",
				"Tilded",
				"UNITEDRAKE",
				"WarriorPride",
				"sKyWIper"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "cf826655-5fcb-4331-bdc5-5ef267db9d3c",
			"created_at": "2025-08-07T02:03:24.631402Z",
			"updated_at": "2026-04-10T02:00:03.608938Z",
			"deleted_at": null,
			"main_name": "BRONZE MAYFAIR",
			"aliases": [
				"APT3 ",
				"Gothic Panda ",
				"Pirpi",
				"TG-0110 ",
				"UPSTeam"
			],
			"source_name": "Secureworks:BRONZE MAYFAIR",
			"tools": [
				"Cookiecutter",
				"HUC Proxy Malware (Htran)",
				"Pirpi",
				"PlugX",
				"SplitVPN",
				"UPS",
				"ctt",
				"ctx"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "3fff98c9-ad02-401d-9d4b-f78b5b634f31",
			"created_at": "2023-01-06T13:46:38.376868Z",
			"updated_at": "2026-04-10T02:00:02.949077Z",
			"deleted_at": null,
			"main_name": "Cleaver",
			"aliases": [
				"G0003",
				"Operation Cleaver",
				"Op Cleaver",
				"Tarh Andishan",
				"Alibaba",
				"TG-2889",
				"Cobalt Gypsy"
			],
			"source_name": "MISPGALAXY:Cleaver",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "74d9dada-0106-414a-8bb9-b0d527db7756",
			"created_at": "2025-08-07T02:03:24.69718Z",
			"updated_at": "2026-04-10T02:00:03.733346Z",
			"deleted_at": null,
			"main_name": "BRONZE VINEWOOD",
			"aliases": [
				"APT31 ",
				"BRONZE EXPRESS ",
				"Judgment Panda ",
				"Red Keres",
				"TA412",
				"VINEWOOD ",
				"Violet Typhoon ",
				"ZIRCONIUM "
			],
			"source_name": "Secureworks:BRONZE VINEWOOD",
			"tools": [
				"DropboxAES RAT",
				"HanaLoader",
				"Metasploit",
				"Mimikatz",
				"Reverse ICMP shell",
				"Trochilus"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "dc7ee503-9494-4fb6-a678-440c68fd31d8",
			"created_at": "2022-10-25T16:07:23.349177Z",
			"updated_at": "2026-04-10T02:00:04.552639Z",
			"deleted_at": null,
			"main_name": "APT 31",
			"aliases": [
				"APT 31",
				"Bronze Vinewood",
				"G0128",
				"Judgment Panda",
				"Red Keres",
				"RedBravo",
				"TA412",
				"Violet Typhoon",
				"Zirconium"
			],
			"source_name": "ETDA:APT 31",
			"tools": [
				"9002 RAT",
				"Agent.dhwf",
				"AngryRebel",
				"CHINACHOPPER",
				"China Chopper",
				"Destroy RAT",
				"DestroyRAT",
				"Farfli",
				"Gh0st RAT",
				"Ghost RAT",
				"GrewApacha",
				"HOMEUNIX",
				"HiKit",
				"HidraQ",
				"Homux",
				"Hydraq",
				"Kaba",
				"Korplug",
				"McRAT",
				"MdmBot",
				"Moudour",
				"Mydoor",
				"PCRat",
				"PlugX",
				"RedDelta",
				"Roarur",
				"Sakula",
				"Sakula RAT",
				"Sakurel",
				"SinoChopper",
				"Sogu",
				"TIGERPLUG",
				"TVT",
				"Thoper",
				"Trochilus RAT",
				"Xamtrav"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "06f622cb-3a78-49cf-9a4c-a6007a69325f",
			"created_at": "2022-10-25T16:07:23.315239Z",
			"updated_at": "2026-04-10T02:00:04.537826Z",
			"deleted_at": null,
			"main_name": "APT 3",
			"aliases": [
				"APT 3",
				"Boron",
				"Brocade Typhoon",
				"Bronze Mayfair",
				"Buckeye",
				"G0022",
				"Gothic Panda",
				"Group 6",
				"Operation Clandestine Fox",
				"Operation Clandestine Fox, Part Deux",
				"Operation Clandestine Wolf",
				"Operation Double Tap",
				"Red Sylvan",
				"TG-0110",
				"UPS Team"
			],
			"source_name": "ETDA:APT 3",
			"tools": [
				"APT3 Keylogger",
				"Agent.dhwf",
				"BKDR_HUPIGON",
				"Backdoor.APT.CookieCutter",
				"Badey",
				"Bemstour",
				"CookieCutter",
				"Destroy RAT",
				"DestroyRAT",
				"DoublePulsar",
				"EXL",
				"EternalBlue",
				"HTran",
				"HUC Packet Transmit Tool",
				"Hupigon",
				"Hupigon RAT",
				"Kaba",
				"Korplug",
				"LaZagne",
				"MFC Huner",
				"OSInfo",
				"Pirpi",
				"PlugX",
				"RedDelta",
				"RemoteCMD",
				"SHOTPUT",
				"Sogu",
				"TIGERPLUG",
				"TTCalc",
				"TVT",
				"Thoper",
				"Xamtrav",
				"remotecmd",
				"shareip",
				"w32times"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775434207,
	"ts_updated_at": 1775826718,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/9839a714808e02dfe206f20b5ad15a569ea2165b.pdf",
		"text": "https://archive.orkl.eu/9839a714808e02dfe206f20b5ad15a569ea2165b.txt",
		"img": "https://archive.orkl.eu/9839a714808e02dfe206f20b5ad15a569ea2165b.jpg"
	}
}