MontysThree: Industrial espionage with steganography and a Russian accent on both sides

By GIXnews

In summer 2020 we uncovered a previously unknown multi-module C++ toolset used in highly targeted industrial espionage attacks dating back to 2018. Initially the reason for our interest in this malware was its rarity, the obviously targeted nature of the campaign and the fact that there are no obvious similarities with already known campaigns at the level of code, infrastructure or TTPs. To date, we consider this toolset and the actor behind it to be new. The malware authors named the toolset “MT3”; following this abbreviation we have named the toolset “MontysThree”.

Following the MT3 abbreviation we named the toolset MontysThree

The malware includes a set of C++ modules used for persistence, obtaining data from a bitmap with steganography, decryption of configuration tasks (making screenshots, fingerprinting the target, getting the file, etc.) and their execution, and network communications with major legitimate public cloud services such as Google, Microsoft and Dropbox. MontysThree is configured to search for specific Microsoft Office and Adobe Acrobat documents stored in current documents directories and on removable media. The malware uses custom steganography and several encryption schemes: besides custom XOR-based encryption, the modules rely on 3DES and RSA algorithms for configuration decryption and communications.

MontysThree contains natural language artifacts of proper Russian language and configuration that seek directories that exist only on Cyrilic localised Windows versions. While most external public cloud communications use token-based authorisation, some samples contain email-based accounts for them, which pretend to be a Chinese lookalike. We consider these names to be false flags. Many more artifacts suggest that the malware was developed by a Russian-speaking actor and is targeting Cyrillic Windows versions.

How the malware spreads

The initial loader module is spread inside RAR self-extracting archives (SFX) with names related to employees’ phones list, technical documentation and medical test results. There are no lures, only PE files (masquerading a .pdf or .doc file), but such titles are now a typical trick used in spear-phishing – “corporate info update” or “medical analysis results”. One of the loaders (MD5 da49fea229dd2dedab2b909f24fb24ab) has the name “Список телефонов сотрудников 2019.doc” (“Employee phone list”, in Russian). Other loaders have the names “Tech task.pdf” and “invitro-106650152-1.pdf”. The latter is the name of a medical laboratory in Russia. All of them seem like typical spear-phishing tricks. The SFX script is as follows:

Setup=rundll32.exe "invitro-106650152-1.pdf",Open

On execution, the SFX script calls the Open() function (we’ll return to this exported name) of the decompressed loader executable in the %TEMP% directory and deletes it. Judging by the filename, it most likely imitates medical analysis results, given that “Invitro” is a prominent medical laboratory in Russia. This initial PE32 is the first loader module.

How modules work and communicate

Execution flow of MontysThree’s modules

The diagram above shows the overall execution flow of the MontysThree modules. Four modules and their features are listed in the table below. The modules share common communication conventions. When dealing with shared data, such as the configuration and detailed execution log, the malware initializes the structure in thread local storage (TLS), which in its turn refers to heap structures. Interestingly, besides RAM, the execution log is stored on disk in a file, encrypted with a one-byte XOR.

The entry point DllEntryPoint() works just like a construtor, which allocates the structure with TlsAlloc() and saves it in a global variable. Modules must export a function named Open(), which takes no parameters (but could parse the command line) and returns a four-byte error code.

Module name

This anti-detection module is in charge of custom steganography, kernel module decryption.

This kernel (main) module is in charge of decrypting the config XML, then parsing and executing the corresponding tasks in it.

Network module to communicate with Google, Microsoft, Dropbox legitimate public cloud services, as well as with WebDAV sources. The module is able to make requests through RDP and Citrix in a naive way using legitimate clients.

Persistence module is a Windows Quick Launch .lnk modifier. With this naive persistence method users would run the Loader module by themselves every time along with the browsers from the Windows Quick Launch toolbar.

Now let’s take a look how the developers mixed strong modern cryptography standards with custom XOR-based ones.

Encryption in use

To decrypt the kernel module the initial loader uses a custom algorithm.

Logs encryption
The malware logs exist in memory as well as in encrypted files on disk at the same time. In RAM the developers store the logs in plaintext, on disk they use one-byte XOR.

Config encryption
Kernel module uses strong encryption algorithms. Configuration data is encrypted with 3DES and the key is encrypted using RSA. All the keys – RSA public/private as well as encrypted 3DES – are stored inside the module’s .data section.

Network module encryption
Initially encrypted HttpTransport is made of four binary blobs stored in the kernel module. The kernel concatenates them and decrypts them with a custom XOR-based algorithm. A round key of four bytes length is used

Communications encryption
The encryption algorithm is RSA using the same public and private keys stored inside the kernel module .data section.


Loader module: Bitmap decryptor and next stage launcher

If the filename of the bitmap containing the steganography-encrypted data is provided to the loader as an argument, the loader decrypts the next stager from the pixel array. In the first iteration, it extracts the steganography parameter data. To do so, the algorithm takes the last bits of the bytes.

The IID, IParam and ISize parameters are kept in the first 384 bytes of the pixel array, meaning that only the last bit of every pixel array’s byte is needed. As a result, the module gathers 48 bytes of steganography configuration structure with the fields, determining the next decryption stages.


Determines one or two decryption layers would apply to the following pixel array.

Determines which bits from pixel arrays bytes would form the next kernel module.

The decrypted kernel module’s resulting size.

After extracting the steganography parameters, the next stager is decrypted using a two-step algorithm. Firstly, the IParam algorithm chooses the bits from the pixel array’s bytes. Then, if IID equals 2, a custom dexoring operation using a four-byte round key is applied on the gathered bytes. The initial key for the first four-byte decryption has the hardcoded value 0x23041920. Then the formula for the round XOR key for the next bytes is:
key ^= 8 * (key ^ (key

Source:: Securelist