Skip to content
Technical Analysis Mltbackdoor

Technical Analysis Mltbackdoor

www.zscaler.com June 25, 2026

In May 2026, Zscaler ThreatLabz identified a new malware family that we track as MLTBackdoor that is likely leveraged by a ransomware-related threat actor. MLTBackdoor has been observed by ThreatLabz being delivered in a multi-stage ClickFix infection chain. MTLBackdoor supports a set of commands like downloading and uploading files from the victim’s system. However, one of the most powerful features is the ability to load Beacon Object Files (BOFs) to expand its capabilities.

In this blog post, ThreatLabz provides a technical analysis of MLTBackdoor, including its core features, configuration, obfuscation, network communication protocol, and capabilities.

In the following sections, ThreatLabz examines the technical details of MLTBackdoor, including its obfuscation methods, anti-analysis techniques, network protocol, and supported commands.

The infection chain begins with a ClickFix lure on an automotive-related web page. If the victim copies, pastes, and executes the ClickFix content, the following commands are executed:

The downloaded file, retrieved from a domain that appears in that day’s domain DGA set (discussed later), is a compressed archive that contains the following files:

The endpointdlp.dll file decrypts the RC4-encrypted data.bin file, which contains the second stage of the infection chain. The decryption key is stored in its own header and has the following structure:

The decrypted payload is the MLTBackdoor itself. It first performs a self-update, then reuses the endpointdlp.dll filename and sideloads it via a legitimate signed Microsoft Defender mpextms.exe executable.

MLTBackdoor hinders analysis by using indirect system calls and API hashing, along with different obfuscation methods applied at compilation time using an LLVM-based obfuscator. These methods are described in the following sections.

The Mixed Boolean-Arithmetic (MBA) obfuscation technique takes a normal arithmetic expression like x + y and rewrites it as something mathematically equivalent but much more difficult to follow. For instance, the following figure shows part of the DGA function, where numerous mathematical operations are performed solely to add noise:

Figure 1: MBA obfuscation in MLTBackdoor’s DGA function.

A single increment turns into several lines. For example:

But if we replace ~x with -x - 1 they collapse, as shown in the table below:

v275 = 2 * (-163 * v248 - 164 * ~v248) - 328;

v276 = 22*(~v261&~v275) + 24*(v275&v261) + 23*(~v275&v261) + 23*(~v261&v275) + 22;

v277 = 28 * ~(-45*v276 - 46*~v276 - 46) + 29 * (-46*~v276 - 45*v276) - 1306;

v279 = -22*v248 - 22*~v248 - 22;

Table 1: Simplified MLTBackdoor MBA examples.

MLTBackdoor makes extensive use of this technique to the point that around 95% of its code is just extra, unnecessary calculations.

MLTBackdoor also uses control flow flattening (CFF). CFF replaces every if/else block with a large while(1){ switch(state) { … }} structure, so a function ends up looking similar to the following figure:

Figure 2: CFF obfuscation in MLTBackdoor’s command-handling function.

This method essentially uses a few instructions to transform a straightforward function into something that is difficult to understand. The obfuscator shuffles blocks which obscures execution order with different state assignments.

MLTBackdoor performs two additional steps to complicate analysis further:

The pseudocode for these steps is shown in the figure below.

Figure 3: Example of MLTBackdoor’s CFF state obfuscation and MBA.

Unlike most malware families, string values are not encrypted or encoded. Instead the strings are constructed at runtime byte-by-byte on the stack. On its own, this isn’t particularly remarkable, but combined with MBA and CFF it results in fragmented strings. For example, the C2 string may be constructed by calling two functions and stitching them together as follows:

Figure 4: MLTBackdoor stack-based strings constructed in two separate functions and concatenated together.

Taken together, these routines construct the full cwrtwright[.]com C2 domain. However, because the string is built across a flattened state machine, the only reliable way to recover it is to trace the state transitions, defeating tools like FLOSS that look for consecutive characters in memory.

MLTBackdoor resolves everything at runtime (Win32 APIs, system calls, and Beacon Object File symbols) using DJB2 hashing.

The main difference in MLTBackdoor’s API resolution is how it feeds the strings to the algorithm. ThreatLabz observed the following three cases:

Many security products hook WinAPI functions to detect abnormal calls or activity. However, by skipping user mode APIs and the kernel32 wrappers around a system call and going directly to the address where the actual system call is made, it’s possible to evade detection. MLTBackdoor follows this approach using a Hell’s Gate-style technique in three steps:

