Back Zscaler Targeted Attack on Middle East Govts (Part 2) | ThreatLabz - Zscaler, Inc.
This is Part 2 of our two-part technical analysis on new tools used by an East Asia-linked threat actor targeting government entities in the Middle East. After ThreatLabz published Part 1 on the TELESHIM backdoor and MIXEDKEY loader, Kaspersky highlighted a related campaign in recent reporting. Building upon our initial findings, Part 2 dives into a detailed technical analysis of BINDCLOAK , a new modular stage 3 backdoor uncovered during our investigation. As detailed later in our threat attribution section, key code similarities between BINDCLOAK and OctLurk as well as shared command-and-control (C2) infrastructure directly connect the threat actor behind OctLurk to the campaign we describe in this two-part blog series.
ThreatLabz assesses with high-confidence that BINDCLOAK is a variant of OctLurk. In this blog, we analyze BINDCLOAK’s previously undocumented C2 communication channel.
BINDCLOAK is a 64-bit modular backdoor written in C++ that uses a complex message routing mechanism to manage the C2 communication channel. In the following section, we a detailed technical analysis of BINDCLOAK and how it implements the C2 communication.
This report is based on a DLL sample with the MD5 hash 7a14a99d70d42d3f7bf72f843185fc07 that exports two malicious functions named curl_easy_escape and mn_dcode . The MIXEDKEY loader (mentioned in Part 1 of this blog series) calls the curl_easy_escape export .
BINDCLOAK first generates a unique 4-byte identifier for each victim’s machine using the hostname and the volume serial number as follows.
BINDCLOAK contains two core modules with additional plugin modules delivered from the C2 server as DLLs when the INIT_PLUGIN_MODULE command is issued by the C2 server.
Each built-in module is configured with two functions:
Upon creation, a unique ID is derived from the module type to identify each module instance as shown in the table below.
Table 1: Core BINDCLOAK modules and their types.
The C2 module connects to a C2 server via TLS over TCP connections.
All incoming and outgoing messages, including the beacon message, begin with a 28-byte header followed by the sizes of two binary blobs and the respective blobs' contents.
The Flags is a bitfield that indicates the message type (e.g., the flags 0x3001 indicate a control message, which is a special message type used for managing modules to stop or reset state).
The table below summarizes BINDCLOAK’s message structure.
*The message type will determine the meaning of the field.
Message type bitfield.
Byte count of Blob 1 data. Beacon message size: 0x620
Byte count of Blob 2 data.
Primary payload (see beacon message below).
Empty for beacon message.
Table 2: BINDCLOAK message structure.
The beacon message is the first message that BINDCLOAK sends to the C2 server to register an infected machine’s host-specific information. This message payload has the following format and a size of 1568 (0x620) bytes and will be sent in the message’s blob1 data field. The structure is shown below. Information gathered from the host machine by BINDCLOAK and the structure of the beacon message sent to the C2 server is the same as the OctLurk backdoor.
OS Version Information
Operating system version information returned in OSVERSIONINFOEX structure.
Calls GetComputerNameW to fetch the computer name.
Calls GetUserNameW to fetch the username.
Calls gethostname to fetch the hostname.
Calls GetAddrInfoW to get the local IP and formats it as %u.%u.%u.%u
System time information returned in the SYSTEMTIME structure via GetLocalTime .
Table 3: BINDCLOAK beacon message payload structure.
This C2 message encryption algorithm is the same as the one used by the OctLurk backdoor and it is summarized below.
All of this is assembled together to produce the final encrypted message that is sent over the network. The table below summarizes the structure of the encrypted message.
Total payload size (everything after this field)
Random generated 83-byte XOR key used in XOR pass 2
Compressed message size + 4. Two passes of XOR.
Uncompressed message size Two passes of XOR.
zlib compressed message. Two passes of XOR.
Table 4: Encrypted BINDCLOAK message structure.
Upon receiving the beacon message, the C2 server may respond with similarly encrypted messages (e.g., a message containing a C2 command for the BINDCLOAK command module). This will be followed by a message with the 0x2 flag bit set to initiate the routing of the C2 message to the respective modules. These messages are decrypted by BINDCLOAK in the reverse order as described earlier.
BINDCLOAK supports a total of 11 C2 commands that are described in this section.
The commands can be grouped as follows:
This group of commands collect and manage useful user and process tokens that can be used to elevate privileges for modules using the module commands.
The COLLECT_USER_TOKEN (0x58320) command attempts to log in with the provided credentials via LogonUserW and stores the user token handle on successful authentication. The domain, username, and password are sent in the message’s blob1 and the size of blob1 is 712 (0x2C8) bytes. The result for this command contains only the authentication status.
The CLEANUP_USER_TOKENS (0x22577) command clears the list of user token handles collected by the COLLECT_USER_TOKEN command.
The GET_STATUS command returns a result containing BINDCLOAK modules, all user token handles collected via the COLLECT_USER_TOKEN command, and information running processes.
BINDCLOAK uses WTSEnumerateProcessesW to collect the process ID, name, and session ID, LookupAccountSidW to collect the process user name and domain, and OpenProcessToken to check whether its token has the following flags: TOKEN_QUERY , TOKEN_DUPLICATE , and TOKEN_ASSIGN_PRIMARY . This process info can be used by the threat actor to elevate privileges for specific modules.
This set of commands start and stop specific BINDCLOAK modules. Modules need to be stopped before module start commands are issued. The start commands have no effect if the module is currently running.
The START_MODULE_WITH_USER_TOKEN (0x65918) command starts a module with the specified ID with a duplicate of the provided user token handle created using DuplicateTokenEx with TOKEN_ASSIGN_PRIMARY as the TokenType parameter. This command is likely used in conjunction with the user tokens collected with the COLLECT_USER_TOKEN command.
The START_MODULE_WITH_PROCESS_TOKEN (0x47621) command behaves similarly but uses the process token of the provided process ID. This command is likely used in conjunction with the process info collected with the GET_STATUS command.
The STOP_MODULE (0x96324) command stops the module with the specified ID and returns whether it’s still running after 5 seconds.
The REMOVE_MODULE (0x74523) command removes the module only if it is not running. Once removed, a module cannot be restarted and must be reinitialized.
The INIT_PLUGIN_MODULE (0x86321) command reflectively loads a plugin module into memory. The plugin module is stored in the first blob of the message. The loader is described in the plugin loader section.
The plugin module does not run after loading; the result contains the module ID of the loaded plugin module so the C2 can send it messages (e.g., the START_MODULE commands to start running).
The REMOVE_PLUGIN_MODULE (0x45717) command stops the plugin modules that match specific metadata flags after waiting for the specified timeout.
The command (0x64570) copies the command message into a new outgoing message. The intent or purpose of this command is currently unknown.
The SET_THREAD_EXECUTION_STATE (0x27844) command calls the SetThreadExecutionState API with the specified flags, likely to prevent the infected machine from entering sleep mode.
A plugin module is expected to be a DLL with the exports ins_ctl_db (for the initialization function) and oct_lk_col (main function).
The DLL size is stored as a DWORD at offset 0x8 (overwriting the e_cparhdr and e_minalloc fields of the DOS header). As the PE header offset at e_lfanew field in the DOS header and the SizeOfOptionalHeader field in the file header are accessed directly via their offsets (offsets 0x3C and 0x11C respectively), it’s possible that some of the fields in the DOS header and/or PE headers have been modified or zeroed to hinder static detection.
Memory for the plugin is allocated via VirtualAlloc with PAGE_EXECUTE_READWRITE (RWX) permissions and reflective loading used to load the plugin DLL into the allocated memory. When resolving imports, each DLL is loaded via RtlQueueWorkItem with LoadLibraryW and the DLL name as arguments to evade EDRs since LoadLibraryW calls from unbacked executable memory regions are considered highly suspicious by EDRs.
The plugin loader then calls the DLL entrypoint function and returns. If the entrypoint function returns FALSE, the allocated memory for the plugin for is zeroed and freed.
ThreatLabz attributes the targeted campaign described in this blog to the same threat actor behind the OctLurk backdoor used in targeted attacks against Central Asia as mentioned here .
In addition to code overlaps between the BINDCLOAK and OctLurk backdoors, there are also significant overlaps in the threat actor's infrastructure as described below.
The C2 domain identified in our investigation: cert.hypersnet[.]com uses an SSL certificate with serial number: 59fe1ef7707fe497d89f34505222862f and a Common Name: 107.175.172[.]40 . This is the same SSL certificate shared by the C2 domain .blsouqs[.]com used by the OctLurk backdoor.
As described in Part 1 of our research, during post-compromise activity, the threat actor verified network connectivity by attempting multiple ping commands to the attacker-controlled C2 servers. We observed attempts by the threat actor to ping ssl.blsouqs[.]com (C2 server of OctLurk backdoor), cert.hypersnet[.]com (C2 server of BINDCLOAK) and contacts.ftabnews[.]com .
Furthermore, the threat actor consistently reused the Tucows domain registrar to register C2 domains, as well as Njalla name servers, and infrastructure hosted on ASN 14956. Based on this infrastructure overlap and post-compromise activity, we assess with a high-confidence that ftabnews[.]com is part of threat actor's infrastructure and potentially also used as a C2 server.
While this group has primarily targeted entities in Central Asia since early 2025 as observed by Kaspersky here , the new campaign we identified in July 2026 highlights a notable expansion of operations to target the Middle East with a key focus on the energy vertical.
BINDCLOAK is a newly identified backdoor that uses a complex message routing mechanism. The sophisticated and modular nature of BINDCLOAK highlights the threat actor's development capabilities. As highlighted in Part 1 of this two-part series, the threat actor took extra measures to ensure the final stage payload is only deployed and detonated on intended targets.
ThreatLabz continues to closely monitor the latest tactics, techniques, and procedures (TTPs) of this threat actor to protect our customers and research with the security community.
Zscaler’s multilayered cloud security platform detects indicators related to this campaign at various levels.
7a14a99d70d42d3f7bf72f843185fc07
577b1cc894636f4ac5ad670b0079b9b7ade137c3
3b0c658ebaa2bae80af97f390b9b2bb20a2f815eb584b2251255e84da4fa669d
Privilege Escalation: Access Token Manipulation: Token Impersonation/Theft
BINDCLOAK can escalate privileges for modules by abusing collected user and process tokens
Privilege Escalation: Access Token Manipulation: Make and Impersonate Token
BINDCLOAK can abuse user tokens collected from authenticated with provided credentials
Stealth: Reflective Code Loading
BINDCLOAK loads plugin module DLLs via reflective DLL loading
Discovery: Process Discovery
BINDCLOAK collects information running processes and associated user and token
Command and Control: Data Encoding: Non-Standard Encoding
BINDCLOAK uses two layers of XOR encoding for C2 communication
Command and Control: Non-Application Layer Protocol
BINDCLOAK uses TLS over TCP for C2 communication
Disclaimer: This blog post has been created by Zscaler for informational purposes only and is provided "as is" without any guarantees of accuracy, completeness or reliability. Zscaler assumes no responsibility for any errors or omissions or for any actions taken based on the information provided. Any third-party websites or resources linked in this blog post are provided for convenience only, and Zscaler is not responsible for their content or practices. All content is subject to change without notice. By accessing this blog, you agree to these terms and acknowledge your sole responsibility to verify and use the information as appropriate for your needs.
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
