Peering Down the Remote Desktop Rabbit Hole

Introduction

Exposing protocols like Microsoft’s Remote Desktop (RDP) to the Internet has always been considered a 'bad idea', but is this just security folklore or will the world really come to an end if you go ahead and open that port? Let's take a brief look at what is actually behind the much maligned RDP/3389 and find out.

Meet the RDP Protocol Stack

Let's jump straight in with a big picture view of the RDP protocol stack. The first bit of good news is that the protocol specs are published by Microsoft. These specs, along with a number of open source client implementations, make it reasonably easy to understand the protocol and to 'poke' it with some test packets to see how it actually behaves. A little bit of reading and some testing was enough to be able to put together an (approximate) picture of the overall stack. It looks like this:

High level overview of the RDP protocol stack.

Most of us have come to expect the IT world to be packed with obscure terms and acronyms, even so, some of the terms mentioned above would elicit a bewildered look from most people. I don't want to turn this into a history lesson but there are a couple of things that do need a bit of an explanation.

Many years ago, the ISO and ITU-T were collectively defining a standardised suite of communications protocols, these are loosely called the "ISO Protocol Family".  RDP was originally built on these protocols, specifically the T.120 suite of protocols that were designed for multimedia conferencing. As the world now runs on TCP rather than the old ISO equivalent (COTP) the current RDP protocol stack has essentially now been 'glued' on top of TCP. That is why there are so many obscure sounding terms dotted throughout the protocol specifications.

COTP was a packet based protocol, this means that an additional layer, called TPKT, is needed to map RDP’s packet based view of the world to TCP's stream based approach. The sheer number of protocol layers being used here actually makes RDP fairly inefficient, as even a small packet needs multiple packet headers. The 'FastPath' protocol (which is either a clever optimisation or an ugly hack depending on your point of view) is there to address this by collapsing some of protocol layers, this saves bandwidth by reducing the packet header overhead.

Complexity is the Enemy of Security

Even though we are yet to dig into any real detail, security alarm bells are already ringing at this point. This is due to one very obvious problem: complexity. RDP has an awful lot of it. Screen remoting protocols inherently involve a lot of low-level bit twiddling, when you add in all of the protocol complexity that arises from the old stack design and all of the various extensions and virtual channels that now exist as part of any RDS deployment you get something that presents an immense attack surface. And let's not forget that nearly all of this is written in unsafe programming languages, and a lot of it runs in a privileged context.

RDP also has a fundamental security design challenge: users might need to authenticate using the standard windows graphical user interface. In some deployments this means that RDP needs to expose almost the entire graphics remoting stack to unauthenticated users.

The level of complexity is reflected in the number of earlier vulnerabilities. This stack has been impacted by multiple remote code execution vulnerabilities in the last few years, these have been discovered in the graphics remoting code, the virtual channel handling, the TLS implementation and even the newer CredSSP layer that was added to improve security.

It is instructive to pause at this point and compare RDP with something that is designed to be used in an Internet facing way. We would expect such a protocol to offer minimal pre-authenticated attack surface, run with the least possible privileges, be implemented in a memory-safe language and be implemented using the minimal possible level of complexity. Remoting protocols such as RDP are almost a secure protocol anti-pattern.

NLA to the Rescue (Maybe)

In the very best traditions of the software industry, Microsoft attempted to address the attack surface complexity problem by adding more complexity. It's time to meet NLA (Network Level Authentication).

On the surface this is a good idea. Just add an authentication layer in front of RDP thus preventing any unauthenticated attackers from being able to poke at bits of the stack that might turn out to be a bit 'squishy'. The problem is that just adding a new layer onto an existing protocol tends to break any deployed clients that use the existing protocol.

NLA is therefore something of a compromise. The new authentication layer uses TLS+CredSSP to authenticate users before they can access the RDP stack, but even when NLA is "required" RDP still allows unauthenticated access to some parts of the stack. This seems to have been done partly for compatibility reasons, to enable older clients to either work or at least report a useful error, and party because some of the stack functionality needs to be accessed before authentication. 

The net effect is that, even when NLA is required, RDP still exposes a complex pre-authentication attack surface. As shown by the lighter coloured components in the above stack diagram: the initial RDP connection handshake, the rather oddly named RDSTLS messages that can enable the target server to act as a form of proxy for load balancing, the parsing functionality associated with those legacy x224 and TPKT layers, and of course the CredSSP and TLS layers themselves, are all still available without authentication. Requiring NLA does significantly reduce the attack surface, but it is no silver bullet.

NLA is also not as widely used as might be expected. Our current data set from EdgeScope shows that just over a third of Internet visible RDP servers do not require NLA and are still exposing the entire graphics remoting stack to unauthenticated attackers.

The Password Shaped Elephant

While our focus is on the RDP stack itself, the elephant in the room here is related to the use of weak authentication. Exposing RDP to the Internet generally means you are providing an easily discoverable endpoint that often relies on a single password. 

To make things even worse, it is relatively easy to extract domain details from Internet visible RDP servers. This enables an attacker to cross reference leaked email/password combinations against the domains being used by Internet-visible RDP servers. This enables wide scale automated and highly focused credential stuffing attacks to be carried out with relative ease.

The reality today is that using password authentication on an Internet-facing server essentially amounts to inviting people into your network. It is simply a matter of time before one of your accounts is compromised and somebody gets access to the server.

Conclusion

Real world security often involves making a complex risk/benefit tradeoff in the context of a specific customer and environment. Blanket statements that simply state that any given technology or practice is 'bad' often tend to overlook a lot of this subtlety. That said, it is difficult to see many scenarios where directly exposing RDP to the Internet is the right decision.

Unfortunately, enabling direct access to RDP can often look like a good solution as the level of risk involved (from the stack itself as well as the associated credential related threats) tends to be much less visible than the immediate value of being able to access a system remotely. This visibility imbalance can easily result in people making well-intentioned decisions that actually end up exposing them to a very high level of risk. In the majority of cases, our advice on exposing RDP is very simple: don't do it.

If you are looking for security guidance on your remote access solution then get in touch. We can provide a risk-based review of your current system along with specific guidance on how you can reduce your exposure to common threats and attacks. You can book a free initial consultation here: https://calendly.com/secmatics/call

Next
Next

Dear Open Source, Can we ever trust you again?