MCPcopy
hub / github.com/GoSecure/pyrdp

github.com/GoSecure/pyrdp @v2.1.0 sqlite

repository ↗ · DeepWiki ↗ · release v2.1.0 ↗
2,410 symbols 8,027 edges 220 files 837 documented · 35%
README

PyRDP

Tests Black Hat Arsenal 2019 Black Hat Arsenal 2021 Black Hat Arsenal 2022

PyRDP is a Python Remote Desktop Protocol (RDP) Monster-in-the-Middle (MITM) tool and library.

PyRDP Logo

It features a few tools: - RDP Monster-in-the-Middle - Logs plaintext credentials or NetNTLM hashes used when connecting - Steals data copied to the clipboard - Saves a copy of the files transferred over the network - Crawls shared drives in the background and saves them locally - Saves replays of connections so you can look at them later - Runs console commands or PowerShell payloads automatically on new connections - RDP Player: - See live RDP connections coming from the MITM - View replays of RDP connections - Take control of active RDP sessions while hiding your actions - List the client's mapped drives and download files from them during active sessions - Converter tool: - Convert RDP replays to videos for easier sharing - Convert RDP replays to a sequence of low-level events serialized in JSON format - Convert PCAPs to replays, videos or JSON events - Convert decrypted PCAPs (L7 PDUs) to replays, videos or JSON events - RDP Certificate Cloner: - Create a self-signed X509 certificate with the same fields as an RDP server's certificate

PyRDP was introduced in 2018 in which we demonstrated that we can catch a real threat actor in action. This tool is being developed with both pentest and malware research use cases in mind.

PyRDP Player Replaying an RDP session

Table of Contents

Supported Systems

PyRDP should work on Python 3.7 and up on the x86-64, ARM and ARM64 platforms.

This tool has been tested to work on Python 3.7 on Linux (Ubuntu 20.04, 22.04), Raspberry Pi and Windows. It has not been tested on macOS.

Installing

Two installation techniques are recommended via pipx or using docker containers. Installing from source or building docker containers yourself is covered in the development documentation.

Using pipx

Dependencies

Linux

First, make sure to install the prerequisite packages (these are listed for Ubuntu 22.04, you might need to adjust for other distros). We provide two types of installs a full one and a slim one. Install the dependencies according to your use case.

# Full install (GUI, convert captures to video)
sudo apt install python3 python3-pip python3-venv \
        build-essential python3-dev openssl \
        libegl1 libxcb-cursor0 libxkbcommon-x11-0 libxcb-icccm4 libxcb-keysyms1 \
        libnotify-bin \
        libavcodec58 libavdevice58

# Slim install (no GUI, no conversion to video possible)
sudo apt install python3 python3-pip python3-venv \
        build-essential python3-dev git openssl

This should install the dependencies required to run PyRDP. If you choose to install without the GUI or video conversion dependencies, it will not be possible to use pyrdp-player without headless mode (--headless) or pyrdp-convert to produce video output.

Make sure you have pipx installed. On Ubuntu 22.04:

python3 -m pip install --user pipx
python3 -m pipx ensurepath
Windows

Make sure you have Python installed. Windows Store Python didn't work for me on Windows 11. We recommend installing Python via Scoop.

scoop install python # if not installed already
scoop install pipx
pipx ensurepath

Log out and log back in (to update your PATH).

Other OS

To install pipx on other operating systems see here: https://github.com/pypa/pipx#install-pipx

Install

For the full PyRDP experience with the QT GUI and the ability to convert captures to video:

pipx install pyrdp-mitm[full]

For the compact version meant to be run in headless environments (servers, RaspberryPi):

pipx install pyrdp-mitm

You are ready to go! See the usage instructions.

Using the Docker Image

This is the easiest installation method if you have docker installed and working.

docker pull gosecure/pyrdp:latest

As an alternative we have a slimmer image without the GUI and ffmpeg dependencies. This is the only provided image on ARM platforms.

docker pull gosecure/pyrdp:latest-slim

You can find the list of all our Docker images on the gosecure/pyrdp DockerHub page. The latest tag refers to the latest released version while the devel tag is the docker image built out of our main branch.

Using PyRDP

Using the PyRDP Monster-in-the-Middle

Use pyrdp-mitm <ServerIP> or pyrdp-mitm <ServerIP>:<ServerPort> to run the MITM.