Startup builder: When first running, MLTBackdoor walks and matches ntdll exports against a list of 31 “Nt” hashes and builds a runtime table that looks like this:

Syscall Gadget Address

0x15A5ECDB (NtCreateFile)

0x7FFE12340A18 (ntdll + 0x9D2C8)

Table 2: Example MLTBackdoor system call table.

Figure 5: MLTBackdoor indirect system call trampoline.

The full list of kernel “Nt” functions is available in the Appendix .

MLTBackdoor includes multiple anti-analysis techniques to detect debuggers and sandboxed environments, but detection does not halt execution.

Instead, MLTBackdoor aggregates the results of 10 distinct checks into a bitmask and sends it as part of its initial request, as described later in the Network communications section. The following table lists the checks and their associated flags:

Checks whether the hypervisor bit is set; if so, queries leaf 0x40000000 to get the vendor ID and compares it against these values: VMwareVMware , VBoxVBoxVBox , XenVMMXenVMM and KVMKVMKVM .

If there are no matches in the step and the vendor ID is anything else, including Microsoft HV , it checks whether leaf 0x40000003 has EBX[12] set, allowing Win10/11 hosts with Virtualization-Based Security (VBS) enabled to pass, otherwise it is also flagged

Performs a minimum of 5 RDTSC + CPUID + RDTSC loops to measure the number of cycles required, which can indicate emulation, virtualization, and debugging.

Queries NtQueryInformationProcess with the ProcessDebugPort ProcessInformationClass to detect a debugger.

Iterates through all the names of the running processes, calculates the SHA256 hash, and compares it against a hardcoded list of hashes (the full list of cracked hashes is available in the Appendix ).

Compares a list of stack-built strings (such as x64dbg , x32dbg , ollydbg , windbg , idapro , process monitor , process explorer , wireshark , fiddler , dnspy and cff explorer ) to identify window titles retrieved by calling EnumWindows and GetWindowText .

Sandboxes drivers check

Compares drivers loaded with the following name list: vbox , vmci , vmhgfs , virtio , vioscsi , and xenbus .

Checks if RAM is below 2GB.

Checks if the number of processors is 1.

Checks whether the uptime is less than 5 minutes.

Table 3: MLTBackdoor anti-analysis checks and flags.

MLTBackdoor includes a small set of built-in commands:

What really increases MLTBackdoor’s capabilities, however, is the BOF loader functionality.

A Beacon Object File (BOF) is a Microsoft Common Object File Format (MS-COFF) compiled file, containing sections, a symbol table, and relocations, that malware can map and execute within its own process, then free. Using BOFs for post-exploitation tasks was first popularized by Cobalt Strike, and there are now hundreds of community-made BOFs for a wide range of tasks.

MLTBackdoor’s BOF dispatcher follows these steps:

MLTBackdoor’s BOF loader is compatible with Cobalt Strike beacons that rely on the small subset of DJB2-hashed imports shown in the table below:

Table 4: MLTBackdoor BOF imports.

What differentiates this BOF loader is that, in addition to the small set of imports above, it includes 19 additional cases that route calls to MLTBackdoor’s own indirect system call wrappers described in the sections. These are shown in the table below:

Resolved System Call Wrapper

BeaconNtAllocateVirtualMemory

BeaconNtProtectVirtualMemory

BeaconNtFreeVirtualMemory

BeaconNtQueryInformationFile

BeaconNtSetInformationFile

BeaconNtQueryDirectoryFile

BeaconNtQuerySystemInformation

BeaconNtOpenProcessToken

BeaconNtQueryInformationToken

BeaconNtDeleteValueKey

Table 5: Indirect system calls beacon imports supported by MLTBackdoor.

MLTBackdoor uses a custom encrypted binary protocol over TLS on port 443 with a fixed path ( /api/v1/telemetry ) and User-Agent ( Microsoft-Delivery-Optimization/10.1 ) to masquerade as legitimate traffic. Network communications are encrypted using an Elliptic-Curve Diffie-Hellman (ECDH) key exchange with NIST curve P‑256 to generate a shared secret. MLTBackdoor generates a new key-pair per session, and performs ECDH with a P‑256 public key shared by the C2 server. The result is concatenated to both the session’s public key and the C2 server’s public key, and then hashed with SHA256 to derive the shared secret, which is then used as an AES-256-GCM session key. All subsequent messages are then encrypted with this AES session key with a random 12 byte nonce.

