RDP Replay

RDP Replay

Here at Context we work hard to keep our clients safe. During routine client monitoring our analysts noticed some suspicious RDP traffic. It was suspicious for two reasons. Firstly the client was not in the habit of using RDP, and secondly it had a Chinese keyboard layout.

By Steve Elliott

Principal Software Engineer

30 Oct 2014

This information is available in the ClientData handshake message of non-SSL traffic, and can easily be seen in wireshark.

Notice that the keyboard layout is 2052. This, for our client, is bad. I’ve also blanked out the client name, as this information is leaked by the attackers.

I was asked what I could get out of this pcap file. Well, as it turns out, quite a lot!


The first thing to note is that, after the initial (lengthy) handshake, all messages are encrypted. Most people will just give up at this point. Not me. I’m stubborn. I know wireshark can decrypt (most) SSL crypt as long as you have the private key. Surely you can do the same with standard RDP encryption? If so, where do I get the private key? How do I get the private key? What do I do with it if I get one?

First Steps

I got hold of the source code for a Linux RDP client (rdesktop), and found where the crypt exchange takes place. These are all about securely exchanging a shared session key. Hacking the client with a simple “printf” gave me the session key for a single pcap session. So I have the key, what can I do with it? Some experimentation with the decryption routines in rdesktop gave me decrypted data. Surely all I need to do is feed this data into rdesktop in the correct place to get the display rendered. Easy, right? So, what next?

Processing the Data

The protocol stack is shown here.

Notice that the stack may or may not have SSL depending on negotiated capabilities but the RDP and Fast Mode headers and details will be different between the two modes, as this is where the encryption takes place for non-SSL data. If you want detail on the various layers, they are all standard and RFC based, and wireshark does a good job of displaying them. How do I process them? I’m a Unix guy, so this is all done in Linux (Ubuntu to be more specific). I’ll explain my processing a layer at a time.

Pcap Replay

I had to write software to read a pcap file and play it back in real time (or other specified speed). This was fairly simple to achieve. Playing at full speed is fun, but not very useful.


I simply skip over this, after checking that the payload is IP4 (type 0x0800).


Processing IP4 was not so straight forward, as I had to deal with fragmentation as well as checksum verification. This has to live closely with TCP to make sure we have correct TCP/IP footprint for the data to be processed. I needed to re-order packets, drop duplicate data, and perform checksum verification for TCP. By default it will “lock on” to the first TCP SYN packet. You can specify a port if your pcap contains more than one TCP stream.

TPKT / X.224 / T.125

I perform minimal processing of the these layers, just making sure that I’m parsing and checking lengths and discarding non payload frames. Setup and negotiation information is of no interest to us. Well, mostly. Some of it is of use, for example the MCS channel negotiation will tell us where to find the clipboard channel. Apart from a few similar details, all I need at this point is the RDP payload data.


Microsoft have a very good reference for the RDP protocol


This was invaluable for getting higher versions of RDP working. I will not go into details here. Feel free to browse the reference material (it will help you sleep). I will explain this processing later.

Crypt (Again)

I need to get hold of the session key for each session I want to decrypt/display. The only way to do this is with the private key, as session keys are exchanged with public crypt. I’m by no means an expert on these things, but basic public key crypt goes something like this.

This is a little over simplified, but the basics are there. It shows that we can recover the session key with the encrypted session key (that we see in the traffic) and the private key from the server. But how do we get that?

This turned out not to be a showstopper as we have access (via our customer) to the server and can extract the private key needed to decrypt the traffic. But how? Where are the keys held, and how do I get to them?

Accessing your Privates

There are 2 real variants of encryption used by RDP. The original RDP encryption, using RC4, and SSL. SSL will be used by preference, but older servers and/or clients may not support this, and fall back to the older encryption method. I will cover extraction of SSL keys in a moment. I will explain the older style private key handling first.

RC4 Key Extraction

Originally there was only one RDP private key (pre Vista) and it was stored in the LSA (Local Security Authority) under a key named

  • L$HYDRAENCKEY_28ada6da-d622-11d1-9cb9-00c04fb16e75

Passcape have a tool for extracting this, as long as you have Admin privileges, and here we can see an example output. 

The private key here is c18f99e6……33bd (from 0x110 to 0x14f)

