ĢTV

This is some text inside of a div block.
Glitch effect

Oh No Cleo! Malichus Implant Malware Analysis

Contributors:
Special thanks to our Contributors:
Glitch effectGlitch effectGlitch effect
Glitch banner

Summary - CVE-2024-55956

ĢTV previously reported on malicious activity from the exploitation of a 0-day vulnerability in Cleo software. The malware being delivered through this exploitation has now been analyzed and a technical breakdown of a new family of malware we’ve named [.highlight]Malichus[.highlight] is included in this post. The name is a play on the word Cleopatra and comes from Malichus I, who is noted to have burned Cleopatra’s navy fleet in revenge for his losses throughout a war that Cleopatra had initiated.

Figure 1: Overview of the attack chain

Technical Analysis

Stage 1: Powershell Downloader

The malware makes use of a small PowerShell loader that sets up the host for further exploitation. It is stored as a base64 blob and gets decoded and is used to execute a Java Archive that gets deployed to the system with the name [.highlight]cleo.[numerical-identifier][.highlight].

The loader creates a TCP connection to a C2 IP address to retrieve a second stage payload. The formatted loader is shown below:

Figure 2: Formatted Stage 1 PowerShell Downloader script

The loader also sets a variable called [.highlight]Query[.highlight] which is used for retrieving the C2 address used in a subsequent Java backdoor and the victim IP address identifier. The C2 IP address and second stage dropper are different for each identified payload by ĢTV.

Stage 2: Java Downloader

The downloaded second stage archive is decrypted by the loader using a unique AES key per payload. Upon decrypting and decompiling the second stage downloader, this contained a manifest file indicating it would run the start class upon execution.

Figure 3: Java Downloader MANIFEST.MF file

Starting from the main method, the backdoor will get the environment variable query and repair it to make it a valid base64 string. That decoded value contains the AES key, a unique value required to download stage 3, and the IPs of the C2 server and the victim host. A request is then sent to the C2 using that base64 encoded value appended with [.highlight]TLS v3[.highlight].

Figure 4: Annotated Decompilation of main method in stage 2

A CyberChef recipe showing the output of this is as follows:

Figure 5: View of CyberChef with decoded IP addresses (victim’s address redacted)

Using the allocated space we’ve renamed as [.highlight]recvBuf[.highlight], the dropper then keeps accepting bytes until the full stage 3 payload has been downloaded. Then using the AES key and hardcoded IV, it decrypts the downloaded data which will yield an intentionally corrupted zip. They then repair the header by cutting off the first two bytes ([.highlight]cC[.highlight] in the example we analyzed), and move onto extraction and loading.

Figure 6: Annotated decompilation of the decryption routine

A CyberChef recipe showing the output of this is as follows:

Figure 7: View of decrypted zip file within CyberChef

Finally, the backdoor will unzip the downloaded archive using the provided helper method, and dynamically resolve the classes it contains.

Figure 8: Decompilation of start and findClass methods

Figure 9: Decompilation showing calls to start and dynamic loading of class files

Stage 3: Java Backdoor / Post Exploitation Framework

The final stage is a modular Java based post exploitation framework which contains a significant amount of functionality. It is composed of 9 class files, with the primary driver being the Cli class loaded by the previous stage. The framework supports both Linux and Windows however ĢTV only observed usage on Windows.

Cli

This begins with a public class called [.highlight]Cli[.highlight] that takes three parameters passed to it from the stage 2 downloader that are stored in the variables [.highlight]host[.highlight], [.highlight]cliid[.highlight], and [.highlight]stage1fn[.highlight].

Figure 10: Decompilation of Cli class assigning variables before executing run method

The passed parameters from stage 2 correspond to: 

  1. The C2 IP address retrieved from the query parameter 
  2. The exploited system IP address and associated port retrieved from the query parameter (used as a unique victim identifier) 
  3. The file name stored in the environment variable f from the downloader (in this case [.highlight]cleo.2607[.highlight])

The class has a number of static variables defined that are used throughout the payload including one that identifies if it is operating on a Windows operating system or not.

Figure 11: Decompilation of class instance variables used by Cli

Figure 12: Decompilation of Cli class retrieving hostname and determining if it is running on Windows

This runs the main [.highlight]run()[.highlight] method and subsequent [.highlight]runDelFileCmd()[.highlight] method to delete the first stage payload (downloader) from disk ([.highlight]cleo.2607[.highlight]) using either PowerShell or Bash depending on whether the system was identified as Windows or not.