Some MLTBackdoor samples use hardcoded stack-built C2 domains in combination with a DGA, while others rely on either hardcoded domains or the DGA alone. The DGA is designed to maintain control of infected systems if the C2s are unreachable. An MLTBackdoor DGA script, including DGA domains through July 2025, is available in the ThreatLabz GitHub repository .

MLTBackdoor’s DGA algorithm is a deterministic date-based algorithm that generates a new domain per day. The DGA algorithm is shown below in Python:

Interestingly, the domain created for April 29, 2026 ( rs2y15sungu[.]com ) was used not only for C2 communication, but also used for the distribution campaign that day, as explained in the Initial infection chain section.

ThreatLabz dubbed the name, MLTBackdoor, based on the first 4 magic bytes of the network communication protocol’s header. The header, which is present in every communication (client- and server-side) follows the structure below:

The magic bytes are 0x014D4C54 (or \x01MLT ). The session_id consists of 4 random bytes generated via BCryptGenRandom (regenerated on each handshake). The supported msg_type values are shown in the table below:

Check-in containing host information.

Sends a sleep command.

Command execution result.

Elliptic-Curve Diffie–Hellman (ECDH) key exchange.

Table 6: MLTBackdoor protocol message types.

As mentioned above, MLTBackdoor uses ECDH to generate a shared secret that is used as an AES session key. In order to perform the key exchange, MLTBackdoor first sends the session’s P-256 public key to the C2 server with the following structure:

Below, is an example message in this format:

Figure 6: Example MLTBackdoor ECDH key exchange message.

Once this key exchange is complete, MLTBackdoor uses the shared AES-256-GCM key to encrypt and decrypt subsequent messages. Each packet includes an encrypted payload immediately following the header, using the structure shown below:

Despite being relatively new, MLTBackdoor is already a formidable post-exploitation malware framework that provides filesystem access capabilities and expandable functionality with a BOF loader. Most MLTBackdoor binaries leverage CFF and MBA to complicate reverse engineering along with techniques to evade malware sandboxes and analysis environments. MLTBackdoor also uses a custom binary encrypted network protocol with a DGA for backup communications to hinder takedown attempts by researchers and law enforcement for additional resiliency.

Zscaler’s multilayered cloud security platform detects indicators related to MLTBackdoor at various levels. The figure below depicts the Zscaler Cloud Sandbox, showing detection details for MLTBackdoor.

Figure 8: Zscaler Cloud Sandbox Report for MLTBackdoor.

In addition to sandbox detections, Zscaler’s multilayered cloud security platform detects indicators related to MLTBackdoor at various levels with the following threat names:

1e41c7bfaa6aa3b93b6cc024274a10e33f3e12fe7c98c1db387ef8927f9d1984

46b2155c1e71b840d4b7a2e94410b89a61e2446523e6f497206d402eb02e0e93

Archive with stage one loader and encrypted MLTBackdoor.

9e52cc90cff150abe21f0a6440e86e0a99ff383b81061b96def8948e21d0ac66

MLTBackdoor with domains and DGA.

ced6b0f44410f6133ad63b61e04613a8b56cc3338d7b34497540e9541163e7ec

MLTBackdoor DGA only.

1d09357b6a096fdc35cd5c873eed15665d6b3c879d20c8cf01e6bca0005512cf

MLTBackdoor DGA only.

2cd88d5280a61714836f5f07a16df190911c5b952af2998dbbcda910b3b1c494

MLTBackdoor domains only.

d34e4038c5c80728f9648ba84833f69bc1ccea82e2e8e748b7b7f02fb687b92b

MLTBackdoor update sideload archive.

DGA domain also used in the distribution campaign.

powwowski[.]com/payloads/update.zip

MLTBackdoor update URL.

NtAllocateVirtualMemory

NtProtectVirtualMemory

NtQueryInformationProcess

NtQuerySystemInformation

NtQueryInformationToken

NtQueryInformationFile

9e8777661a1ad9c983f03060f0a04a3244daac8c3639b3eb1bbce29355bc6c10

e063358d88290c5d05d58594da341690024cf7fa57408a3874899f10e56d8bc8

9c8384f93b9d347a716ea3e55b9a01250473f667b95d467126c048256b0049e9

ed80408eb9092301e628791e7a9a2e86c6f496a9afd7b56d7c1a1684b1b87251

57cfa4cbf3d6cbd13973bbf0625bfa6d20677abb0a6e6bec9a6bf587799b56fa

b2e1f5aedb049092135e90c153f5bd386aa81cd2df355d90912dcba33c3176e5