Assuming you have an RDP server running on 192.168.1.10 and listening on port 3389, you would run:

pyrdp-mitm 192.168.1.10

When running the MITM for the first time a directory called pyrdp_output/ will be created relative to the current working directory. Here is an example layout of that directory:

pyrdp_output/
├── certs
│   ├── WinDev2108Eval.crt
│   └── WinDev2108Eval.pem
├── files
│   ├── e91c6a5eb3ca15df5a5cb4cf4ebb6f33b2d379a3a12d7d6de8c412d4323feb4c
│   ├── b14b26b7d02c85e74ab4f0d847553b2fdfaf8bc616f7c3efcc4771aeddd55700
├── filesystems
│   ├── romantic_kalam_8214773
│   │   └── device1
│   │   └── clipboard
|           └── priv-esc.exe -> ../../../files/b14b26b7d02c85e74ab4f0d847553b2fdfaf8bc616f7c3efcc4771aeddd55700
│   └── happy_stonebraker_1992243
│       ├── device1
│       └── device2
|           └── Users/User/3D Objects/desktop.ini -> ../../../../../../e91c6a5eb3ca15df5a5cb4cf4ebb6f33b2d379a3a12d7d6de8c412d4323feb4c
├── logs
│   ├── crawl.json
│   ├── crawl.log
│   ├── mitm.json
│   ├── mitm.log
│   ├── mitm.log.2021-08-26
│   ├── ntlmssp.log
│   ├── player.log
│   └── ssl.log
└── replays
    ├── rdp_replay_20231214_01-20-28_965_happy_stonebraker_1992243.pyrdp
    └── rdp_replay_20231214_00-42-24_295_romantic_kalam_8214773.pyrdp
  • certs/ contains the certificates generated stored using the CN of the certificate as the file name
  • files/ contains all files captured and are deduplicated by saving them using the SHA-256 hash of the content as the filename
  • filesystems/ contains a recreation of the filesystem of the targets classified by session IDs. To save space on similar sessions, files are symbolic links to the actual files under files/.
  • logs/ contains all the various logs with most in both JSON and plaintext formats:
  • crawl: the file crawler log
  • mitm: the main MITM log
  • ntlmssp.log: the captured NetNTLM hashes
  • player.log: the player log
  • ssl.log: the TLS master secrets stored in a format compatible with Wireshark
  • replays/ contains all the previously recorded PyRDP sessions with timestamps and session IDs in the filename

Specifying the private key and certificate

If key generation didn't work or you want to use a custom key and certificate, you can specify them using the -c and -k arguments:

pyrdp-mitm 192.168.1.10 -k private_key.pem -c certificate.pem
Monster-in-the-Middle Network Level Authentication (NLA) connections

Network Level Authentication (NLA) is a security feature available since Windows Vista that adds security to RDP connections. NLA relies on the new security support provider CredSSP and is sometimes referred by that name. A server that enforces NLA is harder to attack. There are three different strategies that can be used:

  • Obtain the server's certificate and private key
  • Using a host redirection feature
  • Capture the client's NetNTLMv2 hash and crack it
Monster-in-the-Middle NLA

If we have access to the server's certificate and private key, we can successfully MITM RDP even if NLA is enforced. We documented this attack in our 1.0 release blog post. Instructions to extract the RDP certificate and private key are available on our GitHub.

With the certificate and private key accessible, you just need to set the authentication to ssp by adding this on the pyrdp-mitm.py command-line:

--auth ssp -c <certificate.pem> -k <private-key.pem>

This will enable the possibility to intercept NLA-enforced connections.

Alternative host redirection when NLA enforced by server

Diagram that explains NLA redirection

When PyRDP connects to the destination RDP server (1) if that server enforces NLA then PyRDP (2) will replace the connection to go to another host of your chosing (3) instead.

For example, this can be used to redirect to a server that is known not to enforce NLA or it could even redirect to a VM in the control of an attacker.

To enable this feature specify the alternative host's address and port like this:

--nla-redirection-host 192.168.1.12 --nla-redirection-port 3389

This feature was introduced in PyRDP 1.1.0.

Capturing NetNTLMv2 hashes

