Goodbye RDCMan, hello IAP Desktop
On March 10, Microsoft published a security advisory describing a vulnerability in Remote Desktop Connection Manager (RDCMan):
[RDCMan] improperly parses XML input containing a reference to an external entity. An attacker who successfully exploited this vulnerability could read arbitrary files via an XML external entity (XXE) declaration. To exploit the vulnerability, an attacker could create an RDG file containing specially crafted XML content and convince an authenticated user to open the file.
Microsoft rated the vulnerability’s exploitability as Less Likely which seems reasonable given that downloading RDG files from untrusted sources (or really, from anywhere) is a rather uncommon uce case. I am sure a fix would not require more than a few lines of code, but Microsoft apparently had other priorities. In what seems like an unprecedented move for a tool as widely used as RDCMan, Microsoft simply removed the tool from the download catalog:
Microsoft is not planning on fixing this vulnerability in RDCMan and has deprecated the application. Microsoft recommends using supported Remote Desktop clients.
Granted, RDCMan was an unsupported product and development had already been stalling for a while – so the decision neither violated any support policies, nor was it a huge surprise either. But as the author of a plugin for RDCMan, the decision was a disappointment nonetheless.
Google Cloud IAP for Remote Desktop plugin
RDCMan was not the most feature-rich RDP client, and certainly was not the RDP client with the most modern UX either. But a unique feature that RDCMan provided was a simple (albeit undocumented) plugin API.
I used this plugin API to develop the Google Cloud IAP for Remote Desktop plugin, which added the capability to connect to VM instances via a Cloud IAP TCP forwarding tunnel.
The reason I built this plugin was actually rather selfish: I use Windows VMs a lot, and I am not only accessing them when I am in the office, but also when I am travelling or working from home. However, I am also security-conscious enough that I do not ever want to expose RDP over the public internet.
Accessing RDP over an IAP TCP tunnel is a great way to avoid having to expose RDP publicly. However, having to establish tunnels by using gcloud compute start-iap-tunnel
for every VM you connect to can become cumbersome rather quickly. Integrating the logic to manage tunnels into RDCMan therefore seemed like a logical step to me to combine the convenience of RDCMan with the security of IAP.
I published the plugin in summer 2019 and have been using it myself on an almost every day basis ever since.
But with Microsoft dropping RDCMan, the future of the plugin suddenly seemed in jeopardy and I was forced to reassess my options.
Replacing RDCMan
First, I could do nothing and let it go. I could continue using RDCMan and the plugin myself, but for the open-source project, it would be the end as there would be no point in evolving a plugin for an application that people cannot download anymore.
Second, I could switch horses and look for a different RDP client to extend. Many existing RDP clients turn out to be closed-source and among the few open-source projects, mRemoteNG seems to be the only one that is still actively being maintained. mRemoteNG is a decent tool and I have used it myself in the past. But as a client for RDP, VNC, SSH, RCA, and god knows what else, mRemoteNG simply tries to be too many things to too many people. Also, the source code is GPL-licensed which makes it difficult for me to work with.
Third, I could shed the dependency on RDCMan and turn the plugin into a standalone application. That would give me the most flexibility and would avoid the risk of ever getting into a similar situation again. But building a full-featured remote desktop connection manager also would not be a trivial undertaking.
Building a remote desktop connection manager
The heavy lifting of any RDP client that runs on Windows is actually performed by the Remote Desktop ActiveX control. This control renders the remote desktop and also encapsulates the RDP protocol logic. All the application needs to do is provide a GUI, manage settings, and host the Active X control.
That is easier said than done however.
The first area of complexity tends to be managing the inventory of connections. A remote desktop connection manager needs to allow a user to manage dozens of connections, each potentially using different settings and different credentials. The way applications typically solve this is to allow users to arrange connections in a hierarchical folder structure and to allow settings to not only be specified for individual connections, but also to entire folders of connections.
Supporting arbitrarily nested folder structures, inheritance of settings, encryption of credentials, dealing with malformed input, implementing persistence – none of it is particularly challenging, but the sum of it still is a lot of work.
The second notable area of complexity has to do with the RDP ActiveX itself. This control has been around for over a decade, and by now, it has no less than 10 interface versions – from IMsRdpClient all the way up to IMsRdpClient10. Because the control is part of Windows, it depends on the OS version which interface version the ActiveX control on your machine supports and which one it does not. Many remote desktop connection managers therefore probe different interface versions and adapt their feature set depending on the OS version they are running on.
Focusing on Google Cloud
IAP is a feature that is unique to Google Cloud. It was therefore clear from the start that a standalone RDP would only support VM instances running on Google Cloud.
On Google Cloud, all resources are managed in projects (which in turn can be in folders) – so inventory management is something that is already being taken care of. Instead of reinventing the wheel by allowing users to come up with their own structure, focusing on Google Cloud meant that I would be able to reuse the existing project structure by querying the resource manager API.
Of course, this left the problem of having to manage and persist settings. But because the project structure is fairly stable (you cannot nest projects, and you cannot easily move VMs between projects), this problem seemed a lot easier to solve.
The second challenge, dealing with differences between ActiveX versions turned out to be not much of a problem on closer look: There used to be significant differences in supported interface versions between versions prior to Windows 8/Windows Server 2012, but the differences between more recent versions are almost negligible.
Windows 7 and Windows Server 2008 went out of support earlier this year. By focusing on in-support Windows versions, I would be able to avoid the extra complexity of having to work with (and test) different versions.
IAP Desktop
So I went ahead and turned the plugin into a standalone application, and called the result IAP Desktop.
Functionality-wise, IAP Desktop is similar to Remote Desktop Connection Manager with the IAP plugin installed – but it is specific to Google Cloud and unconditionally uses IAP tunneling to connect to RDP. The app comes as a 2 MB .msi package and works on Windows 8/Windows Server 2012 upwards. It does not have any special dependencies and also does not require gcloud.
A first, “alpha” version of IAP Desktop is now available for download on Github. You can give it a try – and if you do, make sure to let me know what you think!