d51ce268a585657226510586e47c58a47cee2f2bf2049008760c58dc4e6ba650

75635009a00cb26d2f532ad974ede59785a18e4b30132a1f585108589394ba5a

a5a5b6257304eefe5212edfd8c0ad27f77357c5046a7acb8eb7ba72ed4bad9e0

0ca2edf9982f58e63cc49ba69fb9a88762d1f220ed9482810b512d4add0f8f0b

ac66c2d47cdefb221822b9074c9810434e8da702a0694139aa9177557e6b292b

d8f291a459c1acc53f9c8dccb1049bfe2d3b00c7a86d50542dc7fd7b0628ea6a

ab0541672b57cd3b7e8c973fb9fcbecd18b7fe14c1c2f571e7a2f2921919b500

fe8557d454adc7a91162495628d269738b92b4b5d7e5d620fc3f38c27a9a41a7

fc8649547ad0ece93ad82de75cb6b875be0873774de89b78546c9a66d2043087

6870e3bbf2447c96d21682caf943cf31c2e8c21c8cfb91a5092eab1c9e5f19ae

0f7463aecc3920f9e2b32ab9d77861a9e69a3e8aa28d06b4602195623312331d

b32461077b2e04145b87e9b5177a331dfd2248b81570aa96b9a302dffe643f70

687968b820fd7a6bedb03d644410c663b1720ad76519e2dcf98d61df498470df

4c357a29b202b77e7db190d359ead2dfd3f8869c6808b96bfa8bee82525bb2a2

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.

Extracted Entities

Attack Types (1)

SHA256 Hashes (27)

0ca2edf9982f58e63cc49ba69fb9a88762d1f220ed9482810b512d4add0f8f0b0f7463aecc3920f9e2b32ab9d77861a9e69a3e8aa28d06b4602195623312331d1d09357b6a096fdc35cd5c873eed15665d6b3c879d20c8cf01e6bca0005512cf1e41c7bfaa6aa3b93b6cc024274a10e33f3e12fe7c98c1db387ef8927f9d19842cd88d5280a61714836f5f07a16df190911c5b952af2998dbbcda910b3b1c49446b2155c1e71b840d4b7a2e94410b89a61e2446523e6f497206d402eb02e0e934c357a29b202b77e7db190d359ead2dfd3f8869c6808b96bfa8bee82525bb2a257cfa4cbf3d6cbd13973bbf0625bfa6d20677abb0a6e6bec9a6bf587799b56fa6870e3bbf2447c96d21682caf943cf31c2e8c21c8cfb91a5092eab1c9e5f19ae687968b820fd7a6bedb03d644410c663b1720ad76519e2dcf98d61df498470df75635009a00cb26d2f532ad974ede59785a18e4b30132a1f585108589394ba5a9c8384f93b9d347a716ea3e55b9a01250473f667b95d467126c048256b0049e99e52cc90cff150abe21f0a6440e86e0a99ff383b81061b96def8948e21d0ac669e8777661a1ad9c983f03060f0a04a3244daac8c3639b3eb1bbce29355bc6c10a5a5b6257304eefe5212edfd8c0ad27f77357c5046a7acb8eb7ba72ed4bad9e0ab0541672b57cd3b7e8c973fb9fcbecd18b7fe14c1c2f571e7a2f2921919b500ac66c2d47cdefb221822b9074c9810434e8da702a0694139aa9177557e6b292bb2e1f5aedb049092135e90c153f5bd386aa81cd2df355d90912dcba33c3176e5b32461077b2e04145b87e9b5177a331dfd2248b81570aa96b9a302dffe643f70ced6b0f44410f6133ad63b61e04613a8b56cc3338d7b34497540e9541163e7ecd34e4038c5c80728f9648ba84833f69bc1ccea82e2e8e748b7b7f02fb687b92bd51ce268a585657226510586e47c58a47cee2f2bf2049008760c58dc4e6ba650d8f291a459c1acc53f9c8dccb1049bfe2d3b00c7a86d50542dc7fd7b0628ea6ae063358d88290c5d05d58594da341690024cf7fa57408a3874899f10e56d8bc8ed80408eb9092301e628791e7a9a2e86c6f496a9afd7b56d7c1a1684b1b87251fc8649547ad0ece93ad82de75cb6b875be0873774de89b78546c9a66d2043087fe8557d454adc7a91162495628d269738b92b4b5d7e5d620fc3f38c27a9a41a7