Vista onwards changed the way keys were handled with the introduction of DPAPI (Data Protection API). The length of the private key increased from 512 bits to 2048 bits. The shorter key is still available under the name

  • L$HYDRAENCKEY_52d1ad03-4565-44f3-8bfd-bbb0591f4b9d

The tool from Passcape will not work with the DPAPI, so we wrote our own. To access the DPAPI you need to run as System, so we use PsExec (a SysInternals tool) for this. Here’s an example (on Windows 7) 

SSL Key Extraction

To extract the private key for SSL you will need to use Mimikatz. When I added support for SSL, I used the latest version (from May 2013). I looked at the latest version when putting together this report (October 2014), and did not have much joy with it. It’s probably the way I’m driving the software, but didn’t spend much time on trying to get it to work. Here you will see an example using this older version of Mimikatz on a Windows 7 box. Again, you will need to run this as the System user.

Once you have extracted the PFX file, you can use openssl to get the private key:

openssl pkcs12 –in infile.pfx –nodes –out outfile.pem
When prompted, the password is: mimikatz


I now know how to get private keys, so I can (in theory) recover session keys. I have all the puzzle pieces, so just need to write something.

I have already explained the processing up to the encryption and RDP layers, so it’s time to tackle the decryption.

Armed with the private key for old style RDP, this is not too bad a job. I have to perform custom initialisation of the crypto variables, and use both sets for the decryption, but mostly this taken from freely available software.

SSL was a different matter. I’m using OpenSSL, and there is no support for feeding in data that is not associated with a socket. It does not play nicely.  Controlling the initialisation of the crypt variables also took quite a bit of head scratching, and I was relieved to get this part working. Not fun. 

The RDP layer

RDP is really a rich set of capabilities, and clients negotiate with servers to agree a compatible set to use. We have no control over this, so need to be able to process what was on the wire.

It quickly became apparent that the capabilities supported in rdesktop were not very extensive. Rather than implementing a large amount of functionallity, I looked elsewhere. I found something better suited to my needs with FreeRDP, another open source implementation of RDP.


The APIs available in FreeRDP were not designed for the use (or abuse) that I had planned. I had to chop out and discard most of the functionality it provided. I did re-use the RDP crypt processing, but mostly needed the bitmap/pixmap parsing, caching and processing, and the rendering engine. I also needed to add some functionality (e.g. Bulk compression support was added, as this was used in some of the data we had) and fix the odd bug. I had to make the library more robust, as I was feeding in wild and unexpected data that was not always in the correct state to process, and so needed to guard against NULL pointers and suchlike. This was a long an iterative process, and will probably continue as and when clients need the use of this capability.

This is by no means a full implementation of RDP. Support has only been added for the parts of the protocol specification I needed to process. Large the parts of the specification are already supported by FreeRDP. Together this covers a large proportion of the specification, but mileage may vary.

Other Considerations

I mainly focused on data from the server to the client, as this has all the rendering information. Data in the reverse direction has mouse movement and key-press information. This allows me to extract all keys pressed, including hidden (password) text, and track the mouse cursor. This was useful (well, the analysts demanded it), so I added support for this.

The analysts also wanted to watch the output as a video, so I also added support to output directly to a video file (using V4L).

We (again, I mean the analysts) saw that the clipboard was used to transfer data to and from the target machine, so all clipboard selections can be optionally output to disk.


Enough talk, let’s see a run of the program. Here I am extracting the RDP keys I need to process the pcap I’m capturing while doing it! You also see the command line and the key press information.


Information gained from viewing the intrusion was invaluable. Details of tradecraft and operational tools showed just how mature the intrusion was. We were also able to get these tools for further analysis (they were normally cleaned up after use). It helped to identify ORBs and compromised machines, and guided the remediation planning. It is also high impact in the board room. Telling the customer they have an intrusion is one thing. Showing them a video of the actors on their network is another thing entirely. 


We have made the RDP replay code available after being asked by a number of our blog readers. More information about the tool and how to download it is available here.

Subscribe for more Research like this

About Steve Elliott

Principal Software Engineer

CHECK IT Health Check Service
Cyber Essentials
CESG Certified Service
First - Improving Security Together
BSI ISO 9001 FS 581360
BSI ISO 27001 IS 553326
PCI - Approved Scanning Vendor
NCSC CCSC - Assured Service Provider