Snort Rule for the Bluekeep Module in Metasploit

Alexandre Vieira
4 min readSep 24, 2019

The goal here is to analyze the behavior of the Metasploit Blueekeep Module, which exploits the CVE-2019–0708 vulnerability, and identify signatures which can be used in writing a snort rule for detecting its usage.

Both NCC Group and Talos Intelligence has published snort rules for detecting the CVE-2019–0708. However, both of them suggested the detection based on some contents that will travel under encryption and will be visible only with specific decryption softwares/appliances.

Here I focus in the not encrypted part of the communication.

RDP Communication

First of all, it’s important to understand the basics of RDP communication which is used in the exploit.

RDP Connection Sequence

The documentation can be found here.

Connection Initiation: The client initiates the connection by sending the server a Class 0 X.224 Connection Request PDU (section 2.2.1.1). The server responds with a Class 0 X.224 Connection Confirm PDU (section 2.2.1.2).
From this point, all subsequent data sent between client and server is wrapped in an X.224 Data Protocol Data Unit (PDU) (1).

So, from the “Client MCS Connect Initial PDU with GCC Conference Create Request” (doc) the messages begin to be transmited with some kind of encoding.

Based on this, the best moment to identify the clear data sent from the metasploit code is at the Connectoin Request PDU.

Client X.224 Connection Request PDU

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/18a27ef9-6f9a-4501-b000-94b1fe3c2c10

The connection request PDU is assembled in the file lib/msf/core/exploit/rdp.rb, with the following method:

Observing the exploit’s behavior, you can see that the first step is the call of the fingerprint method with the parameters:

rdp_fingerprint()
rdp_check_protocol(RDPConstants::PROTOCOL_SSL | RDPConstants::PROTOCOL_HYBRID | RDPConstants::PROTOCOL_HYBRID_EX)

This causes the [requested_protocols].pack(‘L<’), of the pdu_negotiation_request(), to results on “0b 00 00 00”.

The options of the RequestedProtocols are:

 PROTOCOL_RDP = 0
PROTOCOL_SSL = 1
PROTOCOL_HYBRID = 2
PROTOCOL_RDSTLS = 4
PROTOCOL_HYBRID_EX = 8

These values are sent in 32 bit format.

The value of “0b 00 00 00” is sent in the first time the rdp_fingerprint is called. This is caused by the “OR” operator applied in the constants with their default value:

RDPConstants::PROTOCOL_SSL | RDPConstants::PROTOCOL_HYBRID | RDPConstants::PROTOCOL_HYBRID_EX1 OR 2 OR 80001 OR 0010 OR 1000 = 1011 = \x0B

With that, the [requested_protocols].pack(‘L<’) results in “0b000000”.

According to the RDP Negotiation Request (RDP_NEG_REQ) documentation, this requested_protocol value will enable all three options [PROTOCOL_SSL, PROTOCOL_HYBRID, PROTOCOL_HYBRID_EX]. This last one activating the “Early User Authorization Result PDU”.

It happens only at a first round and the code passes through the rdp_fingerprint again. At the second time, it goes successfully.
After the second “Verifying RDP protocol” it’s possible to see the “Send data” showing a payload ending with “01000000”, which is the regular usage of the requestedProtocols, not using the “Early User Authorization Result PDU”.

After that, the protocol proceed with the connection and the exploit follow its flow.

The point is, that first RDP Negotiation Request PDU sent, with the Early user Authorization Result PDU set, is not the default behavior. Not in the windows RDP Client, nor in the Linux clients, like remmina.

So, with this particular piece of data within the clear part of the communication, it becomes the best signature to the Bluekeep’s Metasploit Module.

Finally, this can be resumed in the following snort signature.

#content:”|03 00|” -->TPKT Header version 03, reserved 00
#content:”|43 6f 6f 6b 69 65 3a 20 6d 73 74 73 68 61 73 68 3d|” --> ‘Cookie: mstshash=’
#content:”|0b 00 00 00|” -->requested_protocols
####################################################################
alert tcp any any -> any 3389 (msg:”Metasploit Bluekeep”; flow:to_server,established; content:”|03 00|”; offset:0; depth:2; content:”|43 6f 6f 6b 69 65 3a 20 6d 73 74 73 68 61 73 68 3d|”; distance:9; within:17; content:”|0b 00 00 00|”; distance: 13; reference:url,github.com/alexandrevvo/snort_rules/blob/master/metasploit_bluekeep; sid:100000012;)

--

--