From c18a4c41017503d0517449abfe70914729ad3372 Mon Sep 17 00:00:00 2001 From: speidy Date: Sun, 5 Aug 2018 15:15:10 +0300 Subject: [PATCH 1/2] rdpy-rdpmitm: apply pep8 fixes --- bin/rdpy-rdpmitm.py | 87 +++++++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 35 deletions(-) diff --git a/bin/rdpy-rdpmitm.py b/bin/rdpy-rdpmitm.py index b568b7f..c27bf04 100755 --- a/bin/rdpy-rdpmitm.py +++ b/bin/rdpy-rdpmitm.py @@ -29,7 +29,10 @@ Client RDP -> | ProxyServer | ProxyClient | -> Server RDP ----------------- """ -import sys, os, getopt, time +import sys +import os +import argparse +import time from rdpy.core import log, error, rss from rdpy.protocol.rdp import rdp @@ -37,10 +40,12 @@ from twisted.internet import reactor log._LOG_LEVEL = log.Level.INFO + class ProxyServer(rdp.RDPServerObserver): """ @summary: Server side of proxy """ + def __init__(self, controller, target, clientSecurityLevel, rssRecorder): """ @param controller: {RDPServerController} @@ -52,14 +57,14 @@ class ProxyServer(rdp.RDPServerObserver): self._client = None self._rss = rssRecorder self._clientSecurityLevel = clientSecurityLevel - + def setClient(self, client): """ @summary: Event throw by client when it's ready @param client: {ProxyClient} """ self._client = client - + def onReady(self): """ @summary: Event use to inform state of server stack @@ -69,29 +74,30 @@ class ProxyServer(rdp.RDPServerObserver): @see: rdp.RDPServerObserver.onReady """ if self._client is None: - #try a connection + # try a connection domain, username, password = self._controller.getCredentials() - self._rss.credentials(username, password, domain, self._controller.getHostname()) - + self._rss.credentials(username, password, + domain, self._controller.getHostname()) + width, height = self._controller.getScreen() self._rss.screen(width, height, self._controller.getColorDepth()) - - reactor.connectTCP(self._target[0], int(self._target[1]), ProxyClientFactory(self, width, height, - domain, username, password,self._clientSecurityLevel)) - + + reactor.connectTCP(self._target[0], int(self._target[1]), ProxyClientFactory(self, width, height, + domain, username, password, self._clientSecurityLevel)) + def onClose(self): """ @summary: Call when human client close connection @see: rdp.RDPServerObserver.onClose """ - #end scenario + # end scenario self._rss.close() - - #close network stack + + # close network stack if self._client is None: return self._client._controller.close() - + def onKeyEventScancode(self, code, isPressed, isExtended): """ @summary: Event call when a keyboard event is catch in scan code format @@ -102,9 +108,10 @@ class ProxyServer(rdp.RDPServerObserver): """ if self._client is None: return - self._client._controller.sendKeyEventScancode(code, isPressed, isExtended) + self._client._controller.sendKeyEventScancode( + code, isPressed, isExtended) self._rss.keyScancode(code, isPressed) - + def onKeyEventUnicode(self, code, isPressed): """ @summary: Event call when a keyboard event is catch in unicode format @@ -116,7 +123,7 @@ class ProxyServer(rdp.RDPServerObserver): return self._client._controller.sendKeyEventUnicode(code, isPressed) self._rss.keyUnicode(code, isPressed) - + def onPointerEvent(self, x, y, button, isPressed): """ @summary: Event call on mouse event @@ -129,11 +136,13 @@ class ProxyServer(rdp.RDPServerObserver): if self._client is None: return self._client._controller.sendPointerEvent(x, y, button, isPressed) - + + class ProxyServerFactory(rdp.ServerFactory): """ @summary: Factory on listening events """ + def __init__(self, target, ouputDir, privateKeyFilePath, certificateFilePath, clientSecurity): """ @param target: {tuple(ip, prt)} @@ -141,13 +150,14 @@ class ProxyServerFactory(rdp.ServerFactory): @param certificateFilePath: {str} file contain server certificate (if none -> back to standard RDP security) @param clientSecurity: {str(ssl|rdp)} security layer use in client connection side """ - rdp.ServerFactory.__init__(self, 16, privateKeyFilePath, certificateFilePath) + rdp.ServerFactory.__init__( + self, 16, privateKeyFilePath, certificateFilePath) self._target = target self._ouputDir = ouputDir self._clientSecurity = clientSecurity - #use produce unique file by connection + # use produce unique file by connection self._uniqueId = 0 - + def buildObserver(self, controller, addr): """ @param controller: {rdp.RDPServerController} @@ -155,12 +165,14 @@ class ProxyServerFactory(rdp.ServerFactory): @see: rdp.ServerFactory.buildObserver """ self._uniqueId += 1 - return ProxyServer(controller, self._target, self._clientSecurity, rss.createRecorder(os.path.join(self._ouputDir, "%s_%s_%s.rss"%(time.strftime('%Y%m%d%H%M%S'), addr.host, self._uniqueId)))) - + return ProxyServer(controller, self._target, self._clientSecurity, rss.createRecorder(os.path.join(self._ouputDir, "%s_%s_%s.rss" % (time.strftime('%Y%m%d%H%M%S'), addr.host, self._uniqueId)))) + + class ProxyClient(rdp.RDPClientObserver): """ @summary: Client side of proxy """ + def __init__(self, controller, server): """ @param controller: {rdp.RDPClientController} @@ -168,7 +180,7 @@ class ProxyClient(rdp.RDPClientObserver): """ rdp.RDPClientObserver.__init__(self, controller) self._server = server - + def onReady(self): """ @summary: Event use to signal that RDP stack is ready @@ -176,25 +188,26 @@ class ProxyClient(rdp.RDPClientObserver): @see: rdp.RDPClientObserver.onReady """ self._server.setClient(self) - #maybe color depth change - self._server._controller.setColorDepth(self._controller.getColorDepth()) - + # maybe color depth change + self._server._controller.setColorDepth( + self._controller.getColorDepth()) + def onSessionReady(self): """ @summary: Windows session is ready @see: rdp.RDPClientObserver.onSessionReady """ pass - + def onClose(self): """ @summary: Event inform that stack is close @see: rdp.RDPClientObserver.onClose """ - #end scenario + # end scenario self._server._rss.close() self._server._controller.close() - + def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data): """ @summary: Event use to inform bitmap update @@ -209,13 +222,17 @@ class ProxyClient(rdp.RDPClientObserver): @param data: {str} bitmap data @see: rdp.RDPClientObserver.onUpdate """ - self._server._rss.update(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, rss.UpdateFormat.BMP if isCompress else rss.UpdateFormat.RAW, data) - self._server._controller.sendUpdate(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data) + self._server._rss.update(destLeft, destTop, destRight, destBottom, width, height, + bitsPerPixel, rss.UpdateFormat.BMP if isCompress else rss.UpdateFormat.RAW, data) + self._server._controller.sendUpdate( + destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data) + class ProxyClientFactory(rdp.ClientFactory): """ @summary: Factory for proxy client """ + def __init__(self, server, width, height, domain, username, password, security): """ @param server: {ProxyServer} @@ -233,7 +250,7 @@ class ProxyClientFactory(rdp.ClientFactory): self._username = username self._password = password self._security = security - + def buildObserver(self, controller, addr): """ @summary: Build observer @@ -242,9 +259,9 @@ class ProxyClientFactory(rdp.ClientFactory): @see: rdp.ClientFactory.buildObserver @return: ProxyClient """ - #set screen resolution + # set screen resolution controller.setScreen(self._width, self._height) - #set credential + # set credential controller.setDomain(self._domain) controller.setUsername(self._username) controller.setPassword(self._password) From bcec1aad25916eefe1327a28d4c41a572abd2f21 Mon Sep 17 00:00:00 2001 From: speidy Date: Sun, 5 Aug 2018 15:21:36 +0300 Subject: [PATCH 2/2] rdpy-rdpmitm: use `argparse` for argument parsing --- bin/rdpy-rdpmitm.py | 100 +++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 52 deletions(-) diff --git a/bin/rdpy-rdpmitm.py b/bin/rdpy-rdpmitm.py index c27bf04..fcbf3c4 100755 --- a/bin/rdpy-rdpmitm.py +++ b/bin/rdpy-rdpmitm.py @@ -268,60 +268,56 @@ class ProxyClientFactory(rdp.ClientFactory): controller.setSecurityLevel(self._security) controller.setPerformanceSession() return ProxyClient(controller, self._server) - -def help(): - """ - @summary: Print help in console - """ - print """ - Usage: rdpy-rdpmitm.py -o output_directory target - [-l listen_port default 3389] - [-k private_key_file_path (mandatory for SSL)] - [-c certificate_file_path (mandatory for SSL)] - [-o output directory for recoded files] - [-r RDP standard security (XP or server 2003 client or older)] - [-n For NLA Client authentication (need to provide credentials)] - """ -def parseIpPort(interface, defaultPort = "3389"): + +def parseIpPort(interface, defaultPort="3389"): if ':' in interface: - return interface.split(':') + s = interface.split(':') + return s[0], int(s[1]) else: - return interface, defaultPort + return interface, int(defaultPort) + + +def isDirectory(outputDirectory): + if outputDirectory is None or not os.path.dirname(outputDirectory): + log.error("{} is an invalid output directory or directory doesn't exist".format( + outputDirectory)) + return outputDirectory + + +def mapSecurityLayer(layer): + return { + "rdp": rdp.SecurityLevel.RDP_LEVEL_RDP, + "tls": rdp.SecurityLevel.RDP_LEVEL_SSL, + "nla": rdp.SecurityLevel.RDP_LEVEL_NLA + }[layer] + if __name__ == '__main__': - listen = "3389" - privateKeyFilePath = None - certificateFilePath = None - ouputDirectory = None - #for anonymous authentication - clientSecurity = rdp.SecurityLevel.RDP_LEVEL_SSL - - try: - opts, args = getopt.getopt(sys.argv[1:], "hl:k:c:o:rn") - except getopt.GetoptError: - help() - for opt, arg in opts: - if opt == "-h": - help() - sys.exit() - elif opt == "-l": - listen = arg - elif opt == "-k": - privateKeyFilePath = arg - elif opt == "-c": - certificateFilePath = arg - elif opt == "-o": - ouputDirectory = arg - elif opt == "-r": - clientSecurity = rdp.SecurityLevel.RDP_LEVEL_RDP - elif opt == "-n": - clientSecurity = rdp.SecurityLevel.RDP_LEVEL_NLA - - if ouputDirectory is None or not os.path.dirname(ouputDirectory): - log.error("%s is an invalid output directory"%ouputDirectory) - help() - sys.exit() - - reactor.listenTCP(int(listen), ProxyServerFactory(parseIpPort(args[0]), ouputDirectory, privateKeyFilePath, certificateFilePath, clientSecurity)) - reactor.run() \ No newline at end of file + p = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + + p.add_argument('-l', '--listen', type=parseIpPort, default="0.0.0.0:3389", + help="[:] to bind the server") + p.add_argument('-t', '--target', type=parseIpPort, required=True, + help="[:] of the target you want to connect to via proxy") + p.add_argument('-o', '--output', type=isDirectory, + help="output directory", required=True) + p.add_argument('-s', '--sec', choices=["rdp", "tls", "nla"], + default="rdp", help="set protocol security layer") + ssl = p.add_argument_group() + ssl.add_argument('-c', '--certificate', help="certificate for TLS connections") + ssl.add_argument('-k', '--key', help="private key of the given certificate for TLS connections") + + args = p.parse_args() + + if args.certificate and args.key and not args.sec == "nla": + args.sec = "tls" + + log.info("running server on {addr}, using {sec} security layer, proxying to {target}".format( + addr=args.listen, sec=args.sec.upper(), target=args.target)) + reactor.listenTCP(args.listen[1], ProxyServerFactory( + args.target, args.output, args.key, args.certificate, mapSecurityLayer(args.sec)), + interface=args.listen[0]) + + reactor.run()