What Happens Before Hello?
This post has been co-authored with Aaron Soto
During the past week or so, some folks in the infosec community have been wrapped around the looming threat of weaponized #BlueKeep vulnerability. BlueKeep reportedly allows for unauthenticated remote code execution (RCE) via Microsoft’s Remote Desktop Protocol (RDP). (To be clear, neither Aaron or myself have seen a working PoC, but recommend checking out this blog post from McAfee).
Based on our understanding, if an attacker can craft the right parameters, that can lead to heap memory corruption and the aforementioned RCE. Thus, we had our starting point.
Sidebar: We’re both down on the Gold Coast of Australia getting ready for speaking at AusCERT this coming Friday; If you’re around, come see us talk about this in person! Also, the Gold Coast is not a bad place for some protocol research :)
TL;DR
Based on what we know — even with encryption — it is possible to identify current BlueKeep scanners and future BlueKeep exploitation.
The RDP Connection Sequence
According to BlueKeep research, the exploit may occur inside of an encrypted tunnel, thus foiling network signatures that rely on plaintext. This left only one server/client exchange that is guaranteed unencrypted: Connection Initiation. Figure 1 provides the RDP Connection Sequence, per Microsoft.
Breaking Down the Connection Initiation
The Connection Initiation phase is lightweight with only one request and response packet:
In Figures 2 and 3, I’ve highlighted the final 19 bytes. These are the portions that contain data we’re going to focus on — specifically in the Connection Initiation Request. Using this Microsoft link as a guide, let’s break down this packet.
Connection Initiation — Client Request
The client request is the first packet you’ll see:
struct rdp_x224_ci_client_req {
[0-3] TPKT Header
[4-10] X.224 Class 0 Connection Request
[var] routingToken [optional] [terminated with 0x0D0A]
[var] cookie [optional] [terminated with 0x0D0A]
[n+8] RDP Negotiation Request [optional]
[n+36] RDP Correlation Info [optional]
}
Notice that the potential bulk of this packet is optional — which could provide more opportunities for detection. We’ll discuss the cookie field, for example, later on on this post.
The RDP Negotiation Request bytes, if included, proved to be the most valuable. Within these 8 bytes, the client indicates the requested security protocol(s):
struct rdp_x224_ci_client_req_rdp_neg {
[0] Type (Always 1)
[1] Flags
[2-3] Length (Always 8)
[4-7] Requested Protocols (See below)
}
Negotiation Request — Requested Protocol(s)
The requested protocol bytes are the most interesting. If an attacker is seeking to simplify their exploit code, this is where they can avoid encryption. These four bytes can contain a combination of the following flags:
- 0x00000000 — Standard RDP Security
- 0x00000001 — TLS 1.0, 1.1, or 1.2
- 0x00000002 — Hybrid (CredSSP — requires that TLS also be set)
- 0x00000004 — RDSTLS
- 0x00000008 — CredSSP coupled with Early User Authorization (EUA) (requires that Hybrid also be set)
Connection Initiation — Server Response
The server response has less variable space:
struct rdp_x224_ci_server_resp {
[0-3] TPKT Header
[4-10] X.224 Class 0 Connection Confirm
[11-18] RDP Negotiation [Response|Failure] [optional]
}
The final 8 bytes of this packet will either indicate a connection success or failure. We will not examine the server response in detail, however there are screenshots provided (see Forcing a Downgrade).
So What?
Based on the above, there’s one key takeaway:
When a client reaches out to establish an RDP connection, it will provide supported security protocols.
Sound familiar? If you’ve ever heard of JA3, then the concept of fingerprinting “how” a client says hello is very valid data. That’s what we’ll look at next :)
Saying Hello in Many Languages
The next step in our research was to start to identify how various clients and tools “say hello” to initiate an RDP connection. And, seeing as we’re sitting before encryption, we have a chance to detect anomalous behavior before scanning or exploitation. We tested multiple clients and tools; here’s a high-level table of our results (granular screenshots are provided below):
During our testing we observed the following:
- Cookie values typically include the name of the user that initiated the request. However, this value is optional, arbitrary, and is randomized by RDPScan and the Metasploit scanner (see below). Thus, it may or may not serve as a useful indicator.
- Windows XP does include a cookie value but NO requested protocol(s). Without requested protocols, the request implies RDP Security. Based on our research, only Windows XP omitted the requested protocol(s).
- The RDPScan and n1xbyte tools are currently hard-coded to request protocol 0x00000001 (aka TLS); based on our research, this is an obvious outlier.
- The Metasploit scanner is currently hard-coded to request protocol 0x00000000 (aka RDP Security). This only shows up during legitimate traffic when Windows XP is the server and a newer operating system is the client (see Forcing a Downgrade).
Windows XP
Windows XP omitted the requested security protocol(s), only including a cookie value.
Windows 7
Windows 7 did not include a cookie field, but did include the requested security protocol(s).
Windows 2012
Windows 2012 did not include a cookie field, but did include the requested security protocol(s).
Windows 10/Windows 2016
Windows 10 and 2016 included both a cookie AND requested security protocol(s).
RDesktop
Rdesktop, a *nix-based RDP client included a cookie value and the requested security protocol(s). The cookie value, as with Windows clients, corresponds to the user that initiates the request. This tool requested 0x03 for requested security protocol(s), which is CredSSP + TLS (same as Windows 7).
Metasploit Scanner
The current version of the Metasploit BlueKeep auxiliary scanner randomizes the cookie value with five characters and has a protocol request of 0x00000000, which is default RDP Security.
RDPScan
RDPScan, the tool created by Rob Graham scans for vulnerable RDP systems. Rob randomizes the Cookie username with eight characters and requested the TLS security protocol (0x01).
n1xbyte’s PoC
n1xbyte’s PoC scanner omitted the cookie value, however requested the TLS security protocol (0x01).
Forcing a Downgrade
One other series of tests we ran was to connect from newer to older, such as from a Windows 10 client to Windows XP server. We wanted to check and see if Windows XP would force a downgrade — which, of course, it did. However, this results in an RDP “double-tap”, in which there are two connections.
Connection 1
The Windows 10 client initially requested security protocol 0x0B. As it cannot support this request, Windows XP responds with no selected protocol (defaulting to 0). We hypothesize that this causes Windows 10 to reissue the request, as Windows 10 forcibly resets the connection.
Connection 2
The Windows 10 client reconnects, this time specifying a security protocol request of 0x00 (aka RDP security). Windows XP happily accepts! Thus, even a “security downgrade” would result in a session with RDP Security, which could be easily observed.
Key Observations
If you’ve made it down this far, then hopefully you’ve arrived at the same observations we have. We think the following can be said:
- Typically, Windows will push you towards more, not less, security. Therefore, look out for requests that specify less security.
- We modified and ran the Metasploit scanner without Cookie or Protocol Request fields, and it still worked! They are optional; you don’t need to specify RDP Security if that’s what you want. However, we will stipulate that an RDP Connection Initiation request without a Cookie OR protocol security request should trigger an alert.
- An attacker could craft a packet that looks like Windows XP, with only a non-randomized username in the Cookie field; this request would default to RDP Security. This structure would make it tough to discern between a scanner, an exploit, or a legitimate Windows XP client.
- HOWEVER — if you default to RDP Security, and are looking to exploit BlueKeep, the subsequent step(s) of setting up MS_T120 over a channel other than 31 is easily observable.
- Lastly, we didn’t focus much on the Cookie value. However, as you can see in the screenshots above (look particularly at Figures 9 and 11), this is an arbitrary text field. Using a tool like Zeek, you can easily extract and analyze these fields from live network traffic. Mr. Richard Bejtlich has a great, succinct Twitter thread about this here.
Scanning Increases
As of the writing of this blog post, there has been an increase in scanning for external-facing RDP. This activity is likely due to either a weaponized version of this vulnerability or building potential target lists for future weaponization. GreyNoise is offering some of the best intel on this at the moment, and we recommend keeping an eye on their Twitter feed.
Closing Thoughts
It’s worth noting that until a working copy of the POC has been observed by more researchers (only a few folks have them, and they’re remaining tight-lipped), we’re reliant on what others have seen/observed. We have trust in the research that has been performed, but the true impact of this vulnerability will likely be better assessed in coming weeks or months.
However — with that being said, remember that with any protocol, there is a structure that must be adhered to. Use these to your advantage; you never know when a single bit might trip up a stealthy attacker!
Recommended Reading
We are, obviously not the only two talking about RDP lately. Here are some great posts that provide some additional insight in analysis and detection of this lovely protocol:
- How to Use Corelight and Zeek Logs to Mitigate RDS/RDP Vulnerabilities by Richard Bejtlich
- Almost One Million Vulnerable to BlueKeep Vuln (CVE-2019–0708) by Rob Graham