{
	"id": "e54f9189-06c3-4be3-b08d-4c5795980377",
	"created_at": "2026-04-06T00:10:50.318893Z",
	"updated_at": "2026-04-10T03:35:45.979704Z",
	"deleted_at": null,
	"sha1_hash": "158121f641ac2c63b1083387974d04de80c2dc5d",
	"title": "A Deep Dive into DoubleFeature, Equation Group’s Post-Exploitation Dashboard",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 208049,
	"plain_text": "A Deep Dive into DoubleFeature, Equation Group’s Post-Exploitation Dashboard\r\nBy itayc\r\nPublished: 2021-12-27 · Archived: 2026-04-05 20:42:38 UTC\r\nEarlier this year, Check Point Research published the story of “Jian” — an exploit used by Chinese threat actor\r\nAPT31 which was “heavily inspired by” an almost-identical exploit used by the Equation Group, made publicly\r\nknown by the Shadow Brokers leak. The spicy part of the story was that Jian had been roaming in the wild and\r\nabusing Equation Group ingenuity to compromise systems before it was cool — as early as 2014, a full two years\r\nbefore the Shadow Brokers leaks made the original exploit public. Evidently, the authors of Jian had acquired\r\nearly access to it some other way.\r\nWhile this discovery had undoubtedly added an extra tinge of paranoia to an already complicated affair, we were\r\nstill left with some questions of our own. Chief among those questions was, “how come that little nugget was still\r\njust lying there for us to find, a full 4 years after the fact?”. In information security terms, 4 years is an eternity.\r\nWhat else would we find, if we dug deep enough? Have the Russians actually had access to these tools back in\r\n2013? The Iranians in 2006? The Babylonians in 700 BC?\r\nFirst of all, we are glad to say the answer is (probably) no. Best that we can tell, APT31’s apparent early access to\r\nthe leaked exploit was the exception, not the rule. This makes for a less exciting headline, but should help all of us\r\nsleep better at night. During our research, we combed over the DanderSpritz framework — a major part of the\r\n“Lost in Translation” leak — in excruciating technical detail; and we present our findings here, with a pedagogical\r\nfocus on its DoubleFeature logging tool which provides a unique view into the rest of the framework.\r\nWhat is DanderSpritz?\r\nDanderSpritz is a full-featured post-exploitation framework used by the Equation Group. This framework was\r\nusually leveraged after exploiting a machine and deploying the PeddleCheap “implant”. DanderSpritz is very\r\nmodular and contains a wide variety of tools for persistence, reconnaissance, lateral movement, bypassing\r\nAntivirus engines, and other such shady activities. It was leaked by The Shadow Brokers on April 14th, 2017 as\r\npart of the “Lost in Translation” leak.\r\nDanderSpritz Structure and Execution Flow\r\nDanderSpritz logic can be found effectively split in two inside the directory tree of the “Lost in Translation” leak:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 1 of 33\n\nEnlighterJS 3 Syntax Highlighter\r\nleak root\r\n----(...)\r\n----windows\r\n--------bin\r\n--------exploits\r\n--------fuzzbunch\r\n--------implants\r\n--------payloads\r\n--------resources\r\n--------specials\r\n--------touches\r\n----(...)\r\nleak root ----(...) ----windows --------bin --------exploits --------fuzzbunch --------implants --------payloads --------\r\nresources --------specials --------touches ----(...)\r\nleak root\r\n----(...)\r\n----windows\r\n--------bin\r\n--------exploits\r\n--------fuzzbunch\r\n--------implants\r\n--------payloads\r\n--------resources\r\n--------specials\r\n--------touches\r\n----(...)\r\nThe core functionality of DanderSpritz is contained in the file DszLpCore.exe , which can be found at\r\nwindows/bin . The framework’s plugins and complex components, including DoubleFeature which we will later\r\ndiscuss in detail, can be found under windows/resources . fuzzbunch , implants , and the other directories\r\nunder windows contain modules separate from DanderSpritz which are used for exploitation itself, taking control\r\nof victim systems, initial data gathering and so on; these are all beyond the scope of this publication.\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 2 of 33\n\nThe basic logical unit inside DanderSpritz is what we dub a “plugin”. These reside in windows/resources ; there\r\nare about a dozen of them and they have a very specific directory structure, seen in the diagram below (though\r\nsome of these subdirectories are optional).\r\nThere are also some other directories under windows\\\\resources that are not plugins (and therefore do not have\r\nthis structure), and instead contain miscellaneous auxiliary scripts (such as validation scripts to verify the\r\naffiliation of victim machines).\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nplugin root\r\n----aliases\r\n----commands\r\n----modules\r\n--------descriptions\r\n--------files-dsz\r\n------------x86\r\n----------------\u003cmodule_name\u003e\r\n----------------\u003cmodule_name\u003e\r\n----------------(...)\r\n------------x64\r\n----------------\u003cmodule_name\u003e\r\n----------------\u003cmodule_name\u003e\r\n----------------(...)\r\n------------(...)\r\n----payloads\r\n--------descriptions\r\n----pylp\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 3 of 33\n\n----pyscripts\r\n----scripts\r\n----tools\r\n----uploads\r\n----version\r\nplugin root ----aliases ----commands ----modules --------descriptions --------files-dsz ------------x86 ----------------\r\n\u003cmodule_name\u003e ----------------\u003cmodule_name\u003e ----------------(...) ------------x64 ----------------\u003cmodule_name\u003e ----\r\n------------\u003cmodule_name\u003e ----------------(...) ------------(...) ----payloads --------descriptions ----pylp ----pyscripts --\r\n--scripts ----tools ----uploads ----version\r\nplugin root\r\n----aliases\r\n----commands\r\n----modules\r\n--------descriptions\r\n--------files-dsz\r\n------------x86\r\n----------------\u003cmodule_name\u003e\r\n----------------\u003cmodule_name\u003e\r\n----------------(...)\r\n------------x64\r\n----------------\u003cmodule_name\u003e\r\n----------------\u003cmodule_name\u003e\r\n----------------(...)\r\n------------(...)\r\n----payloads\r\n--------descriptions\r\n----pylp\r\n----pyscripts\r\n----scripts\r\n----tools\r\n----uploads\r\n----version\r\nAliases and Commands – These both contain XML files that declare support for “aliases” and\r\n“commands”, respectively, which serve a similar function. When a user of the DanderSpritz framework\r\nissues a shell command (in the general sense of the word – in the same way that a Bash user would run\r\nls , top and so on), DanderSpritz will iterate over every plugin, check these XMLs and verify whether\r\nthey declare support for the shell command the user typed. If the command appears under Aliases it will\r\nbe simply mapped to an existing script; a Command will typically, under the hood, invoke the inner logic of\r\nthe plugin in some way. This effectively means that a user of DanderSpritz can run many different shell\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 4 of 33\n\ncommands to achieve various results without being aware that behind the scenes, the same plugin handled\r\nthe execution of all these requests. Under Commands (but not Aliases ), additionally to the XML, there\r\nis an XSL file which specifies a format for the command’s output as returned to the DanderSpritz user\r\n(XSL is a markup language for specifying presentation style for XML data — it is to XML as CSS is to\r\nHTML).\r\nModules – Most of the plugin logic is contained in this directory. As can be inferred from the name, the\r\nlogic is further divided into smaller “modules” of functionality. The descriptions subdirectory contains\r\nan XML file which is a sort of “manifest”. It details what scripts and binaries should be run on the victim\r\nmachine and on the “LP” (“Listening Post” — an attacker-controlled machine remotely monitoring the\r\nvictim). It also lists the plugin’s dependencies on other modules, its interface data, what computing\r\narchitectures it supports, and whether it should run on the victim machine or on the LP. A few plugins also\r\ncontain a payloads directory with a similar function.\r\nPyLp – Contains XML files for formatting incoming information exfiltrated from the victim machine. For\r\nevery “message type” (kind of exfiltrated information), an XML specifies a Python script that formats the\r\ndata for convenient display. This formatting script resides in the PyScripts directory.\r\nPyScripts – All the miscellaneous Python scripts used by the framework are in this directory.\r\nScripts – This directory also contains miscellaneous scripts, written in some sigil-heavy scripting\r\nlanguage that might have seemed reasonable to use before Python’s rise to prominence.\r\nTools – A grab-bag of self-contained material (PEs, DLLs, scripts, JARs, text files, …) which the authors\r\nfigured they’d rather just include and invoke as-is.\r\nUploads – stand-alone binaries which are pushed to the victim system by the plugin.\r\nVersion – contains an XML file containing the plugin version.\r\nBelow we detail the typical control flow when a plugin alias or command is invoked.\r\n1. The DanderSpritz user types a shell command in the DanderSpritz user interface which is, behind the\r\nscenes, implemented using that specific plugin.\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 5 of 33\n\nFigure 1: The User Interface of DanderSpritz and its shell commands.\r\n1. DanderSpritz’s main logic iterates over the resources directory, looking at one plugin directory after the\r\nother. For each plugin directory, DanderSpritz looks at the aliases subdirectory and the commands\r\nsubdirectory, and scrutinizes the XML file within, looking for a declared exported functionality matching\r\nthe shell command. The match is found, and the matched XML element specifies a path inside the plugin’s\r\npyscripts directory.\r\n2. DanderSpritz computes the fully qualified path of the invoked script (by appending the path specified in\r\nthe matched XML element to the path of the plugin’s pyscripts directory) and executes the file. This is\r\nwhere the user interface of the invoked shell command is displayed, and the plugin can be said to be\r\nproperly running. (Ideally, this Python script is just UI and glue, while the core functionality that interacts\r\nwith the victim machine resides in a separate remote component; but this appealing abstraction is broken\r\nsomewhat in the DoubleFeature plugin which we will dig into later.)\r\n3. Now the attacker gets to stare at the UI of the tool they invoked for as long as they like. Eventually, they\r\nwill probably want to invoke some functionality through this UI. Depending on the functionality chosen,\r\nthe Python UI constructs a Remote Procedure Call (taken from raw hardcoded data inside the Python — no\r\nXMLs here). It sends this RPC to the DanderSpritz component on the victim machine. This component on\r\nthe victim side then executes the call and returns a result. In this way, RPCs are used as the API which the\r\ncomponent on the LP accesses to perform actions on the victim machine (such as collecting screenshots or\r\nrecording voice). This API is decoupled from the way these actions are actually implemented on the victim\r\ncomponent side.\r\n4. The RPC returns with the precious information required by the attacker (or maybe just a terse “action\r\naccomplished”). The Python UI consults the XML in the Plugin’s PyLP directory that matches the result’s\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 6 of 33\n\nmessage type. This XML specifies how to display the returned information on the LP end, and the UI does\r\nso.\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 7 of 33\n\nFigure 2: Example of XML files (both LP and Target) of a specific command.\r\nFocus on DoubleFeature\r\nTo better understand the above structure and flow, we focused our research on a component of DanderSpritz\r\nnamed Doublefeature (or Df for short). According to its own internal documentation, this plugin “Generates a\r\nlog \u0026 report about the types of tools that could be deployed on the target”; a lot of the framework tools, in their\r\nown internal documentation, make the chilling claim that DoubleFeature is the only way to confirm their existence\r\non a compromised system. After some pause, we figured that at least this means DoubleFeature could be used as a\r\nsort of Rosetta Stone for better understanding DanderSpritz modules, and systems compromised by them.\r\nDoubleFeature effectively, well, doubles as a diagnostic tool for victim machines carrying DanderSpritz — It’s an\r\nincident response team’s pipe dream.\r\nFigure 3: Code of strangeland.py referring to the fact that the only way to confirm is with DF.\r\nIn a perfect world, we wouldn’t need to explain anything about the inner workings of DoubleFeature under the\r\nhood. After all, we just went through a whole section on how DanderSpritz plugins in general work under the\r\nhood; and DoubleFeature is one such plugin; therefore, everything above about RPC calls whose return values are\r\nformatted per an XSL specification should still hold — right?\r\nUnfortunately, because of DoubleFeature’s unique function as a logging module, it collects a large amount of data\r\nof various types. RPC return values and XSL markup are just not suited to transfer and display information on this\r\nscale. An unexpected corner use case emerged, an ad-hoc solution was created specifically for it, and the “pretty\r\nand elegant framework for everything” vision was quietly taken to the backyard and shot. It’s a tale as old as time.\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 8 of 33\n\nFigure 4: DoubleFeature main menu\r\nDoubleFeature’s PyScripts directory contains its Python UI interface (doublefeature.py) — but when the\r\nattacker chooses an option from the UI menu, behind the scenes instead of simply issuing an RPC, the script\r\ntransmogrifies a “template” DLL, DoubleFeatureDll.dll.unfinalized , that resides in the plugin’s uploads\r\ndirectory. The Python invokes the external tool AddResource.exe , found in the plugin’s tools directory, to\r\nimplant a resource into the already-compiled DLL and make it ready to detonate, under a new name:\r\nDoubleFeatureDll.dll.configured . The exact command run is:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\n*local run -redirect command \"\u003cg_dfconfiguretool\u003e cmpf 6 1104 \u003cconfigureddllpath\u003e \u003cg_dfrscfile\u003e\"*\"\r\n*local run -redirect command \"\u003cg_dfconfiguretool\u003e cmpf 6 1104 \u003cconfigureddllpath\u003e \u003cg_dfrscfile\u003e\"*\"\r\n*localrun-redirect command\"\u003cg_dfconfiguretool\u003ecmpf61104\u003cconfigureddllpath\u003e\u003cg_dfrscfile\u003e\"*\"\r\nThe flags used by the command are explained below.\r\nc (compressed) – Zlib compress the data\r\nm (munge) = Obfuscate the resource by XORing with pseudo-random bytes. The bytes are generated by\r\nrunning a PRNG (a 32-bit LCG, if you insist) and using the execution timestamp as the seed; to allow\r\nrecovery, the seed is prepended to the obfuscated resource.\r\np (place) = Place the resource into a homebrew resource directory (more detail about this later).\r\nf (finalize) = Finalize the proprietary resource directory.\r\n6 = Type of resource (in this case, the enum value 6 translates to RT_STRING , a string-table entry)\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 9 of 33\n\n1104 = Name of the resource.\r\nAfter the main plugin DLL **is endowed with this new resource, the Python UI uses the DanderSpritz dllload\r\nshell command to load it on the victim machine:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\ndllload -ordinal 1 -library \u003cconfiguredDllPath\u003e\r\ndllload -ordinal 1 -library \u003cconfiguredDllPath\u003e\r\ndllload -ordinal 1 -library \u003cconfiguredDllPath\u003e\r\nOnce the DLL on the victim side finishes running and writing the report to the log file on the victim machine, the\r\nPython UI exfiltrates the log file back to the attacker machine using the following DanderSpritz shell command:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nforeground get \u003clog_file_name\u003e -name DFReport\r\nforeground get \u003clog_file_name\u003e -name DFReport\r\nforegroundget\u003clog_file_name\u003e-nameDFReport\r\nWhile (as mentioned above) most output of DanderSpritz commands is viewed according to XSL specifications,\r\nthe output of DoubleFeature is too large and varied for this approach to be feasible. Instead, the attacker typically\r\nviews the log file using a specialized program written for this purpose — DoubleFeatureReader.exe , which can\r\nbe available in the plugin’s tools directory.\r\nDoubleFeature writes all its log data to a debug log file named ~yh56816.tmp ; this artifact was covered in\r\nKaspersky’s 2015 report on the remote access tool dubbed “EquationDrug” (more on that below). This log file is\r\nencrypted using the AES algorithm. Unless the user changes the key manually, the default one used is\r\nbadc0deb33ff00d (possibly to spite vegan developers).\r\nMain DLL of DoubleFeature\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 10 of 33\n\nWhen the patched DLL ( DoubleFeatureDll.dll.configured ) is first loaded on the victim machine, it looks for\r\na resource named “106” in a homebrew resource directory. This directory resides in the “.text” section right after\r\nthe actual code, and the DLL is able to find it by searching for a distinct magic value. The homebrew resource\r\ndirectory has the following structure:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\n**Resource_Directory_struct**:\r\nword word_0\r\nword num_of_resources\r\nResource_data[] resource_array\r\ndword resource_directory_size\r\ndword magic_hash\r\n**Resource_data**:\r\nword resource_type\r\nword resource_num\r\ndword offset_from_directory_start\r\ndword resource_size\r\n**Resource_Directory_struct**: word word_0 word num_of_resources Resource_data[] resource_array dword\r\nresource_directory_size dword magic_hash **Resource_data**: word resource_type word resource_num dword\r\noffset_from_directory_start dword resource_size\r\n**Resource_Directory_struct**:\r\nword word_0\r\nword num_of_resources\r\nResource_data[] resource_array\r\n dword resource_directory_size\r\n dword magic_hash\r\n**Resource_data**:\r\nword resource_type\r\nword resource_num\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 11 of 33\n\ndword offset_from_directory_start\r\ndword resource_size\r\nThis resource (which is distinct from the resource earlier grafted onto the DLL by invoking AddResource.exe ) is\r\nencrypted at rest, and in order to be used, it must be decrypted and decompressed. The (equivalent Python of the)\r\nlogic is below.\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\ndef decrypt_decompress_resource(buf, seed):\r\noutput = bytearray(b'')\r\nfor i in range(len(buf)):\r\nseed = (0xDD483B8F - (0x6033A96D * seed) % (2**32)) % (2**32)\r\ncur_xor_key = seed \u003e\u003e 8\r\noutput.append((cur_xor_key \u0026 0xff) ^ (buf[i] \u0026 0xff))\r\nuncompressed_resource = zlib.decompress(output[4:])\r\nreturn uncompressed_resource\r\ndef decrypt_decompress_resource(buf, seed): output = bytearray(b'') for i in range(len(buf)): seed =\r\n(0xDD483B8F - (0x6033A96D * seed) % (2**32)) % (2**32) cur_xor_key = seed \u003e\u003e 8\r\noutput.append((cur_xor_key \u0026 0xff) ^ (buf[i] \u0026 0xff)) uncompressed_resource = zlib.decompress(output[4:])\r\nreturn uncompressed_resource\r\ndef decrypt_decompress_resource(buf, seed):\r\noutput = bytearray(b'')\r\nfor i in range(len(buf)):\r\nseed = (0xDD483B8F - (0x6033A96D * seed) % (2**32)) % (2**32)\r\ncur_xor_key = seed \u003e\u003e 8\r\noutput.append((cur_xor_key \u0026 0xff) ^ (buf[i] \u0026 0xff))\r\n uncompressed_resource = zlib.decompress(output[4:])\r\nreturn uncompressed_resource\r\nResource 106, once decompressed, is a driver called hidsvc.sys. It is loaded into the kernel by invoking the EpMe\r\nexploit of CVE-2017-0005 (this is the very same exploit that had its logic find its way into the Jian exploit\r\nsomehow). After the driver is loaded, the DLL begins communicating with it using DeviceIoControl s. The most\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 12 of 33\n\ninteresting IOControlCode supported by the driver is 0x85892408, which allows user-mode code to directly\r\ninvoke kernel functions by simply specifying the function name and the arguments. The driver expects incoming\r\nmessages with this code to be bundled with the following struct:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\n**ControlCode_input_buffer**:\r\ndword export_func_hash\r\ndword num_of_arguments_bufs\r\ndword [0x20*num] arguments_buf\r\n**ControlCode_input_buffer**: dword export_func_hash dword num_of_arguments_bufs dword [0x20*num]\r\narguments_buf\r\n**ControlCode_input_buffer**:\r\ndword export_func_hash\r\ndword num_of_arguments_bufs\r\ndword [0x20*num] arguments_buf\r\nMost arguments are self-explanatory, given the purpose of this control code. The one detail that bears explanation\r\nis the export_func_hash – the function name is not passed explicitly, but instead a checksum of it. Upon\r\nreceiving the struct, the driver iterates over every exported function of ntoskernl.exe computes the resulting\r\nchecksum and compares the result with the provided export_func_hash . Once a match is found, the driver\r\nconcludes it has found the correct function. This is a standard method to obfuscate API calls, seen in many other\r\npieces of malware.\r\nThe checksum computation logic can be seen below.\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\ndef checksum(name, len):\r\nval = 0\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 13 of 33\n\nfor i in range(1, len+1):\r\ntemp = (0x1A6B8613 * i) % (2**32)\r\nval = val ^ (temp * ord(name[i-1]) % (2**32))\r\nreturn val\r\ndef checksum(name, len): val = 0 for i in range(1, len+1): temp = (0x1A6B8613 * i) % (2**32) val = val ^ (temp\r\n* ord(name[i-1]) % (2**32)) return val\r\ndef checksum(name, len):\r\nval = 0\r\nfor i in range(1, len+1):\r\ntemp = (0x1A6B8613 * i) % (2**32)\r\nval = val ^ (temp * ord(name[i-1]) % (2**32))\r\nreturn val\r\nSome sample checksum values:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nZwQueryInformationProcess 0x62A0A841\r\nZwQueryObject 0xB7241E54\r\nZwOpenEvent 0xDE2837FA\r\nZwSetEvent 0x662E22E1\r\nZwOpenKey 0xA20F6388\r\nZwFsControlFile 0x407CC9F5\r\nZwQueryVolumeInformationFile 0x161C4B69\r\nZwQueryInformationFile 0xC0E4A30A\r\nZwSetInformationFile 0x535ACCEA\r\nZwReadFile 0xB8075119\r\nZwWriteFile 0xBAE70F4B\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 14 of 33\n\nZwClose 0x69023181\r\nZwCreateFile 0x01862336\r\nZwQueryDirectoryFile 0x41483801\r\nZwQuerySystemInformation 0x178B07C8\r\nZwCreateKey 0x01862336\r\nZwDeleteKey 0x2C9F7CA8\r\nZwQueryKey 0xBDD598E2\r\nZwEnumerateKey 0x8D3E3E7A\r\nZwSetValueKey 0x90A71127\r\nZwEnumerateValueKey 0x040F9817\r\nZwQueryValueKey 0xF655B34B\r\nZwDeleteValueKey 0x2A1BF746\r\nZwWaitForSingleObject 0x86324d14\r\nZwQueryInformationProcess 0x62A0A841 ZwQueryObject 0xB7241E54 ZwOpenEvent 0xDE2837FA\r\nZwSetEvent 0x662E22E1 ZwOpenKey 0xA20F6388 ZwFsControlFile 0x407CC9F5\r\nZwQueryVolumeInformationFile 0x161C4B69 ZwQueryInformationFile 0xC0E4A30A ZwSetInformationFile\r\n0x535ACCEA ZwReadFile 0xB8075119 ZwWriteFile 0xBAE70F4B ZwClose 0x69023181 ZwCreateFile\r\n0x01862336 ZwQueryDirectoryFile 0x41483801 ZwQuerySystemInformation 0x178B07C8 ZwCreateKey\r\n0x01862336 ZwDeleteKey 0x2C9F7CA8 ZwQueryKey 0xBDD598E2 ZwEnumerateKey 0x8D3E3E7A\r\nZwSetValueKey 0x90A71127 ZwEnumerateValueKey 0x040F9817 ZwQueryValueKey 0xF655B34B\r\nZwDeleteValueKey 0x2A1BF746 ZwWaitForSingleObject 0x86324d14\r\nZwQueryInformationProcess 0x62A0A841\r\nZwQueryObject 0xB7241E54\r\nZwOpenEvent 0xDE2837FA\r\nZwSetEvent 0x662E22E1\r\nZwOpenKey 0xA20F6388\r\nZwFsControlFile 0x407CC9F5\r\nZwQueryVolumeInformationFile 0x161C4B69\r\nZwQueryInformationFile 0xC0E4A30A\r\nZwSetInformationFile 0x535ACCEA\r\nZwReadFile 0xB8075119\r\nZwWriteFile 0xBAE70F4B\r\nZwClose 0x69023181\r\nZwCreateFile 0x01862336\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 15 of 33\n\nZwQueryDirectoryFile 0x41483801\r\nZwQuerySystemInformation 0x178B07C8\r\nZwCreateKey 0x01862336\r\nZwDeleteKey 0x2C9F7CA8\r\nZwQueryKey 0xBDD598E2\r\nZwEnumerateKey 0x8D3E3E7A\r\nZwSetValueKey 0x90A71127\r\nZwEnumerateValueKey 0x040F9817\r\nZwQueryValueKey 0xF655B34B\r\nZwDeleteValueKey 0x2A1BF746\r\nZwWaitForSingleObject 0x86324d14\r\nThis isn’t the only aspect of DoubleFeature (and other Equation Group tools) to make life difficult for forensic\r\nanalysts. The strings used in DoubleFeature are decrypted — that alone is very standard — but they are decrypted\r\non-demand per function, which is somewhat more frustrating than usual, and they are re-encrypted once function\r\nexecution completes, which is much more frustrating than usual. DoubleFeature also supports additional\r\nobfuscation methods, such as a simple substitution cipher:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\ndef deobfuscate_strings(enc_strings):\r\nfor enc_string in enc_strings:\r\nreplace_buffer = [ 0x37, 0x3B, 0x5D, 0x4B, 0x45, 0x44, 0x3C, 0x5C, 0x7B, 0x4F,\r\n0x74, 0x41, 0x7D, 0x7E, 0x35, 0x46, 0x23, 0x2B, 0x72, 0x71,\r\n0x40, 0x78, 0x4C, 0x55, 0x39, 0x56, 0x30, 0x5F, 0x50, 0x2C,\r\n0x29, 0x2D, 0x79, 0x59, 0x3A, 0x57, 0x53, 0x69, 0x77, 0x63,\r\n0x26, 0x70, 0x2A, 0x76, 0x60, 0x3D, 0x33, 0x31, 0x22, 0x47,\r\n0x49, 0x4E, 0x75, 0x58, 0x34, 0x68, 0x6B, 0x20, 0x67, 0x32,\r\n0x27, 0x65, 0x51, 0x28, 0x5B, 0x2E, 0x7C, 0x6F, 0x24, 0x4A,\r\n0x3E, 0x64, 0x73, 0x6D, 0x7A, 0x3F, 0x6A, 0x54, 0x62, 0x42,\r\n0x6C, 0x48, 0x2F, 0x25, 0x43, 0x52, 0x21, 0x66, 0x38, 0x5A,\r\n0x61, 0x5E, 0x36, 0x4D, 0x6E, 0x00]\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 16 of 33\n\ndec_string = ''\r\nfor i in range(len(enc_string)):\r\ncur_place = ord(enc_string[i]) - 0x20\r\ndec_string += chr (replace_b\r\nuffer[cur_place])\r\nprint(dec_string)\r\ndef deobfuscate_strings(enc_strings): for enc_string in enc_strings: replace_buffer = [ 0x37, 0x3B, 0x5D, 0x4B,\r\n0x45, 0x44, 0x3C, 0x5C, 0x7B, 0x4F, 0x74, 0x41, 0x7D, 0x7E, 0x35, 0x46, 0x23, 0x2B, 0x72, 0x71, 0x40, 0x78,\r\n0x4C, 0x55, 0x39, 0x56, 0x30, 0x5F, 0x50, 0x2C, 0x29, 0x2D, 0x79, 0x59, 0x3A, 0x57, 0x53, 0x69, 0x77, 0x63,\r\n0x26, 0x70, 0x2A, 0x76, 0x60, 0x3D, 0x33, 0x31, 0x22, 0x47, 0x49, 0x4E, 0x75, 0x58, 0x34, 0x68, 0x6B, 0x20,\r\n0x67, 0x32, 0x27, 0x65, 0x51, 0x28, 0x5B, 0x2E, 0x7C, 0x6F, 0x24, 0x4A, 0x3E, 0x64, 0x73, 0x6D, 0x7A, 0x3F,\r\n0x6A, 0x54, 0x62, 0x42, 0x6C, 0x48, 0x2F, 0x25, 0x43, 0x52, 0x21, 0x66, 0x38, 0x5A, 0x61, 0x5E, 0x36, 0x4D,\r\n0x6E, 0x00] dec_string = '' for i in range(len(enc_string)): cur_place = ord(enc_string[i]) - 0x20 dec_string += chr\r\n(replace_b uffer[cur_place]) print(dec_string)\r\ndef deobfuscate_strings(enc_strings):\r\nfor enc_string in enc_strings:\r\nreplace_buffer = [ 0x37, 0x3B, 0x5D, 0x4B, 0x45, 0x44, 0x3C, 0x5C, 0x7B, 0x4F,\r\n 0x74, 0x41, 0x7D, 0x7E, 0x35, 0x46, 0x23, 0x2B, 0x72, 0x71,\r\n 0x40, 0x78, 0x4C, 0x55, 0x39, 0x56, 0x30, 0x5F, 0x50, 0x2C,\r\n 0x29, 0x2D, 0x79, 0x59, 0x3A, 0x57, 0x53, 0x69, 0x77, 0x63,\r\n 0x26, 0x70, 0x2A, 0x76, 0x60, 0x3D, 0x33, 0x31, 0x22, 0x47,\r\n 0x49, 0x4E, 0x75, 0x58, 0x34, 0x68, 0x6B, 0x20, 0x67, 0x32,\r\n 0x27, 0x65, 0x51, 0x28, 0x5B, 0x2E, 0x7C, 0x6F, 0x24, 0x4A,\r\n 0x3E, 0x64, 0x73, 0x6D, 0x7A, 0x3F, 0x6A, 0x54, 0x62, 0x42,\r\n 0x6C, 0x48, 0x2F, 0x25, 0x43, 0x52, 0x21, 0x66, 0x38, 0x5A,\r\n 0x61, 0x5E, 0x36, 0x4D, 0x6E, 0x00]\r\ndec_string = ''\r\nfor i in range(len(enc_string)):\r\ncur_place = ord(enc_string[i]) - 0x20\r\ndec_string += chr (replace_b\r\nuffer[cur_place])\r\nprint(dec_string)\r\nAnd a stream cipher based on a simple homebrew linear PRNG:\r\nPlain text\r\nCopy to clipboard\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 17 of 33\n\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\ndef decrypt(seed, buffer, mask, first_hex_seed, second_hex_seed):\r\noutut = ''\r\nfor i in range(len(buffer)):\r\nseed = (((first_hex_seed * seed) % (2 ** 32)) + second_hex_seed) % (2 ** 32)\r\ncur_xor_key = ((seed \u003e\u003e 16)) | mask\r\noutput += chr ((cur_xor_key \u0026 0xff) ^ buffer[i])\r\nreturn output\r\ndef decrypt(seed, buffer, mask, first_hex_seed, second_hex_seed): outut = '' for i in range(len(buffer)): seed =\r\n(((first_hex_seed * seed) % (2 ** 32)) + second_hex_seed) % (2 ** 32) cur_xor_key = ((seed \u003e\u003e 16)) | mask\r\noutput += chr ((cur_xor_key \u0026 0xff) ^ buffer[i]) return output\r\ndef decrypt(seed, buffer, mask, first_hex_seed, second_hex_seed):\r\noutut = ''\r\nfor i in range(len(buffer)):\r\nseed = (((first_hex_seed * seed) % (2 ** 32)) + second_hex_seed) % (2 ** 32)\r\ncur_xor_key = ((seed \u003e\u003e 16)) | mask\r\noutput += chr ((cur_xor_key \u0026 0xff) ^ buffer[i])\r\nreturn output\r\nAs mentioned above, by virtue of its function, DoubleFeature is a unique source of knowledge pertaining to\r\nEquation Group tools — after all, the entire logging module depends on an ability to query these tools on a victim\r\nsystem and verify which are present. Below we list some of the tools probed by the logging module, some of\r\nwhich were unknown.\r\nApart from resources 106 and 1104, which are actively used in the DLL’s execution flow, the main DLL’s\r\nhomebrew resource directory also contains the following resources:\r\nResource 1004 – UnitedRake Restart DLL.\r\nResource 1005 – UnitedRake Shutdown DLL.\r\nResource 1006 – StraitBiZarre Restart DLL.\r\nResource 200 – Hashes of known boot managers that are being compared to BCD partition data.\r\nResource 1007 – Upgrade KillSuit module DLL — references to it can be found in the code, but it can no\r\nlonger be physically found in the directory. Possibly it existed in earlier versions of the DLL and was\r\nremoved later.\r\nPlugins Monitored by DoubleFeature\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 18 of 33\n\nUnitedRake\r\nUnitedRake (UR) is a remote access tool that can be used to target Windows machines. It is an extensible and\r\nmodular framework that is provided with a large number of plugins that perform different information collection\r\nfunctions. This is the tool that Kaspersky dubbed “EquationDrug” in their original report, published before the\r\nShadow Brokers leak. The leak also included the UnitedRake manual, which contained the configuration,\r\ncommands, and modules of this tool. DoubleFeature supports many management functions related to UnitedRake\r\nsuch as Shutdown, TipOff, KickStart and Enabling/Disabling logging.\r\nWe came across the following indicators of UnitedRake:\r\nMSNDSRV.sys – Kernel mode stage 0 and rootkit. Implements an NDIS driver for filtering the network\r\ntraffic. Until UR version 4.0.\r\nATMDKDRV.sys – Network-sniffer/patcher. Since UR version 4.1.\r\n“Software\\Classes\\CLSID\\{091FD378-422D-A36E-8487-83B57ADD2109}\\TypeLib” or\r\n“\\Registry\\Machine\\SOFTWARE\\Classes\\CLSID\\{091FD378-422D-A36E-8487-\r\n83B57ADD2209}\\TypeLib” – contains the GUID of UR, the special key registry key.\r\n“\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\MemSubSys\\{95FFB832-8B00-\r\n6E10-444B-DC67CAE0118A-F6D58114}” – KillSuit Logging data related registry key.\r\n“Global\\64322D88-0CEA-4ce0-8562-67345B70C655” – File Mapping created in TipOff command.\r\n“*Global\\*6F27089A-3482-4109-8F5B-CB3143A1AB9A” and “*Global\\*667FBF02-F406-4C0A-BA65-\r\n893747A0D372” – Events created in UR Shutdown.\r\n{A0CCDC61-7623-A425-7002-DB81F353945F-5A8ECFAD} – UnitedRake 3/4 Config Data and\r\nTransport Info CLSID\r\n{30F3976F-90F0-B438-D324-07E031C7507E-981BE0DD} – UnitedRake Plugins Info CLSID\r\n{95FFB832-8B00-6E10-444B-DC67CAE0118A-F6D58114} – UnitedRake Logging data CLSID\r\n{01C482BA-BD31-4874-A08B-A93EA5BCE511} – UnitedRake’s mutex name.\r\nStraitBizarre\r\nStraitBizarre (SBZ) is an implant used for stealthy data exfiltration which is performed over FriezeRamp – a\r\ncustom network protocol that is similar to IPSEC. It’s a cross-platform project, and different versions exist\r\nsupporting Windows, Linux and mobile platforms (e.g. DROPOUTJEEP for iPhone, and there’s even\r\nTOTEGHOSTLY for Windows Mobile).\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 19 of 33\n\nFigure 5: StraitBizzare information. Source: Der Spiegel\r\nWe came across the following indicators of StraitBizarre inside DoubleFeature:\r\n{1B8C5912-8BE4-11D1-B8D3-F5B42019CAED} – SBZ CLSID for GUID, version and Special Status\r\nKeys.\r\nKillSuit\r\nKillSuit (KiSu) (“GrayFish” in the original Kaspersky report) is an unusual plugin in that once deployed on the\r\nvictim machine, its entire mission is running other plugins, providing a framework for persistence and evasion.\r\nSome (not all) DanderSpritz plugins can be either run individually, or be invoked through KillSuit. Its design is\r\nsuch that every instance of KillSuit running on the victim side can host a single tool (such as MistyVeal, below);\r\nand so, it can easily happen that a victim machine will have several instances of KillSuit installed on it, each\r\nhosting a different post-exploitation tool. The data for each KillSuit instance, including all its modules, is kept\r\nencrypted in registry entries. This is something unique to KillSuit and is not a feature of DanderSpritz plugins in\r\ngeneral.\r\nDoubleFeature logs a great amount of data pertaining to KillSuit. In fact, there is also some dead code inside\r\nDoubleFeature that allows deleting, upgrading and pushing module updates into running KillSuit instances (we\r\nagree with the decision to deprecate this code; after all, DoubleFeature is supposed to be used for logging, and\r\nwe’ll soon see this functionality in the KillSuit Python UI, where it belongs). While “KillSuit” is the name used\r\ninside DoubleFeature and in the outer-layer DanderSpritz CLI that the attacker will actually invoke, actually the\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 20 of 33\n\nPlugin folder name used internally is DecibalMinute (DeMi for short). The Python UI logic can mainly be found\r\ninside 3 scripts that, unsurprisingly, reside in the plugin’s pyscripts directory.\r\n“Mcl_Cmd_DiBa_Tasking.py” – handles KiSu installation, uninstallation and upgrades. As a parameter,\r\nthis script accepts the type of persistence mechanism to use; there are 4 types of persistence, helpfully\r\nnamed “Default”, “Launcher”, “SoTi” and “JuVi”. We elaborate on their internal workings a bit further\r\nbelow. Under the hood, the Python UI implements this via an RPC call (RPC_INFO_INSTALL).\r\n“Mcl_Cmd_KisuComms_Tasking.py” – used to establish a connection with a running instance of\r\nKillSuit on the victim end, and provides functionality for dynamically loading and unloading\r\nmodules/drivers.\r\n“_KiSu_BH_enable.py” – One of KillSuit’s internal drivers is called “BroughtHotShot”, or BH for short.\r\nThis script does not enable it, but checks whether it is enabled (via DanderSpritz commands available -\r\ncommand kisu_install -isloaded and available -command kisu_install -load ). If you want to enable\r\nthe driver, you need to do KiSu_BH_enable.py on , and disabling it is KiSu_BH_enable.py off .\r\n“Mcl_Cmd_KiSuFullList_Tasking.py” – Produces a list of current KiSu installations on the target\r\nmachine. Behind the scenes, this is done by invoking the kisu_list DanderSpritz command, and then for\r\nevery returned installation, retrieving its configuration via the DanderSpritz command kisu_config -\r\ninstance id -checksum . This configuration contains various technical details such as the KillSuit version,\r\nthe installation’s registry key and value, the loaders for the kernel and user modules, the directory of the\r\nencrypted virtual filesystem used to keep the hosted plugin’s modules, the legitimate driver that’d been\r\nvictimized by injecting the hosted plugin into it, and the flags used internally when launching KillSuit on\r\nthe victim.\r\nEvery KillSuit instance has an internal record of an “ID” of the tool hosted inside the instance, which is\r\nuniversally the same per tool. We found referenced inside DoubleFeature to the following possible instances:\r\nPC (PeddleCheap) – 0x7A43E1FA – provides an interactive shell and some feature for long-term\r\npersistence. Also serves as a post-exploitation tool in itself, and can install other KillSuit instances on a\r\ncompromised host.\r\nUR (UnitedRake) – 0x91FD378 – see above\r\nSTLA (StrangeLand) / GROK – 0x1A0F5582 – these are both keyloggers. Their encrypted logs are stored\r\ninside files with names of the form tm154*.da .\r\nSNUN (SnuffleUnicorn) – 0x23A4732A\r\nWRWA (WraithWrath) – 0x502BB710\r\nSLSH (SleepySheriff) – 0x32A7032D\r\nWORA (WoozyRamble) – 0x68A40E49\r\nTTSU (TiltTsunami) – 0x8F1D6511\r\nSOKN (SoberKnave) – 0x8F1D6510 – This tool has functionality for data exfiltration through\r\nunused/disabled WiFi cards. It is used in Air-Gapped targets.\r\nMAGR (MagicGrain) – 0x437E52E8\r\nDODA (DoubleDare) – 0x1C9D4A8A\r\nSAAN (SavageAngel) – 0x9D801C63\r\nMOAN (MorbidAngel) – 0x9D801C62\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 21 of 33\n\nDEWH (DementiaWheel) – 0xAE37690B – Hacking tool also known as “Fanny”.\r\nCHMU (ChinMusic) – 0x39B2DA17\r\nMAMO (MagicMonkey) – 0x2D473AB3\r\nMABE (MagicBean) – 0x8675309 – used for WiFi Man In The Middle\r\nDiveBar\r\nDiveBar (DiBa) is DoubleFeature’s name for the part of KillSuit responsible for persistence methods (such as\r\n“KSLA” (KillSuit loader), “SolarTime”, “JustVisiting” and “DoctorOcopus”.\r\nThe different persistence methods, which we mentioned above by name, are:\r\nKSLA (Launcher) – Simply installs a new driver on the victim system and uses it for persistence. This\r\nworked up until Microsoft introduced Driver Signing Enforcement (DSE), which does not allow unsigned\r\ndrivers to run. This method is not supported in Windows Vista and later.\r\nJustVisiting (JuVi) – In order to bypass DSE, this persistence mechanism abuses a known vulnerability in\r\nthe signed driver ElbyCDIO.sys, which is a part of the software “CloneCD” by RedFox. The vulnerable\r\ndriver is made to be loaded, and exploited, on system startup. The elevated privileges obtained in this way\r\nare then used to add DiveBar’s persistence driver to LSAExtensionConfig/interfaces. This method is only\r\ncompatible with Windows 8.\r\nSolarTime (SoTi) – An advanced persistence mechanism that works by modifying one of the victim\r\nsystem’s VBRs. More details about this method can be found in this report by F-Secure. Only compatible\r\nwith NTFS filesystems with FVEBOOT and a certain boot sector format. SoTi compares the hash of the\r\nboot sector to a list of “known good” hashes, which are listed below.\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nC454045E1299C5AD5E2932A7B0016D7A\r\nC1544A2220F5DD61A62C697D9A2C5B77\r\n05422319E7821018401F477B3621F8E2\r\n4C85F9D2D0B02E0B3BDFC34D0F63B414\r\n0023DE8F74BF9F932AFC9E288082E660\r\n58B9130DEEFF83F1185C372595CD4607\r\nB4A78F824A7F0FA688DF729F2AEF7F7F\r\nDCE6AAAD1574BC72A25DC4551D52A2C1\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 22 of 33\n\nC454045E1299C5AD5E2932A7B0016D7A C1544A2220F5DD61A62C697D9A2C5B77\r\n05422319E7821018401F477B3621F8E2 4C85F9D2D0B02E0B3BDFC34D0F63B414\r\n0023DE8F74BF9F932AFC9E288082E660 58B9130DEEFF83F1185C372595CD4607\r\nB4A78F824A7F0FA688DF729F2AEF7F7F DCE6AAAD1574BC72A25DC4551D52A2C1\r\nC454045E1299C5AD5E2932A7B0016D7A\r\nC1544A2220F5DD61A62C697D9A2C5B77\r\n05422319E7821018401F477B3621F8E2\r\n4C85F9D2D0B02E0B3BDFC34D0F63B414\r\n0023DE8F74BF9F932AFC9E288082E660\r\n58B9130DEEFF83F1185C372595CD4607\r\nB4A78F824A7F0FA688DF729F2AEF7F7F\r\nDCE6AAAD1574BC72A25DC4551D52A2C1\r\nAs mentioned above, KillSuit keeps inside the victim registry something called a “module store”. Traditionally the\r\nregistry has been used in malware to store simple configuration data, as per the registry’s legitimate purpose; but\r\nas years have passed, more and more malware has gotten bold in using the registry to store arbitrary data. Here the\r\nregistry is made to swallow a whole Virtual File System containing the module store, which is generated by\r\nconcatenating two words chosen pseudo-randomly from two hard-coded dictionaries (the creation time of the\r\nvictim’s root directory is used as the seed). The list of possible values for the first word is reproduced below:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nAccount\r\nAcct\r\nAdapter\r\nApp\r\nAudit\r\nBoot\r\nClass\r\nCorrection\r\nDebug\r\nDir\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 23 of 33\n\nDirectory\r\nDomain\r\nDriver\r\nEvent\r\nFont\r\nHardware\r\nHiber\r\nHost\r\nLanguage\r\nLegacy\r\nLocale\r\nLogon\r\nManufacturer\r\nMedia\r\nNet\r\nNetwork\r\nOEM\r\nPower\r\nPrefetch\r\nPrivilege\r\nProcess\r\nRemote\r\nScheduler\r\nSecurity\r\nServer\r\nShared\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 24 of 33\n\nShutdown\r\nStartup\r\nTask\r\nTrust\r\nUninstall\r\nUser\r\nWin16\r\nWin32\r\nAccount Acct Adapter App Audit Boot Class Correction Debug Dir Directory Domain Driver Event Font\r\nHardware Hiber Host Language Legacy Locale Logon Manufacturer Media Net Network OEM Power Prefetch\r\nPrivilege Process Remote Scheduler Security Server Shared Shutdown Startup Task Trust Uninstall User Win16\r\nWin32\r\nAccount\r\nAcct\r\nAdapter\r\nApp\r\nAudit\r\nBoot\r\nClass\r\nCorrection\r\nDebug\r\nDir\r\nDirectory\r\nDomain\r\nDriver\r\nEvent\r\nFont\r\nHardware\r\nHiber\r\nHost\r\nLanguage\r\nLegacy\r\nLocale\r\nLogon\r\nManufacturer\r\nMedia\r\nNet\r\nNetwork\r\nOEM\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 25 of 33\n\nPower\r\nPrefetch\r\nPrivilege\r\nProcess\r\nRemote\r\nScheduler\r\nSecurity\r\nServer\r\nShared\r\nShutdown\r\nStartup\r\nTask\r\nTrust\r\nUninstall\r\nUser\r\nWin16\r\nWin32\r\nAnd the possible values for the second word:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nCache\r\nCfg\r\nConfig\r\nData\r\nDatabase\r\nDb\r\nExts\r\nFlags\r\nHierarchy\r\nHistory\r\nInfo\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 26 of 33\n\nLibs\r\nList\r\nLogs\r\nMappings\r\nMaps\r\nMgmt\r\nMon\r\nMonitor\r\nPerformance\r\nPlugins\r\nPolicy\r\nProfile\r\nRecords\r\nRegistry\r\nSettings\r\nSetup\r\nSupport\r\nUsage\r\nCache Cfg Config Data Database Db Exts Flags Hierarchy History Info Libs List Logs Mappings Maps Mgmt\r\nMon Monitor Performance Plugins Policy Profile Records Registry Settings Setup Support Usage\r\nCache\r\nCfg\r\nConfig\r\nData\r\nDatabase\r\nDb\r\nExts\r\nFlags\r\nHierarchy\r\nHistory\r\nInfo\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 27 of 33\n\nLibs\r\nList\r\nLogs\r\nMappings\r\nMaps\r\nMgmt\r\nMon\r\nMonitor\r\nPerformance\r\nPlugins\r\nPolicy\r\nProfile\r\nRecords\r\nRegistry\r\nSettings\r\nSetup\r\nSupport\r\nUsage\r\nLooking at the architecture of “GrayFish” as reported by Kaspersky, we are left with the impression that it is one\r\nand the same as KillSuit:\r\nFigure 6: Architecture of GrayFish. Source: Kaspersky\r\nThe resources in the diagram are in a one-to-one correspondence with the DiveBar resources:\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 28 of 33\n\n102 – fvexpy.sys – F7F382A0C610177431B27B93C4C87AC1\r\n103 – mpdkg32.dll – 0182DBF3E594581A87992F80C762C099\r\n104 – BroughtHotShot driver – drmkflt.sys – 9C6D1ED1F5E22BF609BCF5CA6E587DEC /\r\nD3DF8781249F2C404C4935CA9FFB1155\r\n107 – New VBR (for SolarTime)\r\n110 – mpdkg64.dll – F01525C9EF763C49E28CEC6C2F6F6C60\r\n114 – Elby loader – fhsvcapi.dll – 6156E50571571B233019C4EBB472899D\r\n115 – Elby driver – AAA8999A169E39FB8B48AE49CD6AC30A\r\nDiveBar does not limit itself to abusing ElbyCDIO.sys; it also searches for vulnerable benign drivers already\r\npresent on the victim’s machine to be used as a “launcher” for the hosted plugin’s code. Internally, such a benign\r\ndriver that is chosen by DiveBar to launch KillSuit instance is called a “thunk” (this might be the place to mention\r\nthat according to the Merriam-Webster dictionary, the only meaning of the word “thunk” is as a present-tense verb\r\nmeaning “to produce a flat hollow sound”; the author of the original PE file format caused enough suffering by\r\nusing this mysterious word as a description for an opaque digital object, and we are sad to see this practice\r\nrepeated here). For every KillSuit instance, DoubleFeature reports the thunk exploited dll used to load its kernel-mode module, which is called the KML (Kernel Module Launcher) for short. A similar report is made for the User\r\nMode Launcher (UML).\r\nFlewAvenue\r\nFlewAvenue(FlAv) is an IPv4 driver that provides covert network access for other tools. It provides different\r\nnetworking faculties such as DNS queries and ICMP echo (“ping”).\r\nWe came across the following indicators of FlewAvenue:\r\n“ntevt.sys ” – The name of this tool’s driver.\r\nDuneMessiah\r\nDoubleFeature diagnostics only provide very minimal information regarding this tool. For this tool,\r\nDoubleFeature reports a pseudorandomly-generated “Event Name” that the instance on the victim machine uses\r\ninternally, as well a number of “registered KillSuit instances”.\r\nCritterFrenzy\r\nDoubleFeature reports only the bare minimum of information about this plugin as well. From the information we\r\ncan see DoubleFeature collects regarding this tool, it seems to be another instance of KillSuit that probably has\r\nbeen used in the past and its ID was 333.\r\nWe came across the following indicators of CritterFrenzy:\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 29 of 33\n\n“MPDKH32” – The name of this tool.\r\nMistyVeal\r\nMistyVeal (MV) is a “validator” implant, meaning that it is used to verify that the targeted system is indeed an\r\nauthentic victim and not a research environment. It is implemented as an Internet Explorer Browser Helper Object\r\n(these are typically used for extending IE functionality; for example, Adobe’s Acrobat plugin for IE is a Browser\r\nHelper Object). MistyVeal was also part of the Equation Group’s original “Double Fantasy” implant, a precursor\r\nof UnitedRake. You can read more about it and the connection to Regin in a report by EpicTurla.\r\n“nethdlr.sys” – The name of this tool’s driver.\r\nWe came across the following indicators of MistyVeal:\r\n{B812789D-6FDF-97AB-834B-9F4376B2C8E1} – MV CLSID for GUID and version.\r\nDiceDealer\r\nDiceDealer (DD), mentioned in the leaked UnitedRake manual, is a parsing tool for the logging data produced by\r\nall installations and uninstallations performed by DiveBar (this is relevant to UnitedRake because DiveBar is\r\ntypically used to install it). If you are looking to manually parse DiceDealer log files, the easiest method is to copy\r\nthe log file into the same directory where the DiceDealerReader tool is located. The reader is dependent on several\r\nof the files within that directory and will fail to parse the log if they are not present.\r\nPeddleCheap\r\nPeddleCheap ****(PC) is among the first tools to be run on a victim machine, and can be used to bootstrap a\r\ncomplete DanderSpritz installation. PeddleCheap has minimal functionality allowing attackers to connect to the\r\nvictim machine and remotely install and configure implants that allow further post-exploitation functionality,\r\nincluding a full install of the DanderSpritz framework. PeddleCheap is usually injected into lsass.exe by several\r\nmethods, including the DOUBLEPULSAR backdoor.\r\nFigure 7: PeddleCheap User Interface.\r\nWe came across the following indicators of PeddleCheap:\r\n{A682FEC0-333F-B16A-4EE6-24CC2BAF1185} – PC CLSID for GUID and version.\r\nControl flow of DoubleFeature’s Rootkit\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 30 of 33\n\nThe rootkit used by DoubleFeature ( hidsvc.sys ) performs the following actions when it is loaded:\r\nIt creates an unnamed device object but registers IRP dispatch functions.\r\nIt dispatches IOCTL requests.\r\nIt specializes in run-time patching of Windows kernel code.\r\nIt runs kernel APIs for the user-mode module.\r\nThe rootkit is patched by the user-mode DLL before being loaded into memory — this is done to insert the PID of\r\nthe user-mode process so that the rootkit knows which process to hide. The rootkit then attaches to this accomplice\r\nuser-mode process via KeAttachProcess .\r\nThe rootkit finds the dynamic addresses of API functions using HalAllocateCommonBuffer or MmIsAddressValid\r\n(the addresses for these functions are earlier obtained by invoking MmGetSystemRoutineAddress). It uses\r\nencrypted stack strings which are decrypted on a need-to-use basis and encrypted again immediately after they are\r\nused, similarly to the method used in the user-mode component of DoubleFeature that we described earlier.\r\nIn order to avoid detection, the rootkit also takes care to create its own driver objects as stealthily as possible.\r\nFirst, instead of creating the object directly, the rootkit creates a handle to Device\\\\NULL , then hijacks its\r\nFileHandle by inserting its own device object with the name driver\\\\msvss . Then, it uses this FileObject to send\r\na IRP_MJ_Create request in order to obtain a handle to the newly created driver object. Second, the rootkit calls\r\nObMakeTemporaryObject and removes the name of the object from its parent object manager directory, effectively\r\nunlinking it from the structs that the OS uses internally to keep track of loaded drivers. Because of the way\r\nWindows OS handles drivers, this has the effect of keeping the driver running in the background while diagnostic\r\ntools and researchers will fail to find the driver.\r\nThe IRP_MJ_DEVICE_CONTROL handler function of the new device contains the different IoControl codes that\r\ncan be sent from the user-mode DLL (such as 0x8589240c for truncating a file, and 0x85892408 for executing an\r\nAPI call in kernel mode and sending the output back to the user-mode process).\r\nConclusion\r\nSometimes, the world of high-tier APT tools and the world of ordinary malware can seem like two parallel\r\nuniverses. Cybercriminals periodically produce the umpteenth Cryptolocker clone or, at most, another modular\r\njack-of-all-trades Emotet wannabe; in the meanwhile, nation-state actors tend to clandestine, gigantic codebases,\r\nsporting a huge gamut of features that have been cultivated over decades due to practical need. For those of us\r\nwith our heads deep enough up the cybercrime industry’s nether regions, many of the features described above —\r\nrootkits, dedicated components to thoroughly vet victims, whole systems dedicated to logging the stages of post-exploitation — are, largely, abstract theory. The cybercrime industry’s DoubleFeature is typically an HTTP GET\r\nrequest containing \u0026OS=win10 , encrypted by some homebrew variant of RC4. The gap can really not be\r\noverstated.\r\nIt’s not often that we get such a candid glimpse into tools of this degree of sophistication, as the Shadow Brokers\r\nleak allowed us. The DanderSpritz-tier projects of the world are naturally covered by a shroud of secrecy — even,\r\nas we’ve seen, from fellow APT actors, who can maybe at best get their hands on a rival tool once in a blue moon,\r\nas happened with EpRom which led to the creation of Jian. As an industry, it turns out we too are still slowly\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 31 of 33\n\nchewing on the 4-year-old leak that revealed DanderSpritz to us, and gaining new insights. On the defenders’ side,\r\nwe have the duty to study these marvels of infosec engineering carefully and apply the lessons learned — before\r\nlower-tier, run-of-the-mill attackers do the same.\r\nAppendix 1: Table of Command-Line Argument Supported by DoubleFeature\r\nMain DLL\r\nOption Arguments\r\nRelevant\r\ncommand in\r\nthe menu\r\nDescription\r\n-n/-m Registry key name  \r\nCheck if a registry key\r\nexists or not.\r\n-o –  \r\nReturns DuneMessiah\r\ninformation\r\n-p filename   Changes the log file name.\r\n-q Hash, ID/Name   Deletes KillSuit module.\r\n-s ‘u’/’s’  \r\nShutdowns UnitedRake or\r\nStraitBizarre\r\n-t IP, port   TipOffs UnitedRake\r\n-u Hash, ID/Name   Upgrades KillSuit module\r\n-v Hash, ID/Name   Downloads KillSuit module\r\n-x filename  \r\nTruncates file on victim’s\r\ncomputer\r\n-g IP:port  \r\nChecks FlewAvenue\r\nfeature compatibility\r\n-h ‘u’/’s’   Stops FA in UR or SBZ\r\n-i\r\nk = KillSuit m = Manual Instances p\r\n= Processes info q = Modules Data s\r\n= StraitBiZarre u = UnitedRake c=\r\nCritterFrenzy d = DiveBar e =\r\nLoaded Drivers f = FlewAvenue g =\r\nSpecial Implant i = Implant\r\nIndependet\r\n \r\nGives information about\r\nthe tool given as an\r\nargument\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 32 of 33\n\n-j 0/1  \r\nGet DiceDealer logs –\r\nDiveBar information on the\r\nvictim’s computer.\r\n-k ‘u’/’s’   KickStarts UR or SBZ\r\n-l – DFQuery\r\nQuery information as in ‘i’\r\ncommand but on several\r\ntools on one command.\r\n-f –  \r\nToggles FlewAvenue mode\r\n– as a network sniffer or as\r\na memory patcher. It does\r\nthis by changing the\r\n“config2” SubKey.\r\n-a new AES key  \r\nReplaces the AES key for\r\nencrypting the logs.\r\n-b/-e registry key  \r\nDeletes DiveBar registry\r\nkey\r\n-c –   –\r\n-d on/off   Enable/Disable UR logging\r\nSource: https://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nhttps://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/\r\nPage 33 of 33",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia",
		"ETDA"
	],
	"references": [
		"https://research.checkpoint.com/2021/a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard/"
	],
	"report_names": [
		"a-deep-dive-into-doublefeature-equation-groups-post-exploitation-dashboard"
	],
	"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": "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": "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": "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
		}
	],
	"ts_created_at": 1775434250,
	"ts_updated_at": 1775792145,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/158121f641ac2c63b1083387974d04de80c2dc5d.pdf",
		"text": "https://archive.orkl.eu/158121f641ac2c63b1083387974d04de80c2dc5d.txt",
		"img": "https://archive.orkl.eu/158121f641ac2c63b1083387974d04de80c2dc5d.jpg"
	}
}