Find Remote Desktop hosts vulnerable to BlueKeep before someone else does


CVE-2019-0708 or “BlueKeep” is a vulnerability to be taken very serious.

Without CredSSP/NLA an attacker can get full control of a vulnerable RDP host, if he can just make an (unauthenticated) network connection to it.

Microsoft warned about it saying “… any future malware that exploits this vulnerability could propagate from vulnerable computer to vulnerable computer in a similar way as the WannaCry malware spread across the globe in 2017.”

And when they choose to release patches for out-of-support versions of Windows (XP, Vista and Server 2003), you know, that Microsoft is concerned.

This blog post will offer you a PowerShell script, that can scan your network for vulnerable Remote Desktop hots using nmap and rdpscan.

Robert Graham from Errata Security has created tools to find systems vulnerable to BlueKeep accessible from the internet, and he estimates, that there are about 1 million systems just wating to be hit by a WannaCry-like worm.

And those 1 million doesn’t even include all the hosts, that are available from the LAN on company networks but not published on the internet.

How do I find vulnerable hosts on my own network?

You might have hosts, that have not received the patch, maybe even Windows machines, you don’t even know exist.

Robert Graham has created rdpscan based on another tool.

rdpscan is amazingly simple but powerful: Run it against a range of IP’s, and it will return a list of Remote Desktop hosts and tell you, whether they are vulnerable or not.

Here the hosts are all patched against BlueKeep and two of them protected by CredSSP/NLA

Here the hosts are all patched against BlueKeep and two of them protected by CredSSP/NLA

Here, I tested againt two unpatched VM’s, one protected by CredSSP/NLA, the other completely unprotected against CVE-2019-0708.

Here, I tested againt two unpatched VM’s, one protected by CredSSP/NLA, the other completely unprotected against CVE-2019-0708.

But if you were to run rdpscan against a lager network (like /16 or /8), it would take too long to finish.

Robert Graham also has created the immensely impresive tool called masscan, which is actually able to scan the entire internet in 6 minutes (!).

Combining masscan (for finding hosts with port 3389 open) with rdpscan (to find out if the hosts found with masscan are vulnerable) would make it possible to finish scanning your entire enterprise network in a relatively short time.

But… You have to compile masscan yourself. It can be compiled on Windows using MinGW or Visual Studio.

If you, like me, feels a bit less Dev than IT Pro and uneasy about compiling for yourself ;), then here’s another solution, albeit not one that will scan as fast as masscan.

Using nmap in conjunction with rdpscan

I have created a PowerShell script, that will run a fast nmap scan of your network to find hosts with port 3389 active and then have rdpscan to scan the hosts found by nmap to see, if they are vulnerable.

It is nowhere near as fast as with masscan, but it doesn’t require you to do compiling.

And the nmap scan is optimized for performance.

I scanned a 24 bit subnet in 5 seconds.

The following rdpscan based on the nmap scan then took 45 second.

A scan of a 16 bit subnet can be done in about 6 minutes, depending on how many RDP enabled hosts are in those 65.536 IP-adresses.

But first:
All credit goes to:
Robert Graham for creating rdpscan
Rob VandenBrink, who created a PowerShell script on which I based mine, that uses the XML ouput from nmap in PowerShell.

Download nmap

Download the latest stable Windows release from:

Install using defaults and make sure, that the installation path is C:\Program Files (x86)\Nmap.

Download rdpscan

Go to

Below the headline, you will find download link to the Windows Binary.

Save to C:\Temp\rdpscan-windows

Extract to C:\Temp\rdpscan-windows

(if you choose to extract to another path, remember to change the path in the last line of the script below)

Create the PowerShell script

Here is the script:

(Updated 2019-06-12 with $ErrorActionPreference = "SilentlyContinue" to make sure it also works, if that variable has been changed from the default. It also now only displays nmap output of open RDP ports)

$ErrorActionPreference = "SilentlyContinue"
$fileappendix = get-date -Format s | foreach {$_ -replace ":", ""}
$filename = $env:TEMP + "\nmapRDPScan" + $fileappendix + ".xml"
$nmappath = 'C:\Program Files (x86)\Nmap\nmap.exe'
$argScanNet = Read-Host "Type Subnet Address. I.e. ''"
$argScanMaskbits = Read-Host "Type Mask Bits. I.e. '16'"

& $nmappath `-sS `-p 3389 `-T5 `-n `-`-open `-`-min`-hostgroup 256 `-`-min`-parallelism 100 `-`-max`-rtt`-timeout 300ms `-`-max`-retries 3 `-`-send-eth $argScanNet`/$argScanMaskbits `-oX $filename

[xml]$nmapRDPScan=Get-Content $filename

$list = @()
$hosts | foreach {$_.address | foreach {if ($_.addrtype -eq "ipv4") {$hostip = New-Object psobject ; 
    $hostip | Add-Member -MemberType NoteProperty -Name ip -Value $_.addr} }
    $_.ports | foreach {$_.port | foreach {
        $val = New-Object psobject ;
        $val | Add-Member -MemberType NoteProperty -Name Host -Value $hostip.ip
        $val | Add-Member -MemberType NoteProperty -Name Proto -Value $_.protocol
        $val | Add-Member -MemberType NoteProperty -Name Port -Value $_.portid
        $val | Add-Member -MemberType NoteProperty -Name State -Value $_.state.state
        $val | Add-Member -MemberType NoteProperty -Name Service -Value ($ + " "+$_.service.tunnel)
        $val | Add-Member -MemberType NoteProperty -Name Servicedesc -Value $_.service.product
if ($val.proto -ne "") {$list += $val}

Write-Host "`r`n--------------`r`nNow testing all nodes with port 3389 open"
Write-Host "Depending on the number of nodes, this can take a considerable amount of time`r`n--------------`r`n"

$list | Where-Object {$_.State -eq "open"} | ft Host -HideTableHeaders | C:\Temp\rdpscan-windows\rdpscan.exe `-`-file `-

Write-Host "`r`n--------------`r`nScan complete"
Write-Host "You can find more information on each host in the nmap scan XML file"
Write-Host "Location of file:"
Write-Host "$filename`r`n--------------`r`n"

 You simply run the script, input the subnet address and the mask bits, and then let it run.

If you run it against a network, expect to let it run for more than 24 hours.

Then afterward, you have a list of RDP hosts, and which IP’s are vulnerable and needs patching (or at least having NLA enabled).

Happy patching ;)