Figure 13: Decompilation of runDelFileCmd method showing deletion of stage1 payload from disk

The run method is responsible for using the [.highlight]SrvSlot[.highlight] class to queue up connections to the C2 IP address retrieved from the previous query parameter on port 443. This class extends the class [.highlight]Slot[.highlight] allowing it to access the static variable [.highlight]st[.highlight] which is used to send custom commands to the implant from the connected C2 server and is part of a custom C2 protocol. These connections will continue until the number of connections is 5 or more, and the variable [.highlight]st[.highlight] is set to something other than 200 or 500.

Figure 14: Decompilation of run method showing ishell and prs-conf commands

This class also contains two helper methods: [.highlight]l[.highlight] (logging) and [.highlight]dmp[.highlight] (hex dump). The first is used throughout the implant to log various data to a log buffer. The second allows the malware to create a valid hexdump from a provided byte array, which is then logged using the logging helper function. The hexdump function is likely for debugging purposes as it isn’t called anywhere in the implant.

Figure 15: Decompilation of logging function

Figure 16: Decompilation of annotated hex-dump function which is never used.

Dwn

A zip file management class for uploading, packaging, and handling zip files for the operators to read and collect files or directories. A number of variables are used in this class in addition to a method named [.highlight]Dwn[.highlight] responsible for logging how much time has passed since the last update and assigning a queue of files to be uploaded to the C2 server stored in an arraylist called [.highlight]lvs[.highlight].

Figure 17: Decompilation of Dwn class

The class contains a tick method used for keeping track of time passed and sending a status update to the C2 server if more than 5 seconds had passed since the last update.

Figure 18: Annotated decompilation of tick method

The [.highlight]setStat[.highlight] method called by tick will set fields of the newly created tick packet with information about the current state of the [.highlight] Dwn[.highlight] class.

Figure 19: Annotated decompilation of the setStat method

Interestingly this class also has a check called [.highlight]tick2[.highlight] responsible for tracking the state of the files being exfiltrated, and managing the queue of files to be exfiltrated.

Figure 20: Decompilation of tick2 method

The [.highlight]addFile[.highlight] method is used to add the files to the queue for exfiltration.

Figure 21: Decompilation of addFile method

This is supported by the [.highlight]readFile[.highlight] and [.highlight]write[.highlight] method to retrieve the file from disk.

Figure 22: Decompilation of the readFile method

Figure 23: Decompilation of write method

Other methods [.highlight]zipOpen[.highlight], [.highlight]zipClose[.highlight], and [.highlight]getCurrZipSize[.highlight] use a new instance of the [.highlight]Mos[.highlight] class but other than that are fairly self-explanatory.

Figure 24: Decompilation of zipOpen method

Figure 25: Decompilation of zipClose method

Figure 26: Decompilation of getCurrZipSize

DwnLevel

A simple class for managing an array of files preparing for zip archival and uploading to the attacker. It is used primarily in the Dwn class and is just for keeping state.

Figure 27: Decompilation of DwnLevel class

Mos

A small class for handling multi-archive zip files. In order to optimize zip file sending, zip files are split up for every 262154 bytes and then archived with ZipIDs during exfiltration.

This appears to be equivalent to 2 of their custom protocol packet lengths of 131072 bytes.

Figure 28: Decompiled Mos class, including getSize, write, and close methods

Proc

Proc contains implementations of the tasks that can be performed by the malware as well as a few reconnaissance capabilities on the victim’s machine. These commands are parsed in the [.highlight]SlotSrv[.highlight] class.

The [.highlight]Proc[.highlight] class allows the remote attackers to primarily issue execution commands and read from configuration files using the [.highlight]run[.highlight] function. The [.highlight]ishell[.highlight] command (interactive shell) is a command that uses the [.highlight]pipeMode[.highlight] function to handle interactive shells indicating the malware has capability to allow an attacker to go ‘hands-on-keyboard’ and interactively run commands through a terminal.

This aligns to activity identified by the ĢTV SOC when a [.highlight]nltest[.highlight] command was seen to be interactively run by a threat actor. The run function is also the primary method used to retrieve Cleo software configuration via the [.highlight]prs-conf[.highlight] command.

Figure 29: Decompilation of run method

