In the past two months, we observed multiple APT groups attempting to leverage the Russia and Ukraine war as a lure for espionage operations. It comes as no surprise that Russian entities themselves became an attractive target for spear-phishing campaigns that are exploiting the sanctions imposed on Russia by western countries. These sanctions have put enormous pressure on the Russian economy, and specifically on organizations in multiple Russian industries.
Check Point Research (CPR) details a targeted campaign that has been using sanctions-related baits to attack Russian defense institutes, part of the Rostec Corporation. The investigation shows that this campaign is part of a larger Chinese espionage operation that has been ongoing against Russian-related entities for several months. CPR researchers estimate with high confidence that the campaign has been carried out by an experienced and sophisticated Chinese nation-state APT. In the below blog, the researchers reveal the tactics and techniques used by the threat actors and provide a technical analysis of the observed malicious stages and payloads, including previously unknown loaders and backdoors with multiple advanced evasion and anti-analysis techniques.
On March 23, malicious emails were sent to several defense research institutes based in Russia. The emails, which had the subject “List of <target institute name> persons under US sanctions for invading Ukraine
”, contained a link to an attacker-controlled site mimicking the Health Ministry of Russia minzdravros[.]com
and had a malicious document attached:
Figure 1: Spear-phishing email sent to research institutions in Russia.
On the same day, a similar email was also sent to an unknown entity in Minsk, Belarus with the subject “US Spread of Deadly Pathogens in Belarus
”. All the attached documents are crafted to look like official documents from the Russian Ministry of Health, bearing its official emblem and title:
Figure 2: Screenshot of the lure document sent to research institutions in Russia.
Each document downloads an external template from the URLs with a similar format, such as https://www.microtreely.com/support/knowledgebase/article/AIUZGAE7230Z[.]dotm
. The external template contains a macro code that imports several API functions from kernel32 (LoadLibraryA
, CreateFileA
, WriteFile
, ReadFile
, etc) and uses them to:
cmpbk32.dll
, cmpbk64.dll
, and INIT
) to the path: C:/Users/Public
.cmpbk32.dll
or cmpbk64.dll
(depending on the system OS architecture) and execute its exported function R1
.Execution of the exported function R1 finalizes the initialization of the malicious files. The malware creates a working directory %TEMP%\\OfficeInit
and copies to it INIT
and cmpbk32.dll
files, as well as a legitimate 32-bit Windows executable cmdl32.exe from either System32 or SysWOW64 folder, depending on if the operating system is 32 or 64 bit.
Figure 3: The simplified infection chain.
The loader is a 32-bit DLL utilizing dynamic API resolving with name hashing for evasion and anti-analysis. The loader is not only able to hide its main functionality, but also avoid static detection of suspicious API calls by dynamically resolving them instead of using static imports.
The purpose of cmpbk32.dll
is to load specific shellcode from the INIT file, depending on the infection stage, and run it. The INIT
file contains two shellcodes: the first-stage shellcode runs the persistence and cleanup script, and the second-stage shellcode is a multi-layer loader. The goal is to consecutively decrypt the other three fileless loader layers and eventually load the main payload in memory. To distinguish between the stages, the DLL entry point DllMain
performs different actions based on the call reason.
When the malicious document is closed, a PROCESS_DETACH
event is triggered. The DLL executes a portion of the INIT file in charge of cleaning up the files created by the malicious document and creates a scheduled task for persistence:
Figure 4: DLLMain PROCESS_DETACH event executes shellcode responsible for persistence and cleanup from INIT
Figure 5: Persistence and cleanup function
The main loading process begins with the scheduled task running cmdl32.exe
which loads the malicious DLL cmpbk32.dll
. DLL sideloading by a legitimate process is a technique commonly used by threat actors; coupling it with a robust loading process can help evade modern anti-virus solutions as, in this case, the actual running process is valid and signed by Microsoft. Note that the cmpbk64.dll
is not copied into the %TEMP%\\OfficeInit
folder. The 64-bit version of the DLL is only used in the initial infection stage by the 64-bit MS Word process, as the 32-bit cmdl32.exe
can only load 32-bit cmpbk32.dll
.
When the DLL is loaded, the PROCESS_ATTACH
event is triggered and starts a sequence of operations. The sequence peels off multiple encrypted layers from the INIT
file and eventually reveals and executes the final payload. It first reads an XOR-encrypted blob from the INIT
file and decrypts it in memory using a simple XOR with the key 0x9229
. The decrypted blob is a position-independent code and the first of the encrypted layers that “protects” the main payload.
Figure 6: Layers of decryption performed by the loader to uncover the final payload.
This first layer is rather simple. It dynamically loads from Kernel32.dll the WinAPI functions that are essential for its work. Next, it begins a sequence of operations to uncover the second layer. It uses RC4 with the following hardcoded key: 0x1C, 0x2C, 0x66, 0x7C, 0x11, 0xCF, 0xE9, 0x7A, 0x99, 0x8B, 0xA3, 0x48, 0xC2, 0x03, 0x07, 0x55
. It then decompresses the decrypted buffer using RtlDecompressBuffer
and reveals the second layer.
Figure 7: Injection to msiexec.exe
The injected code begins by dynamically loading a PE file embedded inside and executing it from its entry point.
The payload uses two compiler-level obfuscations:
Both methods make it difficult to analyze the payload, but together, they make the analysis painful, time-consuming, and tedious. These two types of obfuscations were previously spotted being used together in samples attributed to the Chinese-speaking group Stone Panda (APT10) and Mustang Panda.
Figure 8: Opaque predicate and control flow flattening code obfuscations in the SPINNER sample.
When the SPINNER backdoor starts to run, it creates a mutex called MSR__112
to ensure there is only one instance of the payload running at a time. The payload also expands the persistence previously created by the loader. It creates a new registry key OfficeInit
under SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run
that points to the cmdl32.exe
path.
Next, it sets up its own configuration, which contains the following fields:
struct malware_config { std::string full_c2_url; std::string host_name; std::string c2_uri; DWORD use_https; DWORD port; DWORD sleep_time; }
The full_c2_url
is decrypted using XOR decryption with the key 0x50
. After decryption, the function InternetCrackUrlA
is used to crack a URL into its component parts: the c2_url_without_scheme
, c2_uri
, port
and use_https fields
.
Next, the backdoor starts its main loop by checking if it’s the first run and therefore system fingerprinting has not yet occurred. If the answer is no, the backdoor creates a random 16-byte Bot ID and saves it to the file %TEMP%\\OfficeInit\\init.ini
. It then collects data about the infected system and creates a string containing the following data:
When it has the string containing all the gathered data, the backdoor prepares a packet to be sent to the C&C server, constructed in the following way:
Offset | Field |
0x0 | 16 null bytes |
0x10 | 4-byte command ID – 0x10010001 |
0x14 | 4 null bytes |
0x18 | System information string length |
0x1C | System information string |
Next, the backdoor generates a random 8-byte RC4 key that is used to encrypt the entire packet. The final packet has this structure:
Offset | Field |
0x0 | 8-byte randomly generated RC4 key |
0x8 | Packet data size |
0xC | Packet data |
The packet is sent through the HTTP/S depending on the URL retrieved from the malware configuration. Similar to the request, the response from the C&C server is encrypted with RC4 and has the same structure containing the key, size, and data. The C&C response can contain one of the following commands:
Command ID | Action |
0x10030001 | Exit Process |
0x10010002 | Self-update – Write data to the INIT file and create another instance of the cmdl32.exe using CreateProcessW . |
0x10010001 | Collect system information and send the data back to the C&C |
Judging by the supported commands, this version of the SPINNER backdoor has only basic capabilities to enumerate the host system. Its main purpose is to run additional payloads received from the C&C server. While we were not able to get other payloads, based on other findings described later in the research, we believe that selected victims likely received the full backdoor with additional capabilities.
While searching VirusTotal for files similar to the loader, we encountered an additional cluster which also utilizes DLL sideloading to launch an in-memory loader that is very similar to the one we discussed previously. It then loads a payload that could be an earlier variant of the SPINNER backdoor. Judging by the names of the files and compilation stamps of the executables, the campaign has been active since June 2021.
Unlike the current campaign, which uses Microsoft Word documents as a dropper, the previous wave of attacks relied on executables bearing the Microsoft Word logo. This suggests these droppers were intended to be delivered to the victims by the same means as the malicious documents, via spear-phishing emails, either as attachments or links to fake sites.
The dropper is a 64-bit executable that has a simpler flow than the previously discussed malicious document:
Figure 9: The Infection chain of the campaign starts with the executable dropper.
First, it extracts the following files from resources: rekeywiz.exe
, UnityPlayer.dll
and PIN
, and drops them into the working folder C:\\Users\\Public\\PublicPIN
. The file rekeywiz.exe
masquerades as a legitimate Windows executable EFS REKEY Wizard, but in fact, is a Steam gaming platform interactive wallpaper called Sheep. Sheep is a digitally signed Unity-based application for Steam Wallpaper Engine. Therefore, it can evasively side-load the malicious loader that imitates Unity dll which in turn loads, decrypts and executes the shellcode from the PIN
file.
The dropper also decrypts from the resources, drops a decoy Word document to %USER%\\Documents\\offic\\
(the typo is on the actor) and opens it for the victim. All the decoy documents we observed in different droppers used Russian government-related themes, such as the Decrees of the President of the Russian Federation, with documents’ names and content in Russian. It can be assumed that the campaign is also targeting entities in or related to Russia.
Figure 10: A fragment of the decoy document launched by the dropper.
For persistence, the dropper creates a scheduled task called InterSys
that points to rekeywiz.exe
. The code handling this is very similar to the “persistence and cleanup” function from the loader we described earlier:
Figure 11: Persistence set up by the dropper.
The older versions of the loader contain debugging information and feature an interesting PDB path: C:\\D\\StageS\\Release\\HackDll2.pdb
.
As the infection chain is simpler, when it is side-loaded by rekeywiz.exe
, the loader only handles the PROCESS_ATTACH
event. The payload decryption code for the loader is similar to the one we described, and it performs the same steps as the new loader: XOR decryption for the first layer encryption, RC4 decryption for the second layer, and injection to a newly created msiexec.exe
.
Figure 12: UnityPlayer.dll XORing bytes from the PIN file (with the keys 0x29, 0x92) vs cmpbk32.dll XORing bytes from the INIT file (with the keys 0x29, 0x92)
Many of the functions inside the final payload share similar logic with the SPINNER variant described above, but the payload lacks the compiler-level obfuscations observed in the newer campaign making it easier to analyze. Furthermore, the previous version of the backdoor contains additional features. This is another indication that the initial SPINNER backdoor version we observed is only a part of the bigger payload. It’s likely the actors eventually split the payload and only equipped the first stage of the main backdoor with essential functions: enumeration of the victim’s machine and execution of the next stage payloads received from the C&C server.
The full version of the SPINNER backdoor contains the following capabilities:
Below is the full list of supported commands:
Command ID | Command Description | Arguments | Output |
0x10040001 | Enumerate disk drives | None | Logical drive strings and their drive types. |
0x10040002 | Enumerate files in a directory | Directory Name | For every file in the specified directory: Filename, 0/1 (directory or not), file size, last_write_time. Output format: “%s\t%s\t%lld\t%d.%d.%d %d:%d:%d ” |
0x10040003 | Create directory | Directory Name | Return value |
0x10040004 | Rename file | Original File Name and New File Name (separated by ‘\t’) | Return value |
0x10040005 | Delete file | File Name | Return value |
0x10040006 | Copy file | Original File Name and New File Name (separated by ‘\t’) | Return value |
0x10040007 | Move file | Original File Name and New File Name (separated by ‘\t’) | Return value |
0x10040008 | Reads file data (Max File Size = 0xA00000) | File Name | File content |
0x10040009 | Write to file | A struct that contains: File Name, File Name Size, Content To Write, Content Size | Return value |
0x10050001 | Run command using cmd.exe | cmd line | Output from Command Line |
0x10010001 | Send User Info (same as the first message to C&C) | None | Bot ID (saved to and retrieved from version.dll file), Computer Name, Host Info, x86/x64, User Name, Sleep Time, Process ID |
0x10000002 | Update Sleep time | New Sleep Time | Return value |
0x10000003 | Do nothing | ||
0x10030001 | Self-delete and exit process (create and run a file named a.bat with the content “ping 127.0.0.1 &&del /q *\r\n ”). Also, delete persistence from the Run Registry Key. |
None | None |
The communication protocol between the SPINNER backdoor and the C&C server didn’t change from one version to the next.
In less than a year, the actors significantly improved the infection chain and made it more complex. All the functionality from the old campaign was preserved, but it was split between multiple components making it harder to analyze or detect each stage. Here are some examples of the split components:
As with any unknown malware sample, the SPINNER loader and backdoor analysis required CPR to determine whether it was a known malware sample or an entirely new malware family. At first glance, the payload looked similar to the PlugX/Hodur malware described by ESET in a recently published report on Chinese APT Mustang Panda. The first similarity is in the ID numbering of C&C commands: both malware use 2 bytes to specify the command category and 2 bytes for a specific command from this category. For example, the command 0x10010001
is used in the SPINNER variant to send the system information data, while Hodur malware uses the command group 0x1001
and command ID 0x1001
for the same action.
In addition, some of the commands themselves overlap between the samples, such as those that list the logical drives, get detailed information about the files in a directory, or execute commands using cmd.exe. These functionalities are not unique and can usually be found in many backdoors. In this case, the two malware share an even greater and more surprising similarity. After opening the Hodur PlugX variant in the disassembler, it became apparent that Hodur — like SPINNER — was heavily obfuscated using Control Flow Flattening (CFF). However, Hodur’s CFF is different from SPINNER’s. Hodur’s CFF relies on a dispatcher that uses a certain register to decide which code block to jump to next, while in SPINNER the register is used as-is without any manipulation. In the PlugX variant, additional arithmetic operations are used on the register before it is checked by the dispatcher. To complete the obfuscation comparison, Hodur heavily obfuscates its API calls and strings, a step which is absent in SPINNER.
Figure 13: Control flow flattening used in SPINNER variant (on the left) vs control flow flattening with arithmetic operations on the CFF register used in the Hodur variant (on the right).
In terms of implementation, the malware samples are entirely different. Hodur is a multithreaded Windows Desktop application and communicates with the C&C through multiple threads, each with its own purpose, while SPINNER is a single-threaded Console application. Hodur’s enumeration method is more extensive than SPINNER’s, but it does not use Bot ID which identifies a specific infected machine. The self-delete function in Hodur might be similar in its logic to SPINNER, but it uses a completely different set of commands to delete itself and its associated files. Hodur’s communication logic with the C&C is more complex, drawn from different parts of the code and from multiple threads, while SPINNER has only has one function that handles the commands.
While the differences indicate these malware belong to different families, they share “best practices” similarities. Here are some examples of their similarities:
It can be argued that those are just common techniques used by all backdoors, but it is not unlikely that these tools might have the same upstream source and therefore share many best practices and methods.
The Tactics, Techniques, and Procedures (TTPs) of this operation enabled us to attribute it to Chinese APT activity. In general, Chinese groups are known to reuse and share tools between them. Without enough strong evidence, such as infrastructure-based connections, we couldn’t directly attribute this activity with high confidence to any specific Chinese threat actor. However, the Twisted Panda campaign bears multiple overlaps with advanced and long-standing Chinese cyberespionage actors:
Figure 14: Control-flow obfuscations in MustangPanda sample (698d1ade6defa07fb4e4c12a19ca309957fb9c40).
The defense research institutes that we identified as targets of this attack belong to a holding company within the Russian state-owned defense conglomerate Rostec Corporation. It is Russia’s largest holding company in the radio-electronics industry and the specific targeted research institutes’ primary focus is the development and manufacturing of electronic warfare systems, military-specialized onboard radio-electronic equipment, air-based radar stations and means of state identification. The research entities are also involved in avionics systems for civil aviation, the development of a variety of civil products such as medical equipment and control systems for energy, transportation, and engineering industries.
The Made in China 2025 plan defines objectives for China to become a major technological and economic power, and also identifies the sectors in which it must become a world leader, including robotics, medical equipment, and aviation. To support that, China’s five-year plan for the years 2021-2025 outlines a steady increase in R&D budgets each year in order to expand China’s scientific and technical capabilities. However, multiple reports – not from the United States and other countries including Russia, which is considered China’s strategic partner – reveal that alongside overt relations and measures, China employs covert tools to gather information, thus combining partnerships with diverse espionage activity. Together with the previous reports of Chinese APT groups conducting their espionage operations against the Russian defense and governmental sector, the Twisted Panda campaign described in this research might serve as more evidence of the use of espionage in a systematic and long-term effort to achieve Chinese strategic objectives in technological superiority and military power.
In this report, CPR researchers have described and exposed a Chinese espionage operation named Twisted Panda which targets defense research institutes in Russia and possibly also in Belarus. This campaign relies on social engineering techniques and exploits recently imposed sanctions on Russia to deliver a previously undocumented backdoor called SPINNER to specific targets. The purpose of the backdoor and the operation is likely to collect information from targets inside the high-tech Russian defense industry to support China in its technological advancement.
As a part of this investigation, we uncovered the previous wave of this campaign, also likely targeting Russian or Russia-related entities, active since at least June 2021. The evolution of the tools and techniques throughout this time period indicates that the actors behind the campaign are persistent in achieving their goals in a stealthy manner. In addition, the Twisted Panda campaign shows once again how quickly Chinese espionage actors adapt and adjust to world events, using the most relevant and up-to-date lures to maximize their chances of success.
To help track and research the Twisted Panda campaign, see Appendix A for relevant Yara rules for all the major components of this attack.
d723c18baea565c9263dca0eb3a11904 |
|
027845550d7a0da404f0f331178cb28b |
docx |
1f9a72dc91759cd06a0f05ac4486dda1 |
docx |
d95bbe8a97d864dc40c9cf845aeb4e9e |
docx |
ce02ee477e1188f0664dd65b17e83d11 |
template |
3855dc19811715e15d9775a42b1a6c55 |
template |
7dd4c80acc4dca33af0d26477efe2002 |
template |
90e6878ebfb3e962523f03f9d411b35c |
loader (64-bit) |
7a371437e98c546c6649713703134727 |
loader (32-bit) |
www.miniboxmail[.]com |
|
www.minzdravros[.]com |
|
www.microtreely[.]com |
Old campaign:
312dcd11c146323876079f55ca371c84 |
dropper |
443c66275e2802c00afe2cf16f147737 |
dropper |
fd73eeead785470f79536e9eb2eb6ef2 |
dropper |
176d7239887a9d0dd24e2cce904277bc |
loader |
daa1da9b515a32032bc621e71d4ae4ca |
loader |
e3072cc3f99dd3a32801e523086d9bb1 |
loader |
06865195c326ff587b2c0bed16021d08 |
loader |
176d7239887a9d0dd24e2cce904277bc |
loader |
25f3da186447794de5af2fa3ff3bcf23 |
loader |
6d4bf8dd4864f9ac564d3c9661b99190 |
loader |
img.elliotterusties[.]com |
rule apt_CN_TwistedPanda_loader { meta: author = "Check Point Research" description = "Detect loader used by TwistedPanda" date = "2022-04-14" hash = "5b558c5fcbed8544cb100bd3db3c04a70dca02eec6fedffd5e3dcecb0b04fba0" hash = "efa754450f199caae204ca387976e197d95cdc7e83641444c1a5a91b58ba6198" strings: // 6A 40 push 40h ; '@' // 68 00 30 00 00 push 3000h $seq1 = { 6A 40 68 00 30 00 00 } // 6A 00 push 0 ; lpOverlapped // 50 push eax ; lpNumberOfBytesRead // 6A 14 push 14h ; nNumberOfBytesToRead // 8D ?? ?? ?? ?? ?? lea eax, [ebp+Buffer] // 50 push eax ; lpBuffer // 53 push ebx ; hFile // FF 15 04 D0 4C 70 call ds:ReadFile $seq2 = { 6A 00 50 6A 14 8D ?? ?? ?? ?? ?? 50 53 FF } // 6A 00 push 0 // 6A 00 push 0 // 6A 03 push 3 // 6A 00 push 0 // 6A 03 push 3 // 68 00 00 00 80 push 80000000h $seq3 = { 6A 00 6A 00 6A 03 6A 00 6A 03 68 00 00 00 80 } // Decryption sequence $decryption = { 8B C? [2-3] F6 D? 1A C? [2-3] [2-3] 30 0? ?? 4? } condition: // MZ signature at offset 0 and ... uint16(0) == 0x5A4D and // ... PE signature at offset stored in MZ header at 0x3C uint32(uint32(0x3C)) == 0x00004550 and filesize < 3000KB and all of ($seq*) and $decryption } rule apt_CN_TwistedPanda_SPINNER_1 { meta: author = "Check Point Research" description = "Detect the obfuscated variant of SPINNER payload used by TwistedPanda" date = "2022-04-14" hash = "a9fb7bb40de8508606a318866e0e5ff79b98f314e782f26c7044622939dfde81" strings: // C7 ?? ?? ?? 00 00 00 mov dword ptr [eax+??], ?? // C7 ?? ?? ?? 00 00 00 mov dword ptr [eax+??], ?? // C6 mov byte ptr [eax], 0 $config_init = { C7 ?? ?? ?? 00 00 00 C7 ?? ?? ?? 00 00 00 C6 } $c2_cmd_1 = { 01 00 03 10} $c2_cmd_2 = { 02 00 01 10} $c2_cmd_3 = { 01 00 01 10} // 8D 83 ?? ?? ?? ?? lea eax, xor_key[ebx] // 80 B3 ?? ?? ?? ?? ?? xor xor_key[ebx], 50h // 89 F1 mov ecx, esi ; this // 6A 01 push 1 ; Size // 50 push eax ; Src // E8 ?? ?? ?? ?? call str_append // 80 B3 ?? ?? ?? ?? ?? xor xor_key[ebx], 50h $decryption = { 8D 83 [4] 80 B3 [5] 89 F1 6A 01 50 E8 [4] 80 B3 } condition: // MZ signature at offset 0 and ... uint16(0) == 0x5A4D and // ... PE signature at offset stored in MZ header at 0x3C uint32(uint32(0x3C)) == 0x00004550 and filesize < 3000KB and #config_init > 10 and 2 of ($c2_cmd_*) and $decryption } rule apt_CN_TwistedPanda_SPINNER_2 { meta: author = "Check Point Research" description = "Detect an older variant of SPINNER payload used by TwistedPanda" date = "2022-04-14" hash = "28ecd1127bac08759d018787484b1bd16213809a2cc414514dc1ea87eb4c5ab8" strings: // C7 ?? ?? ?? 00 00 00 mov dword ptr [eax+??], ?? // C7 ?? ?? ?? 00 00 00 mov dword ptr [eax+??], ?? // C6 mov byte ptr [eax], 0 $config_init = { C7 [3] 00 00 00 C7 [3] 00 00 00 C6 } $c2_cmd_1 = { 01 00 03 10 } $c2_cmd_2 = { 02 00 01 10 } $c2_cmd_3 = { 01 00 01 10 } $c2_cmd_4 = { 01 00 00 10 } $c2_cmd_5 = { 02 00 00 10 } // 80 B3 ?? ?? ?? ?? ?? xor ds:dd_encrypted_url[ebx], 50h // 8D BB ?? ?? ?? ?? lea edi, dd_encrypted_url[ebx] // 8B 56 14 mov edx, [esi+14h] // 8B C2 mov eax, edx // 8B 4E 10 mov ecx, [esi+10h] // 2B C1 sub eax, ecx // 83 F8 01 cmp eax, 1 $decryption = { 80 B3 [5] 8D BB [4] 8B 56 14 8B C2 8B 4E 10 2B C1 83 F8 01 } condition: // MZ signature at offset 0 and ... uint16(0) == 0x5A4D and // ... PE signature at offset stored in MZ header at 0x3C uint32(uint32(0x3C)) == 0x00004550 and filesize < 3000KB and #config_init > 10 and 2 of ($c2_cmd_*) and $decryption } rule apt_CN_TwistedPanda_64bit_Loader { meta: author = "Check Point Research" description = "Detect the 64bit Loader DLL used by TwistedPanda" date = "2022-04-14" hash = "e0d4ef7190ff50e6ad2a2403c87cc37254498e8cc5a3b2b8798983b1b3cdc94f" strings: // 48 8D ?? ?? ?? ?? ?? ?? ?? lea rdx, ds:2[rdx*2] // 48 8B C1 mov rax, rcx // 48 81 ?? ?? ?? ?? ?? cmp rdx, 1000h // 72 ?? jb short loc_7FFDF0BA1B48 $path_check = { 48 8D [6] 48 8B ?? 48 81 [5] 72 } // 48 8B D0 mov rdx, rax ; lpBuffer // 41 B8 F0 16 00 00 mov r8d, 16F0h ; nNumberOfBytesToRead // 48 8B CF mov rcx, rdi ; hFile // 48 8B D8 mov rbx, rax // FF ?? ?? ?? ?? call cs:ReadFile $shellcode_read = { 48 8B D0 41 B8 F0 16 00 00 48 8B CF 48 8B D8 FF} // BA F0 16 00 00 mov edx, 16F0h ; dwSize // 44 8D 4E 40 lea r9d, [rsi+40h] ; flProtect // 33 C9 xor ecx, ecx ; lpAddress // 41 B8 00 30 00 00 mov r8d, 3000h ; flAllocationType // FF ?? ?? ?? ?? ?? call cs:VirtualAlloc $shellcode_allocate = { BA F0 16 00 00 44 8D 4E 40 33 C9 41 B8 00 30 00 00 FF } condition: // MZ signature at offset 0 and ... uint16(0) == 0x5A4D and // ... PE signature at offset stored in MZ header at 0x3C uint32(uint32(0x3C)) == 0x00004550 and filesize < 3000KB and $path_check and $shellcode_allocate and $shellcode_read } rule apt_CN_TwistedPanda_droppers { meta: author = "Check Point Research" description = "Detect droppers used by TwistedPanda" date = "2022-04-14" hash = "59dea38da6e515af45d6df68f8959601e2bbf0302e35b7989e741e9aba2f0291" hash = "8b04479fdf22892cdfebd6e6fbed180701e036806ed0ddbe79f0b29f73449248" hash = "f29a0cda6e56fc0e26efa3b6628c6bcaa0819a3275a10e9da2a8517778152d66" strings: // 81 FA ?? ?? ?? ?? cmp edx, 4BED1896h // 75 ?? jnz short loc_140001829 // E8 ?? ?? ?? ?? call sub_1400019D0 // 48 89 05 ?? ?? ?? ?? mov cs:qword_14001ED38, rax // E? ?? ?? ?? ?? jmp loc_1400018DD $switch_control = { 81 FA [4] 75 ?? E8 [4] 48 89 05 [4] E? } // 41 0F ?? ?? movsx edx, byte ptr [r9] // 44 ?? ?? or r8d, edx // 41 ?? ?? 03 rol r8d, 3 // 41 81 ?? ?? ?? ?? ?? xor r8d, 0EF112233h // 41 ?? ?? mov eax, r10d $byte_manipulation = { 41 0F [2] 44 [2] 41 [2] 03 41 81 [5] 41 } // %public% $stack_strings_1 = { 25 00 70 00 } $stack_strings_2 = { 75 00 62 00 } $stack_strings_3 = { 6C 00 69 00 } $stack_strings_4 = { 63 00 25 00 } condition: // MZ signature at offset 0 and ... uint16(0) == 0x5A4D and // ... PE signature at offset stored in MZ header at 0x3C uint32(uint32(0x3C)) == 0x00004550 and filesize < 3000KB and #switch_control > 8 and all of ($stack_strings_*) and $byte_manipulation }