{"id":13474021,"url":"https://github.com/citronneur/rdpy","last_synced_at":"2025-05-14T20:09:52.071Z","repository":{"id":11156023,"uuid":"13526596","full_name":"citronneur/rdpy","owner":"citronneur","description":"Remote Desktop Protocol in Twisted Python","archived":false,"fork":false,"pushed_at":"2021-06-28T18:46:07.000Z","size":1035,"stargazers_count":1705,"open_issues_count":79,"forks_count":547,"subscribers_count":92,"default_branch":"master","last_synced_at":"2025-04-13T16:01:45.855Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/citronneur.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-10-12T18:23:10.000Z","updated_at":"2025-04-12T06:39:35.000Z","dependencies_parsed_at":"2022-07-12T15:04:12.136Z","dependency_job_id":null,"html_url":"https://github.com/citronneur/rdpy","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/citronneur%2Frdpy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/citronneur%2Frdpy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/citronneur%2Frdpy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/citronneur%2Frdpy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/citronneur","download_url":"https://codeload.github.com/citronneur/rdpy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254219374,"owners_count":22034397,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T16:01:08.901Z","updated_at":"2025-05-14T20:09:52.038Z","avatar_url":"https://github.com/citronneur.png","language":"Python","readme":"# RDPY [![Build Status](https://travis-ci.org/citronneur/rdpy.svg?branch=dev)](https://travis-ci.org/citronneur/rdpy) [![PyPI version](https://badge.fury.io/py/rdpy.png)](http://badge.fury.io/py/rdpy)\n\nRemote Desktop Protocol in twisted python.\n\nRDPY is a pure Python implementation of the Microsoft RDP (Remote Desktop Protocol) protocol (client and server side). RDPY is built over the event driven network engine Twisted. RDPY support standard RDP security layer, RDP over SSL and NLA authentication (through ntlmv2 authentication protocol).\n\nRDPY provides the following RDP and VNC binaries :\n* RDP Man In The Middle proxy which record session\n* RDP Honeypot\n* RDP screenshoter\n* RDP client\n* VNC client\n* VNC screenshoter\n* RSS Player\n\n## Build\n\nRDPY is fully implemented in python, except the bitmap decompression algorithm which is implemented in C for performance purposes.\n\n### Dependencies\n\nDependencies are only needed for pyqt4 binaries :\n* rdpy-rdpclient\n* rdpy-rdpscreenshot\n* rdpy-vncclient\n* rdpy-vncscreenshot\n* rdpy-rssplayer\n\n#### Linux\n\nExample for Debian based systems :\n```\nsudo apt-get install python-qt4\n```\n\n#### OS X\nExample for OS X to install PyQt with homebrew\n```\n$ brew install qt sip pyqt\n```\n\n#### Windows\n\nx86 | x86_64\n----|-------\n[PyQt4](http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.3/PyQt4-4.11.3-gpl-Py2.7-Qt4.8.6-x32.exe) | [PyQt4](http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.3/PyQt4-4.11.3-gpl-Py2.7-Qt4.8.6-x64.exe/download)\n[PyWin32](http://sourceforge.net/projects/pywin32/files/pywin32/Build%20218/pywin32-218.win32-py2.7.exe/download) | [PyWin32](http://sourceforge.net/projects/pywin32/files/pywin32/Build%20218/pywin32-218.win-amd64-py2.7.exe/download)\n\n### Build\n\n```\n$ git clone https://github.com/citronneur/rdpy.git rdpy\n$ pip install twisted pyopenssl qt4reactor service_identity rsa pyasn1\n$ python rdpy/setup.py install\n```\n\nOr use PIP:\n```\n$ pip install rdpy\n```\n\nFor virtualenv, you will need to link the qt4 library to it:\n```\n$ ln -s /usr/lib/python2.7/dist-packages/PyQt4/ $VIRTUAL_ENV/lib/python2.7/site-packages/\n$ ln -s /usr/lib/python2.7/dist-packages/sip.so $VIRTUAL_ENV/lib/python2.7/site-packages/\n```\n\n## RDPY Binaries\n\nRDPY comes with some very useful binaries. These binaries are linux and windows compatible.\n\n### rdpy-rdpclient\n\nrdpy-rdpclient is a simple RDP Qt4 client.\n\n```\n$ rdpy-rdpclient.py [-u username] [-p password] [-d domain] [-r rss_ouput_file] [...] XXX.XXX.XXX.XXX[:3389]\n```\n\nYou can use rdpy-rdpclient in a Recorder Session Scenario, used in rdpy-rdphoneypot.\n\n### rdpy-vncclient\n\nrdpy-vncclient is a simple VNC Qt4 client .\n\n```\n$ rdpy-vncclient.py [-p password] XXX.XXX.XXX.XXX[:5900]\n```\n\n### rdpy-rdpscreenshot\n\nrdpy-rdpscreenshot saves login screen in file.\n\n```\n$ rdpy-rdpscreenshot.py [-w width] [-l height] [-o output_file_path] XXX.XXX.XXX.XXX[:3389]\n```\n\n### rdpy-vncscreenshot\n\nrdpy-vncscreenshot saves the first screen update in file.\n\n```\n$ rdpy-vncscreenshot.py [-p password] [-o output_file_path] XXX.XXX.XXX.XXX[:5900]\n```\n\n### rdpy-rdpmitm\n\nrdpy-rdpmitm is a RDP proxy allows you to do a Man In The Middle attack on RDP protocol.\nRecord Session Scenario into rss file which can be replayed by rdpy-rssplayer.\n\n```\n$ rdpy-rdpmitm.py -o output_dir [-l listen_port] [-k private_key_file_path] [-c certificate_file_path] [-r (for XP or server 2003 client)] target_host[:target_port]\n```\n\nOutput directory is used to save the rss file with following format (YYYYMMDDHHMMSS_ip_index.rss)\nThe private key file and the certificate file are classic cryptographic files for SSL connections. The RDP protocol can negotiate its own security layer If one of both parameters are omitted, the server use standard RDP as security layer.\n\n### rdpy-rdphoneypot\n\nrdpy-rdphoneypot is an RDP honey Pot. Use Recorded Session Scenario to replay scenario through RDP Protocol.\n\n```\n$ rdpy-rdphoneypot.py [-l listen_port] [-k private_key_file_path] [-c certificate_file_path] rss_file_path_1 ... rss_file_path_N\n```\n\nThe private key file and the certificate file are classic cryptographic files for SSL connections. The RDP protocol can negotiate its own security layer. If one of both parameters are omitted, the server use standard RDP as security layer.\nYou can specify more than one files to match more common screen size.\n\n### rdpy-rssplayer\n\nrdpy-rssplayer is use to replay Record Session Scenario (rss) files generates by either rdpy-rdpmitm or rdpy-rdpclient binaries.\n\n```\n$ rdpy-rssplayer.py rss_file_path\n```\n\n## RDPY Qt Widget\n\nRDPY can also be used as Qt widget through rdpy.ui.qt4.QRemoteDesktop class. It can be embedded in your own Qt application. qt4reactor must be used in your app for Twisted and Qt to work together. For more details, see sources of rdpy-rdpclient.\n\n## RDPY library\n\nIn a nutshell RDPY can be used as a protocol library with a twisted engine.\n\n### Simple RDP Client\n\n```python\nfrom rdpy.protocol.rdp import rdp\n\nclass MyRDPFactory(rdp.ClientFactory):\n\n    def clientConnectionLost(self, connector, reason):\n        reactor.stop()\n\n    def clientConnectionFailed(self, connector, reason):\n        reactor.stop()\n\n    def buildObserver(self, controller, addr):\n\n        class MyObserver(rdp.RDPClientObserver):\n\n            def onReady(self):\n                \"\"\"\n                @summary: Call when stack is ready\n                \"\"\"\n                #send 'r' key\n                self._controller.sendKeyEventUnicode(ord(unicode(\"r\".toUtf8(), encoding=\"UTF-8\")), True)\n                #mouse move and click at pixel 200x200\n                self._controller.sendPointerEvent(200, 200, 1, true)\n\n            def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):\n                \"\"\"\n                @summary: Notify bitmap update\n                @param destLeft: xmin position\n                @param destTop: ymin position\n                @param destRight: xmax position because RDP can send bitmap with padding\n                @param destBottom: ymax position because RDP can send bitmap with padding\n                @param width: width of bitmap\n                @param height: height of bitmap\n                @param bitsPerPixel: number of bit per pixel\n                @param isCompress: use RLE compression\n                @param data: bitmap data\n                \"\"\"\n                \n            def onSessionReady(self):\n\t\t        \"\"\"\n\t\t        @summary: Windows session is ready\n\t\t        \"\"\"\n\n            def onClose(self):\n                \"\"\"\n                @summary: Call when stack is close\n                \"\"\"\n\n        return MyObserver(controller)\n\nfrom twisted.internet import reactor\nreactor.connectTCP(\"XXX.XXX.XXX.XXX\", 3389, MyRDPFactory())\nreactor.run()\n```\n\n### Simple RDP Server\n```python\nfrom rdpy.protocol.rdp import rdp\n\nclass MyRDPFactory(rdp.ServerFactory):\n\n    def buildObserver(self, controller, addr):\n\n        class MyObserver(rdp.RDPServerObserver):\n\n            def onReady(self):\n                \"\"\"\n                @summary: Call when server is ready\n                to send and receive messages\n                \"\"\"\n\n            def onKeyEventScancode(self, code, isPressed):\n                \"\"\"\n                @summary: Event call when a keyboard event is catch in scan code format\n                @param code: scan code of key\n                @param isPressed: True if key is down\n                @see: rdp.RDPServerObserver.onKeyEventScancode\n                \"\"\"\n\n            def onKeyEventUnicode(self, code, isPressed):\n                \"\"\"\n                @summary: Event call when a keyboard event is catch in unicode format\n                @param code: unicode of key\n                @param isPressed: True if key is down\n                @see: rdp.RDPServerObserver.onKeyEventUnicode\n                \"\"\"\n\n            def onPointerEvent(self, x, y, button, isPressed):\n                \"\"\"\n                @summary: Event call on mouse event\n                @param x: x position\n                @param y: y position\n                @param button: 1, 2, 3, 4 or 5 button\n                @param isPressed: True if mouse button is pressed\n                @see: rdp.RDPServerObserver.onPointerEvent\n                \"\"\"\n\n            def onClose(self):\n                \"\"\"\n                @summary: Call when human client close connection\n                @see: rdp.RDPServerObserver.onClose\n                \"\"\"\n\n        return MyObserver(controller)\n\nfrom twisted.internet import reactor\nreactor.listenTCP(3389, MyRDPFactory())\nreactor.run()\n```\n\n### Simple VNC Client\n```python\nfrom rdpy.protocol.rfb import rfb\n\nclass MyRFBFactory(rfb.ClientFactory):\n\n    def clientConnectionLost(self, connector, reason):\n        reactor.stop()\n\n    def clientConnectionFailed(self, connector, reason):\n        reactor.stop()\n\n    def buildObserver(self, controller, addr):\n        class MyObserver(rfb.RFBClientObserver):\n\n            def onReady(self):\n                \"\"\"\n                @summary: Event when network stack is ready to receive or send event\n                \"\"\"\n\n            def onUpdate(self, width, height, x, y, pixelFormat, encoding, data):\n                \"\"\"\n                @summary: Implement RFBClientObserver interface\n                @param width: width of new image\n                @param height: height of new image\n                @param x: x position of new image\n                @param y: y position of new image\n                @param pixelFormat: pixefFormat structure in rfb.message.PixelFormat\n                @param encoding: encoding type rfb.message.Encoding\n                @param data: image data in accordance with pixel format and encoding\n                \"\"\"\n\n            def onCutText(self, text):\n                \"\"\"\n                @summary: event when server send cut text event\n                @param text: text received\n                \"\"\"\n\n            def onBell(self):\n                \"\"\"\n                @summary: event when server send biiip\n                \"\"\"\n\n            def onClose(self):\n                \"\"\"\n                @summary: Call when stack is close\n                \"\"\"\n\n        return MyObserver(controller)\n\nfrom twisted.internet import reactor\nreactor.connectTCP(\"XXX.XXX.XXX.XXX\", 3389, MyRFBFactory())\nreactor.run()\n```\n","funding_links":[],"categories":["Uncategorized","Honeypots","\u003ca name=\"honeypots\"\u003e\u003c/a\u003e Honeypots","Tools","Python","\u003ca id=\"tag-dev\" href=\"#tag-dev\"\u003eDev\u003c/a\u003e","Operating Systems"],"sub_categories":["Uncategorized","\u003ca id=\"tag-dev.security\" href=\"#tag-dev.security\"\u003eSecurity\u003c/a\u003e","Windows"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcitronneur%2Frdpy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcitronneur%2Frdpy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcitronneur%2Frdpy/lists"}