The confParser method will retrieve elements from within a configuration file located at conf/Top.xml on disk and retrieve all the host values from within this. For each host identified it will attempt to retrieve the corresponding xml file within hosts/<hostname.xml> and parse this to be used in a function loadUserDirs.

Figure 30: Decompilation of confParser method

The function [.highlight]loadUserDirs[.highlight] is used to parse any [.highlight]Host[.highlight] or [.highlight]Mailbox[.highlight] nodes within the host xml file and extract the aliases defined within this file. In addition this will also parse the file for references to several directories which are sent alongside the alias they are paired with.

  • Default Home Directory
  • FTP Root Path
  • Inbox
  • Sentbox
  • Outbox
Figure 31: Decompilation of loadUserDirs method

Figure 32: Decompilation of mailbox parsing portion of loadUserEnv method

This includes a method to replace any custom variables named [.highlight]Homedirectory[.highlight] and [.highlight]Homedirectorytype[.highlight] that may have been defined in the application instance with their corresponding value.

Figure 33: Decompilation of replCustomVars method

This shows that the malware author had an understanding of specific configuration files used within the Cleo software, and was interested in understanding what types of trading relationships a Cleo Harmony, VLTrader, or LexiCom instance had been configured with in addition to where [.highlight]payload files[.highlight] such as files sent or received between these businesses resided on disk.

Interestingly this contained a method called [.highlight]checkDir[.highlight] that appears to be looking for if a directory is readable or not; however, this was never called in the code so may have been used for debugging purposes or it is a feature which has not yet been implemented.

Figure 34: Decompilation of checkDir method

SFile

This class allows the attackers to perform basic read and write operations on the filesystem using FileOutputStream and FileInputStream classes. This is referenced in file handling procedures within the [.highlight]SvrSlot[.highlight] class.

Figure 35: Decompilation of SFile class

There are also a number of helper functions that help SFile read, write, and manage files:

Figure 36: Decompilation of SFile helper methods

ScSlot

This is a multi-channel communication link with the channel used for handling asynchronous communication, each ScSlot acts as a unique pipeline for data using the SvrSlot class.

Figure 37: Decompilation of ScSlot class with evConnect, evRead, and tick methods

Slot

This class is responsible for establishing and managing the connection to the C2 server. It initializes two buffers for sending and receiving data:

Figure 38: Decompilation of Slot class with connect method

SrvSlot

This class is mainly involved with receiving and sending responses from the C2 server. Upon connection to a C2 server this class will log the packet number using the method [.highlight]l[.highlight] within the [.highlight]Cli[.highlight] class for debugging purposes before setting [.highlight]st[.highlight] to 2 indicating the connection has been successfully established and was ready to receive a hello packet. This overrides a method with the same name in [.highlight]Slot[.highlight] used to determine if connection has been established or not.

Figure 39: Decompilation of evConnect method

The hello packet sent to the C2 has a 16 byte header, the structure is as follows:

Byte Offset Value
0 - 9 Math.random() * 256.0D
10 2
11 119
12 33
13 -1
14 1
15 Cli.fIsWin ? 0 : 1

An interesting bit to note is the 10 junk bytes that are added to the front of the packet. This is likely an attempt to bypass network fingerprinting techniques, however the other bytes in the packet are static making that relatively trivial.

The first packet sent to the C2 by the malware is a “hello” packet which contains an identifier paired with a hostname if it was previously retrieved in Cli ([.highlight]cliid + “\t” + hostname[.highlight]), as well as synchronization required for encrypting further packets.

Figure 40: Decompiled and annotated pktHello method

After that hello packet is sent, the implant awaits a hello response from the server which gets parsed in the prsHelloPkt method.

Figure 41: Annotated decompilation of prsHelloPkt method

SvrSlot also contains an option to record statistics on each compromised endpoint which appears to be used for health tracking of their own C2 and endpoint.

There are three debugging options used for collecting information, the primary command is [.highlight]#dbg#[.highlight] which will collect information on how many zip file errors, how many times they encountered a server queue status, and the availability of free memory on the host.

Figure 42: Decompiled #dbg# command

The command [.highlight]#ll#[.highlight] displays how many files have been added to zips referencing the [.highlight]Dwn[.highlight] Class mentioned above.

Figure 43: Decompiled #ll# command

The command [.highlight]#lsz#[.highlight] performs information about zip file gathering, detailing the last zip file size, the ID of the zip, the zip file number, and the offset of the zip file - this is likely used to debug their multi-zip Archival process performed within the [.highlight]Mos[.highlight] class mentioned above.

