PyRDP on Autopilot – Unattended Credential Harvesting and Client-Side File Stealing

When we initially released PyRDP in late 2018, we familiarized ourselves with the Remote Desktop Protocol (RDP) relatively quickly. It became clear that our initial release couldn’t tackle all the opportunities that an active on-the-wire attacker could have. During my internship, one of my goal was to implement features taking advantage of these opportunities for both offensive use cases and malware research ones.

RDP is a popular protocol among system administrators, since it simplifies remote management and diagnosis without requiring physical access to workstations. It has gained a lot of attention with the recent BlueKeep and DejaBlue vulnerabilities, which both allows a malicious client to execute remote code on a vulnerable RDP server before authentication. With the growing awareness of RDP vulnerabilities and misconfigurations, it is the perfect time to showcase what we have been working on.

PyRDP as an Offensive Tool

So, how can we weaponize an RDP monster-in-the-middle* (MITM) attack? First, we need to automate what is being done manually, like reading passwords from the saved replays and examining shared drives with the pyrdp-player . The player is a useful tool and great for demos, but it should not have all the fun!



Credential Stealing

Pentesters love credentials. Being in an MITM scenario, we can already read everything that the client sends over to the server including keyboard input. When we intercepted a connection, we used to watch the replay file in order to read what credentials were being typed by the client, as seen in this old PyRDP video.

In order to automate this, we are now buffering user input, and printing it when the server signals that the user has correctly logged in. Special inputs like backspace, tab, and Ctrl-a get displayed in tags, which allows the attacker to understand what the client was trying to type. For example, if PyRDP prints Credentials candidate from heuristics: Administratorsumarmer2019 , we can clearly see that the username is Administrator and the password summer2019 .



Passive Shared Drive Crawling

An oft-forgotten feature of RDP is the ability to map a client’s drive to the server. This allows a connected user to browse and copy files from their local machine into the destination machine. The pyrdp-player already supports browsing and requesting files from the client to download. An analyst needs to sit and wait until we intercept an interesting connection and then we need to explore the drive manually as fast as we can. It would be a shame to miss interesting files and folders because we did not have the time to manually crawl the drive or we were grabbing a coffee, right? Therefore, we implemented a passive file crawler, directly inside PyRDP.

The crawler silently explores the client shared drives, looking for files and directories that match a default but configurable list of patterns. Whenever any of the patterns match, the file or directory will be downloaded. There is also a list of excluded patterns that works in the opposite way, so the crawler can avoid exploring useless or huge default directories like C:\Windows\.

That’s Cool, Now What?

Now that we have these new offensive features built into PyRDP, there is still a problem that needs to be addressed: We still need someone to intentionally connect to our MITM. For our honeypot research this isn’t a problem but for our intrusion testing engagements it is. We needed a way to jump “in the middle” of legitimate RDP connections, since we can’t expect connections to magically come to us.



A new Bettercap Module – An RDP proxy

Bettercap is a powerful framework that aims to be an all-in-one solution created to perform various types of MITM attacks on a network. We already had documentation to perform a manual MITM with bettercap. However, it required a manual iptables setup and could only target a server specified in advance and not the intended target of the client. Since betttercap already supported many kinds of proxies like http.proxy and tcp.proxy , we implemented our own module called rdp.proxy .

Our module, combined with the built-in arp.spoof module of bettercap, allows us to easily MITM any RDP connections on a given LAN segment. For each new RDP connections, we spawn an instance of PyRDP exposed locally, and force the traffic meant for the intended server to go through the new local PyRDP instance first. Of course, this will raise a certificate error on the client side, but in most of the cases, people will click through. Why? Because we have been trained to click through these over the years due to rarely deployed PKI in organizations and there simply hasn’t been an attack tool taking advantage of that situation so far. Raising this kind of awareness is one of the reasons we made PyRDP open source.

Once the connection between PyRDP and the target is established, all that is left to do is wait for the client to either automatically send its credentials if they are saved in the RDP client, or wait for the victim to type their password in the Windows lock screen, simple as that.

As a pleasant bonus, a lot of the connections we get from RDP connections in internal tests are from high-value targets, meaning either domain admins, or users from an administrator group, which increases the likelihood of high-privilege access once compromised. Note that other than the certificate error, the client has no way of knowing that we are redirecting his RDP connection.

We submitted our module to bettercap but it was rejected due to the amount of dependencies that it added to the project. We are considering a re-architecture of our implementation that would have greater chances of being accepted by bettercap. In the meantime, you can use our fork of bettercap and refer to the bettercap with PyRDP documentation.



The NLA Case

One common RDP hardening technique is called Network Level Authentication (NLA). NLA is a technology used by RDP servers and clients that requires the connecting user to provide credentials before a session is established with the server. Without diving into the complex details of NLA, it uses the security support provider CredSSP that offers both Kerberos and Net-NTLM as authentication mechanisms. We evaluated the MITM resistance of the Net-NTLM portion of that security model and concluded that in a case where we don’t control the destination server there is nothing that can be done. In a nutshell, the inner Net-NTLM layer uses the outer TLS layer’s public key encrypted as part of its challenge response protocol. Combining these two layers together is the coup de grace. It means that we either need to control the server’s certificate or know the clients’ credentials in advance in order to properly MITM NLA. Let’s stress out that this is a protocol level analysis only, implementation errors or a very speedy breakage of HMAC-MD5 during the authentication phase would successfully break NLA. Instructive details about NLA are available by reading impacket’s source code.



NLA Stripping

NLA is usually required by the RDP server, meaning that if the client does not support NLA, the connection will be terminated. Even though RDP allows the client to enforce NLA, the mstsc.exe client (the default Windows client) does not expose an option to do so. Its default is set to Negotiate, which is to accept whatever the server proposes. Because of that default behavior a MITM attacker can remove the server’s NLA requirement in transit. Knowing that, there is still a way to steal credentials out of a client attempting to connect to an NLA server. In our bettercap module, we implemented a mode called REDIRECT. When toggled, if the client is attempting to connect to an NLA-enabled server, we spawn a PyRDP instance just like before, but we replace the intended destination address by a user-defined address, which needs to have an exposed RDP server with NLA disabled. Since the RDP client does not enforce NLA, the connection is established. The module allows the user-defined destination address to be either a VM controlled by the attacker (that would collect credentials saved in a client), or another machine without NLA in the same network, which allows the client to connect with saved credentials or credentials entered on the lock screen.

Conclusion

After a few months of experience in the field, it became clear that PyRDP needed to operate more autonomously. An analyst can’t sit in front of the pyrdp-player all day waiting for a connection in order to be able to browse the client-side’s drive content or go through several recording files in order to manually extract credentials. So, we added that functionality. Also, with our bettercap integration, in internal engagements, it takes longer for victims to realize they were misdirected. While the NLA downgrade is noisy, it is useful in some very hardened scenarios. Interest in RDP is certainly on the rise and we intend to keep investing resources into PyRDP. Follow us here or watch our GitHub repository to be notified of what comes next.



This blog post was written by Maxime Carbonneau as part of an internship with us. We are proud that Maxime managed to tackle a complex problem that required a great understanding of the RDP protocol and PyRDP project. Great job Maxime! We are looking forward to what you will do next!

*: The gender-neutral form of man-in-the-middle.