This module was originally developed by @zerosum0x0 and @ryhanson, then further moved along by @OJ, @zeroSteiner, @rickoates, @wvu-r7, @bwatters-r7, @wchen-r7, @tsellers-r7, @todb-r7 and others. The module was ported from a Python external module to a native Ruby module in order to take advantage of the RDP and other library enhancements in Metasploit. The original Python module is in the commit history if you wish to examine and compare it the the current implementation.

The module currently targets 64-bit versions of Windows 7 and Windows Server 2008 R2. For Windows Server 2008 R2, a registry entry needs to be modified to enable heap grooming via the RDPSND channel, though there remain other possibilities to explore for using alternate channels that are enabled by default on all Windows OSes.

The module is currently ranked as Manual, as the user needs to supply additional target information or risk crashing the target host. The module implements a default fingerprint-only TARGET option that just checks for a vulnerable host and displays some initial information about the specific target OS, but the user will need to specify a more exact target based on secondary recon, or until further improvements in this module enable more accurate determination of the target kernel memory layout at runtime.

There are specific targets for bare-metal, Virtualbox, VMware, and Hyper-V, though there may be additional variables in your target environment that additionally shift the base address for grooming, so we welcome any ideas from the community for automatically detecting this instead!

From zerosum0x0:
Exploitation and Caveats:
1. You register with channel MS_T120 (and others such as RDPDR/RDPSND) nominally.
2. Full RDP handshake, I like to wait for RDPDR handshake too (code in the .py)
3. You 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. SHITTY ISSUE
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 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.
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:
* You can use the scanner methodology to detect x86/x64, but I'm still not sure how to detect OS, other than XP nominally will not use SSL and 7 will.
* The whole thing needs to be swapped to the Ruby version. Tom Sellers client is nicer and works for XP whereas this python client will not (when I wrote this module it was still in progress)
* Write the XP/2003 portions grooming MS_T120.
* Can we detect if RDPSND grooming is working or not?
* Any channels besides RDPSND/MS_T120 work for the grooming? (I've gone through about 10 books on NT RDP and reversed enough to doubt it)
https://github.com/0xeb-bp/bluekeep .. this repo has code for grooming MS_T120 on XP... should be same process as the RDPSND

When dealing with the RDP mixin it makes more sense to not expose
TCP-level things, instead it's better to talk RDP. This changeset makes
it so that consumers of the RDP mixin talk RDP only. They can access the
socket through the `rdp_socket` member if required, but the changes made
here mean they don't have to. Ultimately, this new member should be
`private` instead of `protected`, but I'm leaving it like this for now
in case it is required down the track.
I've also made the assumption that all RDP connects want TCP_NODELAY
set. This might be wrong, but I don't think it is.
From here, users can call `rdp_connect` and `rdp_disconnect` to manage
connectivity to the RDP endpoint. The `rdp_connect` function does not
register the TCP client socket as the global `sock` member on the TCP
module instance, this is to prevent the mixin from clashing with other
users of the TCP client in a given module.

This code is at the point where we SHOULD see a crash (given that the
payloads in use for kernel/user are both just As and Bs (deliberate at
this point).
Unforunately the exploit does not result in a crash. Things just keep
on going! I've looked at the difference in the traffic across the two
different exploits (py and rb) and what's clear is that the mixin is
doing a lot more work at the start.
Also, the mixin generates packets of smaller size in the way that it
encodes data (ie. it doesn't always use 2 bytes for a short value, it'll
use 1 instead if only 1 is required).
Pretty sure that the size issues aren't the problem, I think there's
something else in play. I'm at the point where diving into the RDP stuff
even more isn't inspiring so I'm hoping that opening this up to collab
will help us move forward.

For some reason the existing kernel payload doesn't work with the
exploit as it currently stands, which is very odd given that everything
else seems to be in order.
Hoping to get some help from the rest of the MSF folks as right now
I don't think I can trust the tools that I'm using.

This comment has been minimized.

The hardcoded value of GROOMBASE for VirtualBox value was wrong for me, too when eploiting Win7 SP1 Build 7601 on Virtualbox 6.0 with Win10 host. I didn't understand the exploit in detail, but I think GROOMBASE simply needs to be the start address of the NonPagedPool. I found this address by dumping the memory with VBoxManage and then running rekall as suggested by KevTheHermit on Twitter. Please see my blog for details how I did it.

I had to reduce GROOMSIZE from the default of 250 to 50, too. I think the reason was that my VM had kind of limited RAM (2GB) assigned and 250 MB of grooming is too much, therefore the connection is reset before the actual exploit is triggered.

This comment has been minimized.

edited

We have some Windows Server 2008 R2 x64 and Windows 7 SP1 x64 machines in vSphere which also result in BSOD. I suspect the NonPagedPool memory offset (or rather the GROOMBASE) may need to be another value.

This comment has been minimized.

@Et0hacker,if you don't know how to install the pull files(basic knowledge),you should not use it,just wait for this module to land.
Also,this pull request is for reporting the testing issue.If you still have a problem,you should open a issue in "issue" instead!

This comment has been minimized.

The hardcoded value of GROOMBASE for VirtualBox value was wrong for me, too when eploiting Win7 SP1 Build 7601 on Virtualbox 6.0 with Win10 host. I didn't understand the exploit in detail, but I think GROOMBASE simply needs to be the start address of the NonPagedPool. I found this address by dumping the memory with VBoxManage and then running rekall as suggested by KevTheHermit on Twitter. Please see my blog for details how I did it.

I had to reduce GROOMSIZE from the default of 250 to 50, too. I think the reason was that my VM had kind of limited RAM (2GB) assigned and 250 MB of grooming is too much, therefore the connection is reset before the actual exploit is triggered.

This comment has been minimized.

The hardcoded value of GROOMBASE for VirtualBox value was wrong for me, too when eploiting Win7 SP1 Build 7601 on Virtualbox 6.0 with Win10 host. I didn't understand the exploit in detail, but I think GROOMBASE simply needs to be the start address of the NonPagedPool. I found this address by dumping the memory with VBoxManage and then running rekall as suggested by KevTheHermit on Twitter. Please see my blog for details how I did it.

I had to reduce GROOMSIZE from the default of 250 to 50, too. I think the reason was that my VM had kind of limited RAM (2GB) assigned and 250 MB of grooming is too much, therefore the connection is reset before the actual exploit is triggered.

Just for anyone who was having trouble making this work (like myself), when you calculate your new start memory address for the NonPagedPool, make sure you add the correct amount of ff's back into the memory address. So I had to have 5 f's in my memory address to get it working.

This comment has been minimized.

Windows 10 computer / VMWARE Workstation 15 / Windows 2008R2 guest with RDP.
I had to adjust the GROOMBASE (fa8018c04000) and GROOMSIZE (also to 50 MB).
Before i got "Error: Connection reset by peer".
After changing values exploit and reverse shell was succesfull

With vmss2core.exe from VMWARE and rekall it was easy, see the blog entry.

See here:

The hardcoded value of GROOMBASE for VirtualBox value was wrong for me, too when eploiting Win7 SP1 Build 7601 on Virtualbox 6.0 with Win10 host. I didn't understand the exploit in detail, but I think GROOMBASE simply needs to be the start address of the NonPagedPool. I found this address by dumping the memory with VBoxManage and then running rekall as suggested by KevTheHermit on Twitter. Please see my blog for details how I did it.
I had to reduce GROOMSIZE from the default of 250 to 50, too. I think the reason was that my VM had kind of limited RAM (2GB) assigned and 250 MB of grooming is too much, therefore the connection is reset before the actual exploit is triggered.

Just for anyone who was having trouble making this work (like myself), when you calculate your new start memory address for the NonPagedPool, make sure you add the correct amount of ff's back into the memory address. So I had to have 5 f's in my memory address to get it working.

This comment has been minimized.

I was using Win 10 Pro / VMWare 12 pro / Win 7 - 6.1.7600.
I've modified the GROOMBASE value with my VM's NonPagedPool value, which has been generated using Rekall. Also modified the GROOMSIZE value.
For some reason it is not working for me and ends up in BSOD.

Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.