Figure 44: Decompiled #lsz# command

C2 Protocol Analysis

Malichus makes use of a fully custom C2 protocol. Each incoming and outgoing packet is processed by the function in [.highlight]SrvSlot[.highlight] called [.highlight]pkt0[.highlight]. It takes in a complete packet, and calculates its CRC32 value to confirm the packet's integrity. Bytes 3 and 4 are then set to the high and low bytes of that CRC32 value before it is encrypted.

Figure 45: Annotated Decompilation of pkt0 method

After the packet’s CRC32 has been updated, pkt0 calls addEncr which is responsible for encrypting the packet. There are a few global variables that are used to manage both encryption and decryption state:

The C2 and the client must stay in sync for the encryption/decryption to work as the mutation of the state and index variables are updated by the value of the previously encrypted/decrypted byte.

Figure 46: Decompilation of the encryption routine

A similar method exists for decrypting packets but it makes use of a different set of variables to keep track of the state:

Figure 47: Decompilation of the decryption routine

As we mentioned before, the pkt0 method is the final packet constructor used by all other 6 packet types, most of which are overloaded methods of the name pkt. These each have slightly different uses but share the commonality that the first byte is the packet identifier. There are 4 generic packet types, and 2 specialized ones. Of the generic packets:

Figure 48: Annotated decompilation of pkt1

Figure 49: Annotated decompilation of pkt

Figure 50: Annotated decompilation of pkt

Figure 51: Decompilation of pkt helper

The two special packets that are used are helloPkt and zipPkt, with the helloPkt being detailed earlier:

Figure 52: Decompilation of zipdata special packet

After the packets are created by pkt0, they are put into the outbuf queue and are sent to the C2 using the evWrite method in the Slot class:

Figure 53: Decompilation of evWrite method used to send packets to the C2

Conclusion

Whilst the full extent of who created this malware and why still remains under speculation, this blog hopes to shine a light on a new family of malware targeting Cleo software, its functionality, and gives potential insight into what the malware author was hoping to achieve with this custom piece of malware.

This blog post was independently created in tandem with other industry vendors, and mostly aligns with analysis also independently performed by:

Valid C2 Packet Identifiers

Packet Number Value Explanation
1 Hello Hello packet to initialize connections
2 Channel Get C2 channel identifier
3 Data Data Packet
4 Prepare File Prepares a file for upload
5 Close Channel Kill C2 channel and any open handles
6 Echo Return received data to C2
7 Halt Resets input buffers
8 Command Run received command
9 Stop Stop process, channel, or file transfer
10 Resume Restart process, channel, or file transfer
11 Ack Confirm synchronization of processed commands
12 File I/O Status Confirms that implant is able to receive or process zip data
13 Zipdata Reassembly Reassemble zip chunks and remove them from a queue

IOCs

Filename SHA256
cleo.2607 6705eea898ef1155417361fa71b1078b7aaab61e7597d2a080aa38df4ad87b1c
Cli 0c57b317b572d071afd8ccdb844dd6f117e20f818c6031d7ba8adcbd32be0617
Dwn 429d24e3f30c7e999033c91f32b108db48d669fde1c3fa62eff9da2697ed078e
DwnLevel f80634ce187ad4834d8f68ac7c93500d9da69ee0a7c964df1ffc8db1b6fff5a9
Mos 0b7b1b24f85a0107829781b10d08432db260421a7727230f1d3caa854370cb81
Proc 1ba95af21bac45db43ebf02f87ecedde802c7de4d472f33e74ee0a5b5015a726
SFile 57ec6d8891c95a259636380f7d8b8f4f8ac209bc245d602bfa9014a4efd2c740
ScSlot 87f7627e98c27620dd947e8dd60e5a124fdd3bb7c0f5957f0d8f7da6d0f90dee
Slot 1e351bb7f6e105a3eaa1a0840140ae397e0e79c2bdc69d5e1197393fbeefc29b
SrvSlot f4e5a6027b25ede93b10e132d5f861ed7cca1df7e36402978936019930e52a16

YARA Rules

Share

Sign Up for Blog Updates

Subscribe today and you’ll be the first to know when new content hits the blog.

By submitting this form, you accept our Privacy Policy
Oops! Something went wrong while submitting the form.
ĢTV at work
Response to Incidents
Response to Incidents