NetNTLMv2 hashes are useful for an attacker as they can be cracked relatively easily allowing attackers to leverage legitimate RDP access or attempt credentials stuffing. Starting with version 1.1.0, PyRDP has the ability to capture the client's NetNTLMv2 hashes via an NLA (CredSSP) connection by carrying the negotiation and capturing the NTLMSSP authentication messages. In version 1.2.0 that support was extended to work even if we don't have the server's certificate and private key meaning that the connection will not be successfully MITM'ed. This is similar to what Responder does with RDP. The captured NetNTLMv2 hash can be found in the ntlmssp.log log file and it's formatted so cracking tools like John The Ripper or hashcat can ingest it.

This technique has been described in details in a blog post: Capturing RDP NetNTLMv2 Hashes: Attack details and a Technical How-To Guide

This feature is compatible with --auth ssp but incompatible with --nla-redirection-host.

Connecting to the PyRDP player

If you want to see live RDP connections through the PyRDP player, you will need to specify the IP address and port on which the player is listening using the -i and -d arguments. Note: the port argument is optional, the default port is 3000.

pyrdp-mitm 192.168.1.10 -i 127.0.0.1 -d 3000
Connecting to a PyRDP player when the MITM is running on a server

If you are running the MITM on a server and still want to see live RDP connections, you should use SSH remote port forwarding to forward a port on your server to the player's port on your machine. Once this is done, you pass 127.0.0.1 and the forwarded port as arguments to the MITM. For example, if port 4000 on the server is forwarded to the player's port on your machine, this would be the command to use:

pyrdp-mitm 192.168.1.10 -i 127.0.0.1 -d 4000

Running payloads on new connections

PyRDP has support for running console commands or PowerShell payloads automatically when new connections are made. Due to the nature of RDP, the process is a bit hackish and is not always 100% reliable. Here is how it works:

  1. Wait for the user to be authenticated.
  2. Block the client's input / output to hide the payload and prevent interference.
  3. Send a fake Windows+R sequence and run cmd.exe.
  4. Run the payload as a console command and exit the console. If a PowerShell payload is configured, it is run with powershell -enc <PAYLOAD>.
  5. Wait a bit to allow the payload to complete.
  6. Restore the client's input / output.

For this to work, you need to set 3 arguments:

  • the payload
  • the delay before the payload starts
  • the payload's duration
Setting the payload

You can use one of the following arguments to set the payload to run:

  • --payload, a string containing console commands
  • --payload-powershell, a string containing PowerShell commands
  • --payload-powershell-file, a path to a PowerShell script
Choosing when to start the payload

For the moment, PyRDP does no

Core symbols most depended-on inside this repo

unpack
called by 655
pyrdp/core/packing.py
pack
called by 459
pyrdp/core/packing.py
read
called by 278
pyrdp/core/stream.py
field
called by 192
pyrdp/parser/rdp/orders/primary.py
read_coord
called by 98
pyrdp/parser/rdp/orders/primary.py
write
called by 63
pyrdp/parser/mcs.py
write
called by 63
pyrdp/parser/rdp/slowpath.py
write
called by 60
pyrdp/parser/rdp/connection.py

Shape

Method 1,697
Class 588
Function 120
Route 5

Languages

Python100%

Modules by API surface

pyrdp/parser/rdp/orders/primary.py101 symbols
pyrdp/pdu/rdp/capability.py70 symbols
pyrdp/enum/rdp.py59 symbols
pyrdp/player/gdi/draw.py55 symbols
pyrdp/parser/rdp/orders/parse.py51 symbols
pyrdp/parser/rdp/slowpath.py50 symbols
pyrdp/parser/rdp/fastpath.py49 symbols
pyrdp/pdu/rdp/virtual_channel/device_redirection.py48 symbols
pyrdp/mitm/DeviceRedirectionMITM.py48 symbols
pyrdp/parser/rdp/virtual_channel/device_redirection.py46 symbols
pyrdp/parser/rdp/orders/frontend.py44 symbols
test/test_DeviceRedirectionMITM.py40 symbols

Dependencies from manifests, versioned

Automat22.10.0 · 1×
PySide66.6.1 · 1×
PySide6-Addons6.6.1 · 1×
PySide6-Essentials6.6.1 · 1×
Twisted23.10.0 · 1×
appdirs1.4.4 · 1×
attrs23.2.0 · 1×
av11.0.0 · 1×
cffi1.16.0 · 1×
constantly23.10.4 · 1×
cryptography41.0.7 · 1×
hyperlink21.0.0 · 1×

For agents

$ claude mcp add pyrdp \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact