This post describes how Remote Desktop Protocol (RDP) connections can be vulnerable to a downgrade attack if Terminal Servers are configured insecurely.
We’re not aware of this issue being discussed before – googling only found pages about installing an earlier version of the RDP client, not about downgrading the protocol in the way described here. We suspect that it’s a known limitation of the protocol. But it’s one that we though would be interesting to post about.
In this post we provide a demonstration of such a downgrade attack using the aptly named PoC tool rdp-downgrade.py.
RDP Security Layer
Before discussing the downgrade attack, we should outline what we’ll be downgrading from and to.
The following Security Layers are available in the RDP protocol. Support for each can be configured on the Terminal Server:
- Classic RDP Protocol - this is known as “RDP Security Layer” in the tscc.msc configuration tool and PROTOCOL_RDP in the protocol specification (see page 40 of PDF)
- SSL - this is labelled “SSL” or “SSL (TLS 1.0)” in the GUI and called PROTOCOL_SSL in the protocol specification
- CredSSP - this is what you get when you check the ”Network Layer Authentication” box. It also uses uses SSL. It is called PROTOCOL_HYBRID in protocol specification
The first option is the insecure one. If this protocol were to be negotiated, the connection would be vulnerable to a well known “Man-In-The-Middle” attack. Essentially, someone carrying out this attack would be able to see all your key strokes and any other data passed between client and server. This will therefore be the protocol we’ll be downgrading to.
The last two options are both SSL-wrapped and are more secure. It will be these protocols that we’ll be downgrading from.
How to tell which security layer you connected with
The various warnings displayed by the Terminal Services client, mstsc.exe can be used as a crude way to identify which protocol is being used.
Classic RDP
Note that the warning message about not being able to authenticate the server tallies with the MiTM attack described above.
SSL
Unless you’ve configured your host to trust the SSL certificate of the RDP server, you’ll see a certificate warning like this one:
CredSSP (NLA + SSL)
You get prompted for your username and password by a pop-up window – whereas Classic RDP and SSL both use a full Windows Desktop for password entry.
Vulnerable configuration
Terminal Servers set to negotiate their Security Layer are potentially vulnerable to a downgrade attack. Here we view the settings on a Windows 2003 server, but this also holds for newer versions of Windows:
The downgrade attack
We will connect to a Windows 2003 RDP server configured to “Negotiate” its Security Layer. We’ll connect from a modern windows system that supports Classic RDP, SSL and NLA. This server only supports Classic RDP and SSL. As we’d hope, the two will normally negotiate the most secure option supported by both: SSL.
During this attack we will modify network traffic to make the server believe the client only supports Classic RDP. We could intercept traffic using ARP-poisoning or DNS spoofing or some other method.
After connecting to TCP port 3389, the client (mstsc) sends data similar to the following (shown in hex):
03 00 00 13 0e e0 00 00 00 00 00 01 00 08 00 *03* 00 00 00
The 03 is the protocols supported by the client. Several values are possible in this position:
- 00 – Only Classic RDP is supported
- 01 – SSL is supported in addition to Classic RDP.
- 03 – CredSSP is supported in addition to the other two protocols.
This is described on page 37 of the protocol specification.
So our proof-of-concept simply replaces the 03 with 00 to cause the client and server to negotiate Classic RDP instead of SSL.
We set our tool listening on 192.168.190.170 on TCP port 3389. We instruct it to forward traffic to 192.168.2.96.
$ python rdp-downgrade.py 192.168.2.96 [Proxy] Listening for connections on 0.0.0.0:3389
Rather than actually doing ARP-spoofing, I just connect directly to the “Man-In-The-Middle” in this demo:
Back in our PoC tool, we then see an incoming connection from the RDP client (192.168.190.1) and the proxy making an outgoing connection to the target server:
[Proxy] Incoming connection from 192.168.190.1:58715 [Proxy] New outgoing request to 192.168.2.96:3389 [Proxy] Connected
Next we see 19 bytes from the client – note the 03 near the end of the data from the client. This is recognised by our PoC tool and it prints a message to inform us the 03 has been changed to 00:
[From 192.168.190.1] Received 19 bytes 0000 03 00 00 13 0E E0 00 00 00 00 00 01 00 08 00 03 ................ 0010 00 00 00 ... [From 192.168.190.1] Modified data to downgrade connection
Then we see traffic flow freely without further modification:
[From 192.168.2.96] Received 19 bytes 0000 03 00 00 13 0E D0 00 00 12 34 00 02 00 08 00 00 .........4...... 0010 00 00 00 ... ...snip...
mstsc shows us the warning message corresponding to a Classic RDP connection, proving that the downgrade has been successful – remember that we would normally expect a certificate warning for the SSL-wrapped RDP connection.
Conclusion
Configuring the Terminal Server to use SSL for it security layer instead of “Negotiate” prevents such a downgrade attack.
Vendor contact
We were not sure if Microsoft would consider this worthy of a security advisory. We didn’t think so, but sent them a preview of this post before publishing and asked.
Microsoft who responded swiftly to confirm that “After researching the issue, we consider this behavior to be By Design”. They thanked us for our commitment to co-ordinated disclosure and gave their blessing to proceed with publication.