diff --git a/.gitignore b/.gitignore index 56750d33..b5f971a1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ README.md~ dist/* build/* rdpy.egg-info/* +# version +rdpy-*.*.* +temp diff --git a/.travis.yml b/.travis.yml index e3494681..f1f7122b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,13 @@ language: python python: - - 2.7 + - 3.8 before_install: - - sudo apt-get install python-qt4 - - ln -s /usr/lib/python2.7/dist-packages/PyQt4/ $VIRTUAL_ENV/lib/python2.7/site-packages/ - - ln -s /usr/lib/python2.7/dist-packages/sip.so $VIRTUAL_ENV/lib/python2.7/site-packages/ - - pip install qt4reactor pyopenssl twisted service_identity rsa pyasn1 + - sudo apt-get install python-qt5 + - ln -s /usr/lib/python3.8/dist-packages/PyQt5/ $VIRTUAL_ENV/lib/python3.8/site-packages/ + - ln -s /usr/lib/python3.8/dist-packages/sip.so $VIRTUAL_ENV/lib/python3.8/site-packages/ + - pip install qt5reactor pyopenssl twisted service_identity rsa pyasn1 install: - python setup.py install diff --git a/README.md b/README.md index dd6543ed..559be7a3 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ RDPY is fully implemented in python, except the bitmap decompression algorithm w ### Dependencies -Dependencies are only needed for pyqt4 binaries : +Dependencies are only needed for pyqt5 binaries : * rdpy-rdpclient * rdpy-rdpscreenshot * rdpy-vncclient @@ -30,7 +30,7 @@ Dependencies are only needed for pyqt4 binaries : Example for Debian based systems : ``` -sudo apt-get install python-qt4 +sudo apt-get install python-qt5 ``` #### OS X @@ -41,16 +41,13 @@ $ brew install qt sip pyqt #### Windows -x86 | x86_64 -----|------- -[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) -[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) +… FIXME … ### Build ``` $ git clone https://github.com/citronneur/rdpy.git rdpy -$ pip install twisted pyopenssl qt4reactor service_identity rsa pyasn1 +$ pip install twisted pyopenssl qt5reactor service_identity rsa pyasn1 $ python rdpy/setup.py install ``` @@ -59,10 +56,10 @@ Or use PIP: $ pip install rdpy ``` -For virtualenv, you will need to link the qt4 library to it: +For virtualenv, you will need to link the qt5 library to it: ``` -$ ln -s /usr/lib/python2.7/dist-packages/PyQt4/ $VIRTUAL_ENV/lib/python2.7/site-packages/ -$ ln -s /usr/lib/python2.7/dist-packages/sip.so $VIRTUAL_ENV/lib/python2.7/site-packages/ +$ ln -s /usr/lib/python3.8/dist-packages/PyQt5/ $VIRTUAL_ENV/lib/python3.8/site-packages/ +$ ln -s /usr/lib/python3.8/dist-packages/sip.so $VIRTUAL_ENV/lib/python3.8/site-packages/ ``` ## RDPY Binaries @@ -71,7 +68,7 @@ RDPY comes with some very useful binaries. These binaries are linux and windows ### rdpy-rdpclient -rdpy-rdpclient is a simple RDP Qt4 client. +rdpy-rdpclient is a simple RDP Qt5 client. ``` $ rdpy-rdpclient.py [-u username] [-p password] [-d domain] [-r rss_ouput_file] [...] XXX.XXX.XXX.XXX[:3389] @@ -81,7 +78,7 @@ You can use rdpy-rdpclient in a Recorder Session Scenario, used in rdpy-rdphoney ### rdpy-vncclient -rdpy-vncclient is a simple VNC Qt4 client . +rdpy-vncclient is a simple VNC Qt5 client . ``` $ rdpy-vncclient.py [-p password] XXX.XXX.XXX.XXX[:5900] @@ -136,7 +133,7 @@ $ rdpy-rssplayer.py rss_file_path ## RDPY Qt Widget -RDPY 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. +RDPY can also be used as Qt widget through rdpy.ui.qt5.QRemoteDesktop class. It can be embedded in your own Qt application. qt5reactor must be used in your app for Twisted and Qt to work together. For more details, see sources of rdpy-rdpclient. ## RDPY library diff --git a/bin/rdpy-rdpclient.py b/bin/rdpy-rdpclient.py index 660bfa4f..eaa4020f 100755 --- a/bin/rdpy-rdpclient.py +++ b/bin/rdpy-rdpclient.py @@ -23,8 +23,8 @@ import sys, os, getopt, socket -from PyQt4 import QtGui, QtCore -from rdpy.ui.qt4 import RDPClientQt +from PyQt5 import QtGui, QtCore, QtWidgets +from rdpy.ui.qt5 import RDPClientQt from rdpy.protocol.rdp import rdp from rdpy.core.error import RDPSecurityNegoFail from rdpy.core import rss @@ -32,6 +32,12 @@ import rdpy.core.log as log log._LOG_LEVEL = log.Level.INFO +def stop(reactor): + try: + reactor.stop() + except Exception as e: + log.warning(f"Error stopping reactor: {e}") + class RDPClientQtRecorder(RDPClientQt): """ @@ -173,7 +179,8 @@ def clientConnectionLost(self, connector, reason): return log.info("Lost connection : %s"%reason) - reactor.stop() + # reactor.stop() + stop(reactor) app.exit() def clientConnectionFailed(self, connector, reason): @@ -183,7 +190,8 @@ def clientConnectionFailed(self, connector, reason): @param reason: str use to advertise reason of lost connection """ log.info("Connection failed : %s"%reason) - reactor.stop() + # reactor.stop() + stop(reactor) app.exit() def autoDetectKeyboardLayout(): @@ -211,7 +219,7 @@ def autoDetectKeyboardLayout(): return "en" def help(): - print """ + print(""" Usage: rdpy-rdpclient [options] ip[:port]" \t-u: user name \t-p: password @@ -222,7 +230,7 @@ def help(): \t-k: keyboard layout [en|fr] [default : en] \t-o: optimized session (disable costly effect) [default : False] \t-r: rss_filepath Recorded Session Scenario [default : None] - """ + """) if __name__ == '__main__': @@ -240,7 +248,7 @@ def help(): try: opts, args = getopt.getopt(sys.argv[1:], "hfou:p:d:w:l:k:r:") except getopt.GetoptError: - help() + opts = [('-h', '')] for opt, arg in opts: if opt == "-h": help() @@ -270,11 +278,11 @@ def help(): ip, port = args[0], "3389" #create application - app = QtGui.QApplication(sys.argv) - - #add qt4 reactor - import qt4reactor - qt4reactor.install() + app = QtWidgets.QApplication(sys.argv) + + #add qt5 reactor + import qt5reactor + qt5reactor.install() if fullscreen: width = QtGui.QDesktopWidget().screenGeometry().width() diff --git a/bin/rdpy-rdphoneypot.py b/bin/rdpy-rdphoneypot.py index 575215ba..d65a3502 100755 --- a/bin/rdpy-rdphoneypot.py +++ b/bin/rdpy-rdphoneypot.py @@ -94,7 +94,7 @@ def loopScenario(self, nextEvent): clientSize = nextEvent.event.width.value, nextEvent.event.height.value serverSize = self._controller.getScreen() - self._dx, self._dy = (max(0, serverSize[0] - clientSize[0]) / 2), max(0, (serverSize[1] - clientSize[1]) / 2) + self._dx, self._dy = (max(0, serverSize[0] - clientSize[0]) // 2), max(0, (serverSize[1] - clientSize[1]) // 2) #restart connection sequence return @@ -140,14 +140,14 @@ def help(): """ @summary: Print help in console """ - print """ + print(""" Usage: rdpy-rdphoneypot.py [-L logfile] [-l listen_port default 3389] [-k private_key_file_path (mandatory for SSL)] [-c certificate_file_path (mandatory for SSL)] rss_filepath(1..n) - """ + """) if __name__ == '__main__': listen = "3389" @@ -158,7 +158,7 @@ def help(): try: opts, args = getopt.getopt(sys.argv[1:], "hl:k:c:L:") except getopt.GetoptError: - help() + opts = [('-h', '')] for opt, arg in opts: if opt == "-h": help() diff --git a/bin/rdpy-rdpscreenshot.py b/bin/rdpy-rdpscreenshot.py index b87008ab..3290420f 100755 --- a/bin/rdpy-rdpscreenshot.py +++ b/bin/rdpy-rdpscreenshot.py @@ -27,16 +27,27 @@ import os import sys -from PyQt4 import QtCore, QtGui +from PyQt5 import QtCore, QtGui, QtWidgets from rdpy.protocol.rdp import rdp -from rdpy.ui.qt4 import RDPBitmapToQtImage +from rdpy.ui.qt5 import RDPBitmapToQtImage import rdpy.core.log as log from rdpy.core.error import RDPSecurityNegoFail from twisted.internet import task +from rdpy.core.layer import RawLayer + # set log level log._LOG_LEVEL = log.Level.INFO +def stop(reactor): + try: + # https://stackoverflow.com/a/13538248 + reactor.removeAll() + reactor.iterate() + reactor.stop() + except Exception as e: + log.warning(f"Error stopping reactor: {e}") + class RDPScreenShotFactory(rdp.ClientFactory): """ @@ -69,17 +80,20 @@ def clientConnectionLost(self, connector, reason): @param connector: twisted connector use for rdp connection (use reconnect to restart connection) @param reason: str use to advertise reason of lost connection """ - if reason.type == RDPSecurityNegoFail and self._security != "rdp": + if reason.type == RDPSecurityNegoFail and self._security != rdp.SecurityLevel.RDP_LEVEL_RDP: log.info("due to RDPSecurityNegoFail try standard security layer") self._security = rdp.SecurityLevel.RDP_LEVEL_RDP connector.connect() return - log.info("connection lost : %s" % reason) + if "Connection was closed cleanly" not in f"{reason}": + log.info("connection lost : %s" % reason) + RDPScreenShotFactory.__STATE__.append((connector.host, connector.port, reason)) RDPScreenShotFactory.__INSTANCE__ -= 1 if(RDPScreenShotFactory.__INSTANCE__ == 0): - self._reactor.stop() + #self._reactor.stop() + stop(self._reactor) self._app.exit() def clientConnectionFailed(self, connector, reason): @@ -92,7 +106,8 @@ def clientConnectionFailed(self, connector, reason): RDPScreenShotFactory.__STATE__.append((connector.host, connector.port, reason)) RDPScreenShotFactory.__INSTANCE__ -= 1 if(RDPScreenShotFactory.__INSTANCE__ == 0): - self._reactor.stop() + #self._reactor.stop() + stop(self._reactor) self._app.exit() def buildObserver(self, controller, addr): @@ -120,6 +135,7 @@ def __init__(self, controller, width, height, path, timeout, reactor): self._timeout = timeout self._startTimeout = False self._reactor = reactor + self._got_screenshot = False def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data): """ @@ -127,8 +143,10 @@ def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bits """ image = RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data); with QtGui.QPainter(self._buffer) as qp: - # draw image + # draw image qp.drawImage(destLeft, destTop, image, 0, 0, destRight - destLeft + 1, destBottom - destTop + 1) + log.info(f"incoming frame pos={destLeft},{destTop} size={destRight - destLeft + 1},{destBottom - destTop + 1}") + self._got_screenshot = True if not self._startTimeout: self._startTimeout = False self._reactor.callLater(self._timeout, self.checkUpdate) @@ -150,13 +168,15 @@ def onClose(self): """ @summary: callback use when RDP stack is closed """ - log.info("save screenshot into %s" % self._path) - self._buffer.save(self._path) + if self._got_screenshot: + log.info("save screenshot into %s" % self._path) + self._buffer.save(self._path) + log.info("close") def checkUpdate(self): - self._controller.close(); + self._controller.close() - controller.setScreen(self._width, self._height); + controller.setScreen(self._width, self._height) controller.setSecurityLevel(self._security) return ScreenShotObserver(controller, self._width, self._height, self._path, self._timeout, self._reactor) @@ -170,20 +190,40 @@ def main(width, height, path, timeout, hosts): @return: {list(tuple(ip, port, Failure instance)} list of connection state """ #create application - app = QtGui.QApplication(sys.argv) + app = QtWidgets.QApplication(sys.argv) - #add qt4 reactor - import qt4reactor - qt4reactor.install() + #add qt5 reactor + import qt5reactor + qt5reactor.install() from twisted.internet import reactor + # FIXME + if len(hosts) != 1: + raise Exception(f"Only one host supported, got {hosts}") + for host in hosts: if ':' in host: ip, port = host.split(':') else: ip, port = host, "3389" + # FIXME + out_file = path + "%s.bin" % ip + if os.path.exists(out_file): + os.unlink(out_file) + print(f"[*] INFO: out_file={out_file}") + def hack(data): + # print(f"FOOBAR data {data}") + # only first line + if os.path.exists(out_file): + return + out= open(out_file, "ab") + out.write(data) + # out.write(b"\n") + out.close() + RawLayer.__hack__ = hack + reactor.connectTCP(ip, int(port), RDPScreenShotFactory(reactor, app, width, height, path + "%s.jpg" % ip, timeout)) reactor.runReturn() @@ -192,23 +232,23 @@ def main(width, height, path, timeout, hosts): def help(): - print "Usage: rdpy-rdpscreenshot [options] ip[:port]" - print "\t-w: width of screen default value is 1024" - print "\t-l: height of screen default value is 800" - print "\t-o: file path of screenshot default(/tmp/rdpy-rdpscreenshot.jpg)" - print "\t-t: timeout of connection without any updating order (default is 2s)" + print("Usage: rdpy-rdpscreenshot [options] ip[:port]") + print("\t-w: width of screen default value is 1024") + print("\t-l: height of screen default value is 800") + print("\t-o: file path of screenshot default(/tmp/rdpy-rdpscreenshot.jpg)") + print("\t-t: timeout of connection without any updating order (default is 2s)") if __name__ == '__main__': # default script argument width = 1024 height = 800 path = "/tmp/" - timeout = 5.0 + timeout = 2.0 try: opts, args = getopt.getopt(sys.argv[1:], "hw:l:o:t:") except getopt.GetoptError: - help() + opts = [('-h', '')] for opt, arg in opts: if opt == "-h": help() @@ -222,4 +262,6 @@ def help(): elif opt == "-t": timeout = float(arg) + # print(f"opts={opts} args={args}") + main(width, height, path, timeout, args) diff --git a/bin/rdpy-rssplayer.py b/bin/rdpy-rssplayer.py index 82f26a78..035e2fe0 100755 --- a/bin/rdpy-rssplayer.py +++ b/bin/rdpy-rssplayer.py @@ -23,10 +23,10 @@ import sys, os, getopt, socket -from PyQt4 import QtGui, QtCore +from PyQt5 import QtGui, QtCore, QtWidgets from rdpy.core import log, rss -from rdpy.ui.qt4 import QRemoteDesktop, RDPBitmapToQtImage +from rdpy.ui.qt5 import QRemoteDesktop, RDPBitmapToQtImage from rdpy.core.scancode import scancodeToChar log._LOG_LEVEL = log.Level.INFO @@ -46,7 +46,7 @@ def closeEvent(self, e): """ Not Handle """ QRemoteDesktop.__init__(self, width, height, RssAdaptor()) -class RssPlayerWindow(QtGui.QWidget): +class RssPlayerWindow(QtWidgets.QWidget): """ @summary: main window of rss player """ @@ -70,7 +70,7 @@ def __init__(self): self.setGeometry(0, 0, 800, 600) def help(): - print "Usage: rdpy-rssplayer [-h] rss_filepath" + print("Usage: rdpy-rssplayer [-h] rss_filepath") def start(widget, rssFile): loop(widget, rssFile, rssFile.nextEvent()) @@ -107,7 +107,7 @@ def loop(widget, rssFile, nextEvent): try: opts, args = getopt.getopt(sys.argv[1:], "h") except getopt.GetoptError: - help() + opts = [('-h', '')] for opt, arg in opts: if opt == "-h": help() @@ -115,7 +115,7 @@ def loop(widget, rssFile, nextEvent): filepath = args[0] #create application - app = QtGui.QApplication(sys.argv) + app = QtWidgets.QApplication(sys.argv) mainWindow = RssPlayerWindow() mainWindow.show() diff --git a/bin/rdpy-vncclient.py b/bin/rdpy-vncclient.py index 5a6e6b84..a08bdea9 100755 --- a/bin/rdpy-vncclient.py +++ b/bin/rdpy-vncclient.py @@ -23,13 +23,20 @@ """ import sys, os, getopt -from PyQt4 import QtGui -from rdpy.ui.qt4 import RFBClientQt +from PyQt5 import QtGui, QtWidgets +from rdpy.ui.qt5 import RFBClientQt from rdpy.protocol.rfb import rfb import rdpy.core.log as log log._LOG_LEVEL = log.Level.INFO - + +def stop(reactor): + try: + reactor.stop() + except Exception as e: + log.warning(f"Error stopping reactor: {e}") + + class RFBClientQtFactory(rfb.ClientFactory): """ @summary: Factory create a VNC GUI client @@ -62,8 +69,9 @@ def clientConnectionLost(self, connector, reason): @param connector: twisted connector use for vnc connection (use reconnect to restart connection) @param reason: str use to advertise reason of lost connection """ - QtGui.QMessageBox.warning(self._w, "Warning", "Lost connection : %s"%reason) - reactor.stop() + QtWidgets.QMessageBox.warning(self._w, "Warning", "Lost connection : %s"%reason) + # reactor.stop() + stop(reactor) app.exit() def clientConnectionFailed(self, connector, reason): @@ -72,8 +80,9 @@ def clientConnectionFailed(self, connector, reason): @param connector: twisted connector use for vnc connection (use reconnect to restart connection) @param reason: str use to advertise reason of lost connection """ - QtGui.QMessageBox.warning(self._w, "Warning", "Connection failed : %s"%reason) - reactor.stop() + QtWidgets.QMessageBox.warning(self._w, "Warning", "Connection failed : %s"%reason) + # reactor.stop() + stop(reactor) app.exit() if __name__ == '__main__': @@ -84,7 +93,7 @@ def clientConnectionFailed(self, connector, reason): try: opts, args = getopt.getopt(sys.argv[1:], "hp:") except getopt.GetoptError: - help() + opts = [('-h', '')] for opt, arg in opts: if opt == "-h": help() @@ -98,11 +107,11 @@ def clientConnectionFailed(self, connector, reason): ip, port = args[0], "5900" #create application - app = QtGui.QApplication(sys.argv) + app = QtWidgets.QApplication(sys.argv) - #add qt4 reactor - import qt4reactor - qt4reactor.install() + #add qt5 reactor + import qt5reactor + qt5reactor.install() from twisted.internet import reactor reactor.connectTCP(ip, int(port), RFBClientQtFactory(password)) diff --git a/bin/rdpy-vncscreenshot.py b/bin/rdpy-vncscreenshot.py index a3cb7ecf..5d566ab3 100755 --- a/bin/rdpy-vncscreenshot.py +++ b/bin/rdpy-vncscreenshot.py @@ -24,27 +24,41 @@ """ import sys, os, getopt -from PyQt4 import QtCore, QtGui +from PyQt5 import QtCore, QtGui, QtWidgets from rdpy.protocol.rfb import rfb import rdpy.core.log as log -from rdpy.ui.qt4 import qtImageFormatFromRFBPixelFormat +from rdpy.ui.qt5 import qtImageFormatFromRFBPixelFormat from twisted.internet import task +from rdpy.core.layer import RawLayer + #set log level log._LOG_LEVEL = log.Level.INFO +def stop(reactor): + try: + # https://stackoverflow.com/a/13538248 + reactor.removeAll() + reactor.iterate() + reactor.stop() + except Exception as e: + log.warning(f"Error stopping reactor: {e}") + + class RFBScreenShotFactory(rfb.ClientFactory): """ @summary: Factory for screenshot exemple """ __INSTANCE__ = 0 - def __init__(self, password, path): + def __init__(self, reactor, password, path, timeout): """ @param password: password for VNC authentication @param path: path of output screenshot """ RFBScreenShotFactory.__INSTANCE__ += 1 + self._reactor = reactor self._path = path + self._timeout = timeout self._password = password def clientConnectionLost(self, connector, reason): @@ -53,10 +67,12 @@ def clientConnectionLost(self, connector, reason): @param connector: twisted connector use for rfb connection (use reconnect to restart connection) @param reason: str use to advertise reason of lost connection """ - log.info("connection lost : %s"%reason) + if "Connection was closed cleanly" not in f"{reason}": + log.info("connection lost : %s"%reason) RFBScreenShotFactory.__INSTANCE__ -= 1 if(RFBScreenShotFactory.__INSTANCE__ == 0): - reactor.stop() + # reactor.stop() + stop(reactor) app.exit() def clientConnectionFailed(self, connector, reason): @@ -68,7 +84,8 @@ def clientConnectionFailed(self, connector, reason): log.info("connection failed : %s"%reason) RFBScreenShotFactory.__INSTANCE__ -= 1 if(RFBScreenShotFactory.__INSTANCE__ == 0): - reactor.stop() + # reactor.stop() + stop(reactor) app.exit() @@ -82,7 +99,7 @@ class ScreenShotObserver(rfb.RFBClientObserver): """ @summary: observer that connect, cache every image received and save at deconnection """ - def __init__(self, controller, path): + def __init__(self, controller, path, timeout, reactor): """ @param controller: RFBClientController @param path: path of output screenshot @@ -90,6 +107,10 @@ def __init__(self, controller, path): rfb.RFBClientObserver.__init__(self, controller) self._path = path self._buffer = None + self._timeout = timeout + self._reactor = reactor + self._startTimeout = False + self._got_screenshot = False def onUpdate(self, width, height, x, y, pixelFormat, encoding, data): """ @@ -108,43 +129,57 @@ def onUpdate(self, width, height, x, y, pixelFormat, encoding, data): return image = QtGui.QImage(data, width, height, imageFormat) with QtGui.QPainter(self._buffer) as qp: - #draw image + #draw image qp.drawImage(x, y, image, 0, 0, width, height) - - self._controller.close() - + log.info(f"incoming frame pos={x},{y} size={width},{height}") + self._got_screenshot = True + self.mouseEvent(1, 1, 1) + self.keyEvent(True, 27) # escape key + + if not self._startTimeout: + self._startTimeout = False + self._reactor.callLater(self._timeout, self.checkUpdate) + def onReady(self): """ @summary: callback use when RDP stack is connected (just before received bitmap) """ log.info("connected %s"%addr) - width, height = self._controller.getScreen() - self._buffer = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32) + self._width, self._height = self._controller.getScreen() + log.info(f"ready size={self._width},{self._height}") + self._buffer = QtGui.QImage(self._width, self._height, QtGui.QImage.Format_RGB32) def onClose(self): """ @summary: callback use when RDP stack is closed """ - log.info("save screenshot into %s"%self._path) - self._buffer.save(self._path) + if self._got_screenshot: + log.info("save screenshot into %s"%self._path) + self._buffer.save(self._path) + log.info("close") + def checkUpdate(self): + self._controller.close() + controller.setPassword(self._password) - return ScreenShotObserver(controller, self._path) + return ScreenShotObserver(controller, self._path, self._timeout, self._reactor) def help(): - print "Usage: rdpy-vncscreenshot [options] ip[:port]" - print "\t-o: file path of screenshot default(/tmp/rdpy-vncscreenshot.jpg)" - print "\t-p: password for VNC Session" + print("Usage: rdpy-vncscreenshot [options] ip[:port]") + print("\t-o: file path of screenshot default(/tmp/rdpy-vncscreenshot.jpg)") + print("\t-t: timeout of connection without any updating order (default is 2s)") + print("\t-p: password for VNC Session") if __name__ == '__main__': #default script argument path = "/tmp/" + timeout = 2.0 password = "" try: opts, args = getopt.getopt(sys.argv[1:], "hp:o:") except getopt.GetoptError: - help() + opts = [('-h', '')] for opt, arg in opts: if opt == "-h": help() @@ -153,24 +188,46 @@ def help(): path = arg elif opt == "-p": password = arg + elif opt == "-t": + timeout = float(arg) #create application - app = QtGui.QApplication(sys.argv) + app = QtWidgets.QApplication(sys.argv) - #add qt4 reactor - import qt4reactor - qt4reactor.install() + #add qt5 reactor + import qt5reactor + qt5reactor.install() from twisted.internet import reactor + + # FIXME + if len(args) != 1: + raise Exception(f"Only one host supported, got {args}") for arg in args: if ':' in arg: ip, port = arg.split(':') else: ip, port = arg, "5900" - - reactor.connectTCP(ip, int(port), RFBScreenShotFactory(password, path + "%s.jpg"%ip)) - + + # FIXME + out_file = path + "%s.bin" % ip + if os.path.exists(out_file): + os.unlink(out_file) + print(f"[*] INFO: out_file={out_file}") + def hack(data): + # print(f"FOOBAR data {data}") + # only first line + if os.path.exists(out_file): + return + out= open(out_file, "ab") + out.write(data) + # out.write(b"\n") + out.close() + RawLayer.__hack__ = hack + + reactor.connectTCP(ip, int(port), RFBScreenShotFactory(reactor, password, path + "%s.jpg" % ip, timeout)) + reactor.runReturn() app.exec_() \ No newline at end of file diff --git a/ext/rle.c b/ext/rle.c index 2d7da8db..4359375e 100644 --- a/ext/rle.c +++ b/ext/rle.c @@ -939,9 +939,18 @@ static PyMethodDef rle_methods[] = {NULL, NULL, 0, NULL} }; +static struct PyModuleDef rle = +{ + PyModuleDef_HEAD_INIT, + "rle", /* name of module */ + "", /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ + rle_methods +}; + PyMODINIT_FUNC -initrle(void) +PyInit_rle(void) { - (void) Py_InitModule("rle", rle_methods); + (void) PyModule_Create(&rle); } diff --git a/rdpy/core/const.py b/rdpy/core/const.py index 6e8489ad..27f9d5eb 100644 --- a/rdpy/core/const.py +++ b/rdpy/core/const.py @@ -64,7 +64,7 @@ def TypeAttributes(typeClass): @return: class decorator """ def wrapper(cls): - for c_name, c_value in cls.__dict__.iteritems(): + for c_name, c_value in cls.__dict__.items(): if c_name[0] != '_' and not callable(c_value): setattr(cls, c_name, typeClass(c_value)) return cls diff --git a/rdpy/core/layer.py b/rdpy/core/layer.py index 7194495b..3d6cb3fb 100644 --- a/rdpy/core/layer.py +++ b/rdpy/core/layer.py @@ -107,7 +107,7 @@ def setNextState(self, callback = None): from twisted.internet import protocol from twisted.internet.abstract import FileDescriptor #first that handle stream -from type import Stream +from rdpy.core.type import Stream class RawLayerClientFactory(protocol.ClientFactory): """ @@ -179,7 +179,7 @@ def __init__(self, presentation = None): #call parent automata LayerAutomata.__init__(self, presentation) #data buffer received from twisted network layer - self._buffer = "" + self._buffer = b"" #len of next packet pass to next state function self._expectedLen = 0 self._factory = None @@ -199,6 +199,11 @@ def dataReceived(self, data): """ #add in buffer self._buffer += data + + if hasattr(self, '__hack__'): + RawLayer.__hack__(data) + # print(f"dataReceived {data}") + #while buffer have expected size call local callback while self._expectedLen > 0 and len(self._buffer) >= self._expectedLen: #expected data is first expected bytes diff --git a/rdpy/core/log.py b/rdpy/core/log.py index cabd7752..d8ebbb84 100644 --- a/rdpy/core/log.py +++ b/rdpy/core/log.py @@ -44,7 +44,7 @@ def log(message): f = open(_LOG_FILE, "a+") f.write("%s\n"%message) f.close() - print "[*] %s"%message + print("[*] %s"%message) def error(message): """ diff --git a/rdpy/core/scancode.py b/rdpy/core/scancode.py index 37e27d6c..d877becb 100644 --- a/rdpy/core/scancode.py +++ b/rdpy/core/scancode.py @@ -55,6 +55,6 @@ def scancodeToChar(code): @summary: try to convert native code to char code @return: char """ - if not _SCANCODE_QWERTY_.has_key(code): + if code not in _SCANCODE_QWERTY_: return ""%code return _SCANCODE_QWERTY_[code]; \ No newline at end of file diff --git a/rdpy/core/type.py b/rdpy/core/type.py index 260c6727..a5539814 100644 --- a/rdpy/core/type.py +++ b/rdpy/core/type.py @@ -26,9 +26,10 @@ import struct from copy import deepcopy -from StringIO import StringIO +from io import BytesIO from rdpy.core.error import InvalidExpectedDataException, InvalidSize, CallPureVirtualFuntion, InvalidValue import rdpy.core.log as log +from os import SEEK_END def sizeof(element): """ @@ -103,7 +104,7 @@ def read(self, s): #check constant value if old != self: #rollback read value - s.pos -= sizeof(self) + s._pos(s._pos() - sizeof(self)) raise InvalidExpectedDataException("%s const value expected %s != %s"%(self.__class__, old.value, self.value)) def __read__(self, s): @@ -203,6 +204,9 @@ def __init__(self, structFormat, typeSize, signed, value, conditional = lambda:T self._structFormat = structFormat Type.__init__(self, conditional = conditional, optional = optional, constant = constant) CallableValue.__init__(self, value) + + def __str__(self): + return f"{self.value}" def __getValue__(self): """ @@ -266,7 +270,7 @@ def mask(self): Because in Python all numbers are Int long or float Cache result in self._mask field """ - if not self.__dict__.has_key("_mask"): + if "_mask" not in self.__dict__: mask = 0xff for _ in range(1, self._typeSize): mask = mask << 8 | 0xff @@ -290,19 +294,25 @@ def __sizeof__(self): @return: typeSize pass in constructor """ return self._typeSize - - def __cmp__(self, other): - """ - @summary: Compare two simple type - Call inner value compare operator - @param other: SimpleType value or try to build same type as self - around value - @return: python value compare - """ + + def _other(self, other): if not isinstance(other, SimpleType): other = self.__class__(other) - return self.value.__cmp__(other.value) - + return other + + def __eq__(self, other): + return self.value.__eq__(self._other(other).value) + def __ne__(self, other): + return self.value.__ne__(self._other(other).value) + def __gt__(self, other): + return self.value.__gt__(self._other(other).value) + def __lt__(self, other): + return self.value.__lt__(self._other(other).value) + def __ge__(self, other): + return self.value.__ge__(self._other(other).value) + def __le__(self, other): + return self.value.__le__(self._other(other).value) + def __invert__(self): """ @summary: Implement not operator @@ -462,7 +472,7 @@ def __read__(self, s): #read is ok but read out of bound if not self._readLen is None and readLen > self._readLen.value: #roll back - s.pos -= sizeof(self.__dict__[name]) + s._pos(s._pos() - sizeof(self.__dict__[name])) #and notify if not optional if not self.__dict__[name]._optional: raise InvalidSize("Impossible to read type %s : read length is too small"%(self.__class__)) @@ -473,7 +483,7 @@ def __read__(self, s): for tmpName in self._typeName: if tmpName == name: break - s.pos -= sizeof(self.__dict__[tmpName]) + s._pos(s._pos() - sizeof(self.__dict__[tmpName])) raise e if not self._readLen is None and readLen < self._readLen.value: @@ -703,7 +713,7 @@ def __read__(self, s): @summary: special read for a special type @param s: Stream """ - self.value = struct.unpack(self._structFormat, '\x00' + s.read(self._typeSize))[0] + self.value = struct.unpack(self._structFormat, b'\x00' + s.read(self._typeSize))[0] class UInt24Le(SimpleType): """ @@ -734,14 +744,14 @@ def __read__(self, s): @summary: special read for a special type @param s: Stream """ - self.value = struct.unpack(self._structFormat, s.read(self._typeSize) + '\x00')[0] + self.value = struct.unpack(self._structFormat, s.read(self._typeSize) + b'\x00')[0] class String(Type, CallableValue): """ @summary: String type Leaf in Type tree """ - def __init__(self, value = "", readLen = None, conditional = lambda:True, optional = False, constant = False, unicode = False, until = None): + def __init__(self, value = b"", readLen = None, conditional = lambda:True, optional = False, constant = False, unicode = False, until = None): """ @param value: python string use for inner value @param readLen: length use to read in stream (SimpleType) if 0 read entire stream @@ -759,15 +769,24 @@ def __init__(self, value = "", readLen = None, conditional = lambda:True, option self._readLen = readLen self._unicode = unicode self._until = until - - def __cmp__(self, other): - """ - @summary: call raw compare value - @param other: other String parameter - @return: if two inner value are equals - """ - return cmp(self.value, other.value) - + # FIXME + if type(value) != bytes: + raise Exception(f"Invalid string value {type(value)} {value}") + + + def __eq__(self, other): + return self.value.__eq__(other.value) + def __ne__(self, other): + return self.value.__ne__(other.value) + def __gt__(self, other): + return self.value.__gt__(other.value) + def __lt__(self, other): + return self.value.__lt__(other.value) + def __ge__(self, other): + return self.value.__ge__(other.value) + def __le__(self, other): + return self.value.__le__(other.value) + def __hash__(self): """ @summary: hash function to treat simple type in hash collection @@ -780,7 +799,7 @@ def __str__(self): @summary: call when str function is call @return: inner python string """ - return self.value + return self.value.decode("ascii", "escape") def __write__(self, s): """ @@ -798,7 +817,9 @@ def __write__(self, s): s.write(encodeUnicode(self.value)) else: s.write(self.value) - + + # print(f"String write unicode={self._unicode} {self.value}") # FIXME + def __read__(self, s): """ @summary: Read readLen bytes as string @@ -808,7 +829,7 @@ def __read__(self, s): """ if self._readLen is None: if self._until is None: - self.value = s.getvalue()[s.pos:] + self.value = s.getvalue()[s._pos():] else: self.value = "" while self.value[-len(self._until):] != self._until and s.dataLen() != 0: @@ -818,6 +839,8 @@ def __read__(self, s): if self._unicode: self.value = decodeUnicode(self.value) + + # print(f"String read unicode={self._unicode} {self.value}") # FIXME def __sizeof__(self): """ @@ -836,7 +859,7 @@ def encodeUnicode(s): @param s: str python @return: unicode string """ - return "".join([c + "\x00" for c in s]) + "\x00\x00" + return b"".join([ bytes([(c if type(c)==int else ord(c))]) + b"\x00" for c in s]) + b"\x00\x00" def decodeUnicode(s): """ @@ -848,26 +871,40 @@ def decodeUnicode(s): r = "" while i < len(s) - 2: if i % 2 == 0: - r += s[i] + r += chr(s[i]) if type(s[i]) == int else s[i] i += 1 return r -class Stream(StringIO): +class Stream(BytesIO): """ @summary: Stream use to read all types """ + + def _pos(self, pos=None): + if pos is not None: + self.seek(pos) + return self.tell() + + def _len(self): + pos = self.tell() + self.seek(0, SEEK_END) + end = self.tell() + self.seek(pos) + return end + + def dataLen(self): """ @return: not yet read length """ - return self.len - self.pos + return self._len() - self._pos() def readLen(self): """ @summary: compute already read size @return: read size of stream """ - return self.pos + return self._pos() def readType(self, value): """ @@ -886,7 +923,7 @@ def readType(self, value): for tmpElement in value: if tmpElement == element: break - self.pos -= sizeof(tmpElement) + self._pos(self._pos() - sizeof(tmpElement)) raise e return @@ -902,7 +939,7 @@ def readNextType(self, t): @param t: Type element """ self.readType(t) - self.pos -= sizeof(t) + self._pos(self._pos() - sizeof(t)) def writeType(self, value): """ diff --git a/rdpy/protocol/rdp/lic.py b/rdpy/protocol/rdp/lic.py index f22f4d40..2f91e790 100644 --- a/rdpy/protocol/rdp/lic.py +++ b/rdpy/protocol/rdp/lic.py @@ -25,8 +25,8 @@ from rdpy.core.type import CompositeType, CallableValue, UInt8, UInt16Le, UInt32Le, String, sizeof, FactoryType, ArrayType, Stream from rdpy.core.error import InvalidExpectedDataException import rdpy.core.log as log -import sec -from t125 import gcc +from rdpy.protocol.rdp import sec +from rdpy.protocol.rdp.t125 import gcc from rdpy.security import rc4 from rdpy.security import rsa_wrapper as rsa @@ -127,10 +127,10 @@ def __init__(self): self.dwVersion = UInt32Le() self.cbCompanyName = UInt32Le(lambda:sizeof(self.pbCompanyName)) #may contain "Microsoft Corporation" from server microsoft - self.pbCompanyName = String("Microsoft Corporation", readLen = self.cbCompanyName, unicode = True) + self.pbCompanyName = String(b"Microsoft Corporation", readLen = self.cbCompanyName, unicode = True) self.cbProductId = UInt32Le(lambda:sizeof(self.pbProductId)) #may contain "A02" from microsoft license server - self.pbProductId = String("A02", readLen = self.cbProductId, unicode = True) + self.pbProductId = String(b"A02", readLen = self.cbProductId, unicode = True) class Scope(CompositeType): @@ -162,7 +162,7 @@ class ServerLicenseRequest(CompositeType): def __init__(self, readLen = None): CompositeType.__init__(self, readLen = readLen) - self.serverRandom = String("\x00" * 32, readLen = CallableValue(32)) + self.serverRandom = String(b"\x00" * 32, readLen = CallableValue(32)) self.productInfo = ProductInformation() self.keyExchangeList = LicenseBinaryBlob(BinaryBlobType.BB_KEY_EXCHG_ALG_BLOB) self.serverCertificate = LicenseBinaryBlob(BinaryBlobType.BB_CERTIFICATE_BLOB) @@ -183,7 +183,7 @@ def __init__(self, readLen = None): #pure microsoft client ;-) #http://msdn.microsoft.com/en-us/library/1040af38-c733-4fb3-acd1-8db8cc979eda#id10 self.platformId = UInt32Le(0x04000000 | 0x00010000) - self.clientRandom = String("\x00" * 32, readLen = CallableValue(32)) + self.clientRandom = String(b"\x00" * 32, readLen = CallableValue(32)) self.encryptedPreMasterSecret = LicenseBinaryBlob(BinaryBlobType.BB_RANDOM_BLOB) self.ClientUserName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_USER_NAME_BLOB) self.ClientMachineName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_MACHINE_NAME_BLOB) @@ -263,8 +263,8 @@ def __init__(self, transport): @param transport: layer use to send packet """ self._transport = transport - self._username = "" - self._hostname = "" + self._username = b"" + self._hostname = b"" def recv(self, s): """ @@ -321,9 +321,9 @@ def sendClientNewLicenseRequest(self, licenseRequest): #format message message = ClientNewLicenseRequest() message.clientRandom.value = clientRandom - message.encryptedPreMasterSecret.blobData.value = rsa.encrypt(preMasterSecret[::-1], serverCertificate.certData.getPublicKey())[::-1] + "\x00" * 8 - message.ClientMachineName.blobData.value = self._hostname + "\x00" - message.ClientUserName.blobData.value = self._username + "\x00" + message.encryptedPreMasterSecret.blobData.value = rsa.encrypt(preMasterSecret[::-1], serverCertificate.certData.getPublicKey())[::-1] + b"\x00" * 8 + message.ClientMachineName.blobData.value = self._hostname + b"\x00" + message.ClientUserName.blobData.value = self._username + b"\x00" self._transport.sendFlagged(sec.SecurityFlag.SEC_LICENSE_PKT, LicPacket(message)) def sendClientChallengeResponse(self, platformChallenge): @@ -340,7 +340,7 @@ def sendClientChallengeResponse(self, platformChallenge): #generate hwid s = Stream() - s.writeType((UInt32Le(2), String(self._hostname + self._username + "\x00" * 16))) + s.writeType((UInt32Le(2), String(self._hostname + self._username + b"\x00" * 16))) hwid = s.getvalue()[:20] message = ClientPLatformChallengeResponse() diff --git a/rdpy/protocol/rdp/nla/ntlm.py b/rdpy/protocol/rdp/nla/ntlm.py index 3d541f64..14921096 100644 --- a/rdpy/protocol/rdp/nla/ntlm.py +++ b/rdpy/protocol/rdp/nla/ntlm.py @@ -23,7 +23,7 @@ """ import hashlib, hmac, struct, datetime -import sspi +from rdpy.protocol.rdp.nla import sspi import rdpy.security.pyDes as pyDes import rdpy.security.rc4 as rc4 from rdpy.security.rsa_wrapper import random @@ -145,7 +145,7 @@ class NegotiateMessage(CompositeType): """ def __init__(self): CompositeType.__init__(self) - self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True) + self.Signature = String(b"NTLMSSP\x00", readLen = CallableValue(8), constant = True) self.MessageType = UInt32Le(0x00000001, constant = True) self.NegotiateFlags = UInt32Le() @@ -169,7 +169,7 @@ class ChallengeMessage(CompositeType): """ def __init__(self): CompositeType.__init__(self) - self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True) + self.Signature = String(b"NTLMSSP\x00", readLen = CallableValue(8), constant = True) self.MessageType = UInt32Le(0x00000002, constant = True) self.TargetNameLen = UInt16Le() @@ -179,7 +179,7 @@ def __init__(self): self.NegotiateFlags = UInt32Le() self.ServerChallenge = String(readLen = CallableValue(8)) - self.Reserved = String("\x00" * 8, readLen = CallableValue(8)) + self.Reserved = String(b"\x00" * 8, readLen = CallableValue(8)) self.TargetInfoLen = UInt16Le() self.TargetInfoMaxLen = UInt16Le(lambda:self.TargetInfoLen.value) @@ -216,7 +216,7 @@ class AuthenticateMessage(CompositeType): """ def __init__(self): CompositeType.__init__(self) - self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True) + self.Signature = String(b"NTLMSSP\x00", readLen = CallableValue(8), constant = True) self.MessageType = UInt32Le(0x00000003, constant = True) self.LmChallengeResponseLen = UInt16Le() @@ -246,7 +246,7 @@ def __init__(self): self.NegotiateFlags = UInt32Le() self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION)) - self.MIC = String("\x00" * 16, readLen = CallableValue(16)) + self.MIC = String(b"\x00" * 16, readLen = CallableValue(16)) self.Payload = String() def getUserName(self): @@ -345,13 +345,14 @@ def DESL(key, data): @param key: {str} Des key @param data: {str} encrypted data """ - return DES(key[0:7], data) + DES(key[7:14], data) + DES(key[14:16] + "\x00" * 5, data) + return DES(key[0:7], data) + DES(key[7:14], data) + DES(key[14:16] + b"\x00" * 5, data) def UNICODE(s): """ @param s: source @return: {str} encoded in unicode """ + s = s.decode("utf-8") if type(s) == bytes else s return s.encode('utf-16le') def MD4(s): @@ -376,7 +377,7 @@ def Z(m): @param m: {int} size of string @return: \x00 * m """ - return "\x00" * m + return b"\x00" * m def RC4K(key, plaintext): """ @@ -399,15 +400,15 @@ def KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge): def SEALKEY(ExportedSessionKey, client): if client: - return MD5(ExportedSessionKey + "session key to client-to-server sealing key magic constant\0") + return MD5(ExportedSessionKey + b"session key to client-to-server sealing key magic constant\0") else: - return MD5(ExportedSessionKey + "session key to server-to-client sealing key magic constant\0") + return MD5(ExportedSessionKey + b"session key to server-to-client sealing key magic constant\0") def SIGNKEY(ExportedSessionKey, client): if client: - return MD5(ExportedSessionKey + "session key to client-to-server signing key magic constant\0") + return MD5(ExportedSessionKey + b"session key to client-to-server signing key magic constant\0") else: - return MD5(ExportedSessionKey + "session key to server-to-client signing key magic constant\0") + return MD5(ExportedSessionKey + b"session key to server-to-client signing key magic constant\0") def HMAC_MD5(key, data): """ @@ -443,8 +444,8 @@ def ComputeResponsev2(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChall @param NegFlg: {int} Negotiation flags come from challenge message @see: https://msdn.microsoft.com/en-us/library/cc236700.aspx """ - Responserversion = "\x01" - HiResponserversion = "\x01" + Responserversion = b"\x01" + HiResponserversion = b"\x01" temp = Responserversion + HiResponserversion + Z(6) + Time + ClientChallenge + Z(4) + ServerName NTProofStr = HMAC_MD5(ResponseKeyNT, ServerChallenge + temp) @@ -538,7 +539,7 @@ def getAuthenticateMessage(self, s): computeMIC = False ServerName = self._challengeMessage.getTargetInfo() infos = self._challengeMessage.getTargetInfoAsAvPairArray() - if infos.has_key(AvId.MsvAvTimestamp): + if AvId.MsvAvTimestamp in infos: Timestamp = infos[AvId.MsvAvTimestamp] computeMIC = True else: diff --git a/rdpy/protocol/rdp/pdu/caps.py b/rdpy/protocol/rdp/pdu/caps.py index 19443577..ba6de9d9 100644 --- a/rdpy/protocol/rdp/pdu/caps.py +++ b/rdpy/protocol/rdp/pdu/caps.py @@ -308,7 +308,7 @@ class OrderCapability(CompositeType): def __init__(self, readLen = None): CompositeType.__init__(self, readLen = readLen) - self.terminalDescriptor = String("\x00" * 16, readLen = CallableValue(16)) + self.terminalDescriptor = String(b"\x00" * 16, readLen = CallableValue(16)) self.pad4octetsA = UInt32Le(0) self.desktopSaveXGranularity = UInt16Le(1) self.desktopSaveYGranularity = UInt16Le(20) @@ -388,7 +388,7 @@ def __init__(self, readLen = None): #same value as gcc.ClientCoreSettings.keyboardFnKeys self.keyboardFunctionKey = UInt32Le() #same value as gcc.ClientCoreSettingrrs.imeFileName - self.imeFileName = String("\x00" * 64, readLen = CallableValue(64)) + self.imeFileName = String(b"\x00" * 64, readLen = CallableValue(64)) class BrushCapability(CompositeType): """ diff --git a/rdpy/protocol/rdp/pdu/data.py b/rdpy/protocol/rdp/pdu/data.py index 509cc6cd..8b7403ec 100644 --- a/rdpy/protocol/rdp/pdu/data.py +++ b/rdpy/protocol/rdp/pdu/data.py @@ -25,7 +25,7 @@ from rdpy.core.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType from rdpy.core.error import InvalidExpectedDataException import rdpy.core.log as log -import caps, order +from rdpy.protocol.rdp.pdu import caps, order class PDUType(object): """ @@ -503,7 +503,7 @@ def __init__(self, readLen = None): self.shareId = UInt32Le() self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) self.lengthCombinedCapabilities = UInt16Le(lambda:(sizeof(self.numberCapabilities) + sizeof(self.pad2Octets) + sizeof(self.capabilitySets))) - self.sourceDescriptor = String("rdpy", readLen = self.lengthSourceDescriptor) + self.sourceDescriptor = String(b"rdpy", readLen = self.lengthSourceDescriptor) self.numberCapabilities = UInt16Le(lambda:len(self.capabilitySets._array)) self.pad2Octets = UInt16Le() self.capabilitySets = ArrayType(caps.Capability, readLen = self.numberCapabilities) @@ -523,7 +523,7 @@ def __init__(self, readLen = None): self.originatorId = UInt16Le(0x03EA, constant = True) self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) self.lengthCombinedCapabilities = UInt16Le(lambda:(sizeof(self.numberCapabilities) + sizeof(self.pad2Octets) + sizeof(self.capabilitySets))) - self.sourceDescriptor = String("rdpy", readLen = self.lengthSourceDescriptor) + self.sourceDescriptor = String(b"rdpy", readLen = self.lengthSourceDescriptor) self.numberCapabilities = UInt16Le(lambda:len(self.capabilitySets._array)) self.pad2Octets = UInt16Le() self.capabilitySets = ArrayType(caps.Capability, readLen = self.numberCapabilities) @@ -542,7 +542,7 @@ def __init__(self, readLen = None): CompositeType.__init__(self, optional = True, readLen = readLen) self.shareId = UInt32Le() self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) - self.sourceDescriptor = String("rdpy", readLen = self.lengthSourceDescriptor) + self.sourceDescriptor = String(b"rdpy", readLen = self.lengthSourceDescriptor) class DataPDU(CompositeType): """ @@ -880,7 +880,7 @@ class BitmapData(CompositeType): """ @summary: Bitmap data here the screen capture """ - def __init__(self, destLeft = 0, destTop = 0, destRight = 0, destBottom = 0, width = 0, height = 0, bitsPerPixel = 0, bitmapDataStream = ""): + def __init__(self, destLeft = 0, destTop = 0, destRight = 0, destBottom = 0, width = 0, height = 0, bitsPerPixel = 0, bitmapDataStream = b""): """ @param destLeft: destination left coordinate @param destTop: destination top coordinate diff --git a/rdpy/protocol/rdp/pdu/layer.py b/rdpy/protocol/rdp/pdu/layer.py index aebcd152..04f03e2e 100644 --- a/rdpy/protocol/rdp/pdu/layer.py +++ b/rdpy/protocol/rdp/pdu/layer.py @@ -28,7 +28,7 @@ from rdpy.core.type import ArrayType import rdpy.core.log as log import rdpy.protocol.rdp.tpkt as tpkt -import data, caps +from rdpy.protocol.rdp.pdu import data, caps class PDUClientListener(object): """ @@ -301,7 +301,7 @@ def readDataPDU(self, dataPDU): if dataPDU.pduData.errorInfo.value == 0: return errorMessage = "Unknown code %s"%hex(dataPDU.pduData.errorInfo.value) - if data.ErrorInfo._MESSAGES_.has_key(dataPDU.pduData.errorInfo): + if dataPDU.pduData.errorInfo in data.ErrorInfo._MESSAGES_: errorMessage = data.ErrorInfo._MESSAGES_[dataPDU.pduData.errorInfo] log.error("INFO PDU : %s"%errorMessage) @@ -357,7 +357,7 @@ def sendConfirmActivePDU(self): #make active PDU packet confirmActivePDU = data.ConfirmActivePDU() confirmActivePDU.shareId.value = self._shareId - confirmActivePDU.capabilitySets._array = self._clientCapabilities.values() + confirmActivePDU.capabilitySets._array = list(self._clientCapabilities.values()) self.sendPDU(confirmActivePDU) def sendClientFinalizeSynchronizePDU(self): @@ -520,7 +520,7 @@ def readDataPDU(self, dataPDU): """ if dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SET_ERROR_INFO_PDU: errorMessage = "Unknown code %s"%hex(dataPDU.pduData.errorInfo.value) - if data.ErrorInfo._MESSAGES_.has_key(dataPDU.pduData.errorInfo): + if dataPDU.pduData.errorInfo in data.ErrorInfo._MESSAGES_: errorMessage = data.ErrorInfo._MESSAGES_[dataPDU.pduData.errorInfo] log.error("INFO PDU : %s"%errorMessage) @@ -554,7 +554,7 @@ def sendDemandActivePDU(self): demandActivePDU = data.DemandActivePDU() demandActivePDU.shareId.value = self._shareId - demandActivePDU.capabilitySets._array = self._serverCapabilities.values() + demandActivePDU.capabilitySets._array = list(self._serverCapabilities.values()) self.sendPDU(demandActivePDU) def sendServerFinalizeSynchronizePDU(self): diff --git a/rdpy/protocol/rdp/rdp.py b/rdpy/protocol/rdp/rdp.py index 3b486086..2419a2c6 100644 --- a/rdpy/protocol/rdp/rdp.py +++ b/rdpy/protocol/rdp/rdp.py @@ -23,13 +23,12 @@ from rdpy.core import layer from rdpy.core.error import CallPureVirtualFuntion, InvalidValue -import pdu.layer -import pdu.data -import pdu.caps +from rdpy.protocol.rdp.pdu import layer as pdu_layer, data, caps +from rdpy.protocol.rdp import pdu import rdpy.core.log as log -import tpkt, x224, sec -from t125 import mcs, gcc -from nla import cssp, ntlm +from rdpy.protocol.rdp import tpkt, x224, sec +from rdpy.protocol.rdp.t125 import mcs, gcc +from rdpy.protocol.rdp.nla import cssp, ntlm class SecurityLevel(object): """ @@ -39,7 +38,11 @@ class SecurityLevel(object): RDP_LEVEL_SSL = 1 RDP_LEVEL_NLA = 2 -class RDPClientController(pdu.layer.PDUClientListener): +def b(value): + return value.encode('ascii') if type(value) == str else value + + +class RDPClientController(pdu_layer.PDUClientListener): """ Manage RDP stack as client """ @@ -47,7 +50,7 @@ def __init__(self): #list of observer self._clientObserver = [] #PDU layer - self._pduLayer = pdu.layer.Client(self) + self._pduLayer = pdu_layer.Client(self) #secure layer self._secLayer = sec.Client(self._pduLayer) #multi channel service @@ -103,6 +106,7 @@ def setUsername(self, username): @param username: {string} username of session """ #username in PDU info packet + username = b(username) self._secLayer._info.userName.value = username self._secLayer._licenceManager._username = username @@ -111,6 +115,7 @@ def setPassword(self, password): @summary: Set password for session @param password: {string} password of session """ + password = b(password) self.setAutologon() self._secLayer._info.password.value = password @@ -119,6 +124,7 @@ def setDomain(self, domain): @summary: Set the windows domain of session @param domain: {string} domain of session """ + domain = b(domain) self._secLayer._info.domain.value = domain def setAutologon(self): @@ -148,7 +154,8 @@ def setHostname(self, hostname): """ @summary: set hostname of machine """ - self._mcsLayer._clientSettings.CS_CORE.clientName.value = hostname[:15] + "\x00" * (15 - len(hostname)) + hostname = b(hostname) + self._mcsLayer._clientSettings.CS_CORE.clientName.value = hostname[:15] + b"\x00" * (15 - len(hostname)) self._secLayer._licenceManager._hostname = hostname def setSecurityLevel(self, level): @@ -365,7 +372,7 @@ def close(self): """ self._pduLayer.close() -class RDPServerController(pdu.layer.PDUServerListener): +class RDPServerController(pdu_layer.PDUServerListener): """ @summary: Controller use in server side mode """ @@ -379,7 +386,7 @@ def __init__(self, colorDepth, privateKeyFileName = None, certificateFileName = #list of observer self._serverObserver = [] #build RDP protocol stack - self._pduLayer = pdu.layer.Server(self) + self._pduLayer = pdu_layer.Server(self) #secure layer self._secLayer = sec.Server(self._pduLayer) #multi channel service diff --git a/rdpy/protocol/rdp/sec.py b/rdpy/protocol/rdp/sec.py index 7a49b5a2..e2f5da86 100644 --- a/rdpy/protocol/rdp/sec.py +++ b/rdpy/protocol/rdp/sec.py @@ -21,10 +21,10 @@ RDP Standard security layer """ -import sha, md5 -import lic, tpkt -from t125 import gcc, mcs -from rdpy.core.type import CompositeType, CallableValue, Stream, UInt32Le, UInt16Le, String, sizeof, UInt8 +from hashlib import sha1 as sha, md5 +from rdpy.protocol.rdp import lic, tpkt +from rdpy.protocol.rdp.t125 import gcc, mcs +from rdpy.core.type import CompositeType, CallableValue, Stream, UInt32Le, UInt16Le, String, sizeof from rdpy.core.layer import LayerAutomata, IStreamSender from rdpy.core.error import InvalidExpectedDataException from rdpy.core import log @@ -56,6 +56,7 @@ class SecurityFlag(object): class InfoFlag(object): """ Client capabilities informations + @see: https://msdn.microsoft.com/en-us/library/cc240475.aspx """ INFO_MOUSE = 0x00000001 INFO_DISABLECTRLALTDEL = 0x00000002 @@ -80,6 +81,7 @@ class InfoFlag(object): class PerfFlag(object): """ Network performances flag + @see: https://msdn.microsoft.com/en-us/library/cc240476.aspx """ PERF_DISABLE_WALLPAPER = 0x00000001 PERF_DISABLE_FULLWINDOWDRAG = 0x00000002 @@ -107,8 +109,8 @@ def saltedHash(inputData, salt, salt1, salt2): @param salt2: another another salt (ex: server random) @return : MD5(Salt + SHA1(Input + Salt + Salt1 + Salt2)) """ - sha1Digest = sha.new() - md5Digest = md5.new() + sha1Digest = sha() + md5Digest = md5() sha1Digest.update(inputData) sha1Digest.update(salt[:48]) @@ -129,7 +131,7 @@ def finalHash(key, random1, random2): @param random2: in 32 @return MD5(in0[:16] + in1[:32] + in2[:32]) """ - md5Digest = md5.new() + md5Digest = md5() md5Digest.update(key) md5Digest.update(random1) md5Digest.update(random2) @@ -143,7 +145,7 @@ def masterSecret(secret, random1, random2): @param serverRandom : {str} server random @see: http://msdn.microsoft.com/en-us/library/cc241992.aspx """ - return saltedHash("A", secret, random1, random2) + saltedHash("BB", secret, random1, random2) + saltedHash("CCC", secret, random1, random2) + return saltedHash(b"A", secret, random1, random2) + saltedHash(b"BB", secret, random1, random2) + saltedHash(b"CCC", secret, random1, random2) def sessionKeyBlob(secret, random1, random2): """ @@ -152,7 +154,7 @@ def sessionKeyBlob(secret, random1, random2): @param clientRandom : client random @param serverRandom : server random """ - return saltedHash("X", secret, random1, random2) + saltedHash("YY", secret, random1, random2) + saltedHash("ZZZ", secret, random1, random2) + return saltedHash(b"X", secret, random1, random2) + saltedHash(b"YY", secret, random1, random2) + saltedHash(b"ZZZ", secret, random1, random2) def macData(macSaltKey, data): """ @@ -161,22 +163,22 @@ def macData(macSaltKey, data): @param data: {str} data to sign @return: {str} signature """ - sha1Digest = sha.new() - md5Digest = md5.new() + sha1Digest = sha() + md5Digest = md5() #encode length dataLength = Stream() dataLength.writeType(UInt32Le(len(data))) sha1Digest.update(macSaltKey) - sha1Digest.update("\x36" * 40) + sha1Digest.update(b"\x36" * 40) sha1Digest.update(dataLength.getvalue()) sha1Digest.update(data) sha1Sig = sha1Digest.digest() md5Digest.update(macSaltKey) - md5Digest.update("\x5c" * 48) + md5Digest.update(b"\x5c" * 48) md5Digest.update(sha1Sig) return md5Digest.digest() @@ -189,8 +191,8 @@ def macSaltedData(macSaltKey, data, encryptionCount): @param encryptionCount: nb encrypted packet @return: {str} signature """ - sha1Digest = sha.new() - md5Digest = md5.new() + sha1Digest = sha() + md5Digest = md5() #encode length dataLengthS = Stream() @@ -200,7 +202,7 @@ def macSaltedData(macSaltKey, data, encryptionCount): encryptionCountS.writeType(UInt32Le(encryptionCount)) sha1Digest.update(macSaltKey) - sha1Digest.update("\x36" * 40) + sha1Digest.update(b"\x36" * 40) sha1Digest.update(dataLengthS.getvalue()) sha1Digest.update(data) sha1Digest.update(encryptionCountS.getvalue()) @@ -208,7 +210,7 @@ def macSaltedData(macSaltKey, data, encryptionCount): sha1Sig = sha1Digest.digest() md5Digest.update(macSaltKey) - md5Digest.update("\x5c" * 48) + md5Digest.update(b"\x5c" * 48) md5Digest.update(sha1Sig) return md5Digest.digest() @@ -220,17 +222,17 @@ def tempKey(initialKey, currentKey): @param currentKey: {str} key actually used @return: {str} temp key """ - sha1Digest = sha.new() - md5Digest = md5.new() + sha1Digest = sha() + md5Digest = md5() sha1Digest.update(initialKey) - sha1Digest.update("\x36" * 40) + sha1Digest.update(b"\x36" * 40) sha1Digest.update(currentKey) sha1Sig = sha1Digest.digest() md5Digest.update(initialKey) - md5Digest.update("\x5c" * 48) + md5Digest.update(b"\x5c" * 48) md5Digest.update(sha1Sig) return md5Digest.digest() @@ -242,7 +244,7 @@ def gen40bits(data): @return: {str} 40 bits data @see: http://msdn.microsoft.com/en-us/library/cc240785.aspx """ - return "\xd1\x26\x9e" + data[:8][-5:] + return b"\xd1\x26\x9e" + data[:8][-5:] def gen56bits(data): """ @@ -251,7 +253,7 @@ def gen56bits(data): @return: {str} 56 bits data @see: http://msdn.microsoft.com/en-us/library/cc240785.aspx """ - return "\xd1" + data[:8][-7:] + return b"\xd1" + data[:8][-7:] def generateKeys(clientRandom, serverRandom, method): """ @@ -310,7 +312,7 @@ def __init__(self): CompositeType.__init__(self) self.length = UInt32Le(lambda:(sizeof(self) - 4)) self.encryptedClientRandom = String(readLen = CallableValue(lambda:(self.length.value - 8))) - self.padding = String("\x00" * 8, readLen = CallableValue(8)) + self.padding = String(b"\x00" * 8, readLen = CallableValue(8)) class RDPInfo(CompositeType): """ @@ -351,7 +353,7 @@ def __init__(self, conditional): self.cbClientDir = UInt16Le(lambda:sizeof(self.clientDir)) self.clientDir = String(readLen = self.cbClientDir, unicode = True) #TODO make tiomezone - self.clientTimeZone = String("\x00" * 172) + self.clientTimeZone = String(b"\x00" * 172) self.clientSessionId = UInt32Le() self.performanceFlags = UInt32Le() diff --git a/rdpy/protocol/rdp/t125/gcc.py b/rdpy/protocol/rdp/t125/gcc.py index 1fa07161..f70a5241 100644 --- a/rdpy/protocol/rdp/t125/gcc.py +++ b/rdpy/protocol/rdp/t125/gcc.py @@ -22,9 +22,9 @@ http://msdn.microsoft.com/en-us/library/cc240508.aspx """ -import md5 +from hashlib import md5 from rdpy.core.type import UInt8, UInt16Le, UInt32Le, CompositeType, CallableValue, String, Stream, sizeof, FactoryType, ArrayType -import per, mcs +from rdpy.protocol.rdp.t125 import per, mcs from rdpy.core.error import InvalidExpectedDataException from rdpy.core import log from rdpy.security import x509 @@ -252,18 +252,18 @@ def __init__(self, readLen = None): self.sasSequence = UInt16Le(Sequence.RNS_UD_SAS_DEL) self.kbdLayout = UInt32Le(KeyboardLayout.US) self.clientBuild = UInt32Le(3790) - self.clientName = String("rdpy" + "\x00"*11, readLen = CallableValue(32), unicode = True) + self.clientName = String(b"rdpy" + b"\x00"*11, readLen = CallableValue(32), unicode = True) self.keyboardType = UInt32Le(KeyboardType.IBM_101_102_KEYS) self.keyboardSubType = UInt32Le(0) self.keyboardFnKeys = UInt32Le(12) - self.imeFileName = String("\x00"*64, readLen = CallableValue(64), optional = True) + self.imeFileName = String(b"\x00"*64, readLen = CallableValue(64), optional = True) self.postBeta2ColorDepth = UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP, optional = True) self.clientProductId = UInt16Le(1, optional = True) self.serialNumber = UInt32Le(0, optional = True) self.highColorDepth = UInt16Le(HighColor.HIGH_COLOR_24BPP, optional = True) self.supportedColorDepths = UInt16Le(Support.RNS_UD_15BPP_SUPPORT | Support.RNS_UD_16BPP_SUPPORT | Support.RNS_UD_24BPP_SUPPORT | Support.RNS_UD_32BPP_SUPPORT, optional = True) self.earlyCapabilityFlags = UInt16Le(CapabilityFlags.RNS_UD_CS_SUPPORT_ERRINFO_PDU, optional = True) - self.clientDigProductId = String("\x00"*64, readLen = CallableValue(64), optional = True) + self.clientDigProductId = String(b"\x00"*64, readLen = CallableValue(64), optional = True) self.connectionType = UInt8(optional = True) self.pad1octet = UInt8(optional = True) self.serverSelectedProtocol = UInt32Le(optional = True) @@ -342,9 +342,9 @@ class ProprietaryServerCertificate(CompositeType): _TYPE_ = CertificateType.CERT_CHAIN_VERSION_1 #http://msdn.microsoft.com/en-us/library/cc240776.aspx - _TERMINAL_SERVICES_MODULUS_ = "\x3d\x3a\x5e\xbd\x72\x43\x3e\xc9\x4d\xbb\xc1\x1e\x4a\xba\x5f\xcb\x3e\x88\x20\x87\xef\xf5\xc1\xe2\xd7\xb7\x6b\x9a\xf2\x52\x45\x95\xce\x63\x65\x6b\x58\x3a\xfe\xef\x7c\xe7\xbf\xfe\x3d\xf6\x5c\x7d\x6c\x5e\x06\x09\x1a\xf5\x61\xbb\x20\x93\x09\x5f\x05\x6d\xea\x87" - _TERMINAL_SERVICES_PRIVATE_EXPONENT_ = "\x87\xa7\x19\x32\xda\x11\x87\x55\x58\x00\x16\x16\x25\x65\x68\xf8\x24\x3e\xe6\xfa\xe9\x67\x49\x94\xcf\x92\xcc\x33\x99\xe8\x08\x60\x17\x9a\x12\x9f\x24\xdd\xb1\x24\x99\xc7\x3a\xb8\x0a\x7b\x0d\xdd\x35\x07\x79\x17\x0b\x51\x9b\xb3\xc7\x10\x01\x13\xe7\x3f\xf3\x5f" - _TERMINAL_SERVICES_PUBLIC_EXPONENT_ = "\x5b\x7b\x88\xc0" + _TERMINAL_SERVICES_MODULUS_ = b"\x3d\x3a\x5e\xbd\x72\x43\x3e\xc9\x4d\xbb\xc1\x1e\x4a\xba\x5f\xcb\x3e\x88\x20\x87\xef\xf5\xc1\xe2\xd7\xb7\x6b\x9a\xf2\x52\x45\x95\xce\x63\x65\x6b\x58\x3a\xfe\xef\x7c\xe7\xbf\xfe\x3d\xf6\x5c\x7d\x6c\x5e\x06\x09\x1a\xf5\x61\xbb\x20\x93\x09\x5f\x05\x6d\xea\x87" + _TERMINAL_SERVICES_PRIVATE_EXPONENT_ = b"\x87\xa7\x19\x32\xda\x11\x87\x55\x58\x00\x16\x16\x25\x65\x68\xf8\x24\x3e\xe6\xfa\xe9\x67\x49\x94\xcf\x92\xcc\x33\x99\xe8\x08\x60\x17\x9a\x12\x9f\x24\xdd\xb1\x24\x99\xc7\x3a\xb8\x0a\x7b\x0d\xdd\x35\x07\x79\x17\x0b\x51\x9b\xb3\xc7\x10\x01\x13\xe7\x3f\xf3\x5f" + _TERMINAL_SERVICES_PUBLIC_EXPONENT_ = b"\x5b\x7b\x88\xc0" def __init__(self): CompositeType.__init__(self) @@ -378,10 +378,10 @@ def computeSignatureHash(self): s.writeType(self.wPublicKeyBlobLen) s.writeType(self.PublicKeyBlob) - md5Digest = md5.new() + md5Digest = md5() md5Digest.update(s.getvalue()) - return md5Digest.digest() + "\x00" + "\xff" * 45 + "\x01" + return md5Digest.digest() + b"\x00" + b"\xff" * 45 + b"\x01" def sign(self): """ @@ -445,10 +445,10 @@ def __init__(self, readLen): self.magic = UInt32Le(0x31415352, constant = True) self.keylen = UInt32Le(lambda:(sizeof(self.modulus) + sizeof(self.padding))) self.bitlen = UInt32Le(lambda:((self.keylen.value - 8) * 8)) - self.datalen = UInt32Le(lambda:((self.bitlen.value / 8) - 1)) + self.datalen = UInt32Le(lambda:((self.bitlen.value // 8) - 1)) self.pubExp = UInt32Le() self.modulus = String(readLen = CallableValue(lambda:(self.keylen.value - 8))) - self.padding = String("\x00" * 8, readLen = CallableValue(8)) + self.padding = String(b"\x00" * 8, readLen = CallableValue(8)) class ChannelDef(CompositeType): """ @@ -458,7 +458,7 @@ class ChannelDef(CompositeType): def __init__(self, name = "", options = 0): CompositeType.__init__(self) #name of channel - self.name = String(name[0:8] + "\x00" * (8 - len(name)), readLen = CallableValue(8)) + self.name = String(name[0:8] + b"\x00" * (8 - len(name)), readLen = CallableValue(8)) #unknown self.options = UInt32Le() diff --git a/rdpy/protocol/rdp/t125/mcs.py b/rdpy/protocol/rdp/t125/mcs.py index 78c604ef..254cf599 100644 --- a/rdpy/protocol/rdp/t125/mcs.py +++ b/rdpy/protocol/rdp/t125/mcs.py @@ -27,10 +27,10 @@ from rdpy.core.layer import LayerAutomata, IStreamSender, Layer from rdpy.core.type import sizeof, Stream, UInt8, UInt16Le, String from rdpy.core.error import InvalidExpectedDataException, InvalidValue, InvalidSize, CallPureVirtualFuntion -from ber import writeLength +from rdpy.protocol.rdp.t125.ber import writeLength import rdpy.core.log as log -import ber, gcc, per +from rdpy.protocol.rdp.t125 import ber, gcc, per import rdpy.security.rsa_wrapper as rsa class Message(object): @@ -182,7 +182,7 @@ def close(self): @summary: Send disconnect provider ultimatum """ self._transport.send((UInt8(self.writeMCSPDUHeader(DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM, 1)), - per.writeEnumerates(0x80), String("\x00" * 6))) + per.writeEnumerates(0x80), String(b"\x00" * 6))) self._transport.close() def allChannelConnected(self): @@ -194,7 +194,7 @@ def allChannelConnected(self): #connection is done self.setNextState(self.recvData) #try connection on all requested channel - for (channelId, layer) in self._channels.iteritems(): + for (channelId, layer) in self._channels.items(): #use proxy for each channel MCSLayer.MCSProxySender(layer, self, channelId).connect() @@ -236,7 +236,7 @@ def recvData(self, data): per.readLength(data) #channel id doesn't match a requested layer - if not self._channels.has_key(channelId): + if channelId not in self._channels: log.error("receive data for an unconnected layer") return @@ -437,7 +437,7 @@ def sendConnectInitial(self): ccReqStream = Stream() ccReqStream.writeType(ccReq) - tmp = (ber.writeOctetstring("\x01"), ber.writeOctetstring("\x01"), ber.writeBoolean(True), + tmp = (ber.writeOctetstring(b"\x01"), ber.writeOctetstring(b"\x01"), ber.writeBoolean(True), self.writeDomainParams(34, 2, 0, 0xffff), self.writeDomainParams(1, 1, 1, 0x420), self.writeDomainParams(0xffff, 0xfc17, 0xffff, 0xffff), diff --git a/rdpy/protocol/rdp/t125/per.py b/rdpy/protocol/rdp/t125/per.py index 6af23885..db8fc044 100644 --- a/rdpy/protocol/rdp/t125/per.py +++ b/rdpy/protocol/rdp/t125/per.py @@ -220,7 +220,7 @@ def readNumericString(s, minValue): @param minValue: offset """ length = readLength(s) - length = (length + minValue + 1) / 2 + length = (length + minValue + 1) // 2 s.read(length) def writeNumericString(nStr, minValue): @@ -264,7 +264,7 @@ def writePadding(length): @param length: length of padding @return: String with \x00 * length """ - return String("\x00"*length) + return String(b"\x00"*length) def readOctetStream(s, octetStream, minValue = 0): """ @@ -276,7 +276,7 @@ def readOctetStream(s, octetStream, minValue = 0): """ size = readLength(s) + minValue if size != len(octetStream): - raise InvalidValue("incompatible size %d != %d"(len(octetStream), size)) + raise InvalidValue("incompatible size %d != %d"%(len(octetStream), size)) for i in range(0, size): c = UInt8() s.readType(c) @@ -300,6 +300,6 @@ def writeOctetStream(oStr, minValue = 0): result = [] for i in range(0, length): - result.append(UInt8(ord(oStr[i]))) + result.append(UInt8(oStr[i] if type(oStr[i])==int else ord(oStr[i]))) return (writeLength(mlength), tuple(result)) \ No newline at end of file diff --git a/rdpy/protocol/rdp/x224.py b/rdpy/protocol/rdp/x224.py index bd900ce5..091f236e 100644 --- a/rdpy/protocol/rdp/x224.py +++ b/rdpy/protocol/rdp/x224.py @@ -79,7 +79,7 @@ def __init__(self): self.len = UInt8(lambda:sizeof(self) - 1) self.code = UInt8(MessageType.X224_TPDU_CONNECTION_REQUEST, constant = True) self.padding = (UInt16Be(), UInt16Be(), UInt8()) - self.cookie = String(until = "\x0d\x0a", conditional = lambda:(self.len._is_readed and self.len.value > 14)) + self.cookie = String(until = b"\x0d\x0a", conditional = lambda:(self.len._is_readed and self.len.value > 14)) #read if there is enough data self.protocolNeg = Negotiation(optional = True) diff --git a/rdpy/protocol/rfb/rfb.py b/rdpy/protocol/rfb/rfb.py index b43cfa01..94eed5df 100644 --- a/rdpy/protocol/rfb/rfb.py +++ b/rdpy/protocol/rfb/rfb.py @@ -35,10 +35,10 @@ class ProtocolVersion(object): """ @summary: Different protocol version """ - UNKNOWN = "" - RFB003003 = "RFB 003.003\n" - RFB003007 = "RFB 003.007\n" - RFB003008 = "RFB 003.008\n" + UNKNOWN = b"" + RFB003003 = b"RFB 003.003\n" + RFB003007 = b"RFB 003.007\n" + RFB003008 = b"RFB 003.008\n" class SecurityType(object): """ @@ -225,14 +225,14 @@ def expectedBody(self, data): are received """ bodyLen = None - if data.len == 1: + if data._len() == 1: bodyLen = UInt8() - elif data.len == 2: + elif data._len() == 2: bodyLen = UInt16Be() - elif data.len == 4: + elif data._len() == 4: bodyLen = UInt32Be() else: - log.error("invalid header length") + log.error(f"invalid header length {data._len()}") return data.readType(bodyLen) self.expect(bodyLen.value, self._callbackBody) @@ -361,7 +361,7 @@ def recvServerName(self, data): @param data: Stream that contains well formed packet """ data.readType(self._serverName) - log.info("Server name %s"%str(self._serverName)) + log.info(f"Server name {self._serverName}") #end of handshake #send pixel format self.sendPixelFormat(self._pixelFormat) @@ -408,7 +408,7 @@ def recvRectHeader(self, data): """ data.readType(self._currentRect) if self._currentRect.encoding.value == Encoding.RAW: - self.expect(self._currentRect.width.value * self._currentRect.height.value * (self._pixelFormat.BitsPerPixel.value / 8), self.recvRectBody) + self.expect(self._currentRect.width.value * self._currentRect.height.value * (self._pixelFormat.BitsPerPixel.value // 8), self.recvRectBody) def recvRectBody(self, data): """ diff --git a/rdpy/security/pyDes.py b/rdpy/security/pyDes.py index 0f307e78..6cde34b1 100644 --- a/rdpy/security/pyDes.py +++ b/rdpy/security/pyDes.py @@ -66,13 +66,13 @@ from pyDes import * data = "Please encrypt my data" -k = des("DESCRYPT", CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) +k = des("DESCRYPT", CBC, b"\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) # For Python3, you'll need to use bytes, i.e.: # data = b"Please encrypt my data" # k = des(b"DESCRYPT", CBC, b"\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) d = k.encrypt(data) -print "Encrypted: %r" % d -print "Decrypted: %r" % k.decrypt(d) +print("Encrypted: %r" % d) +print("Decrypted: %r" % k.decrypt(d)) assert k.decrypt(d, padmode=PAD_PKCS5) == data @@ -419,6 +419,8 @@ def __String_to_BitList(self, data): # Turn the strings into integers. Python 3 uses a bytes # class, which already has this behaviour. data = [ord(c) for c in data] + # String is list of single-string chars ; BytesIO is list of int chars + data = [c if type(c) == int else ord(c) for c in data] l = len(data) * 8 result = [0] * l pos = 0 @@ -574,7 +576,7 @@ def crypt(self, data, crypt_type): raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n. Try setting the optional padding character") else: data += (self.block_size - (len(data) % self.block_size)) * self.getPadding() - # print "Len of data: %f" % (len(data) / self.block_size) + # print("Len of data: %f" % (len(data) // self.block_size)) if self.getMode() == CBC: if self.getIV(): @@ -591,8 +593,8 @@ def crypt(self, data, crypt_type): while i < len(data): # Test code for caching encryption results #lines += 1 - #if dict.has_key(data[i:i+8]): - #print "Cached result for: %s" % data[i:i+8] + #if data[i:i+8] in dict: + # # print("Cached result for: %s" % data[i:i+8]) # cached += 1 # result.append(dict[data[i:i+8]]) # i += 8 @@ -631,7 +633,7 @@ def crypt(self, data, crypt_type): #dict[data[i:i+8]] = d i += 8 - # print "Lines: %d, cached: %d" % (lines, cached) + # print("Lines: %d, cached: %d" % (lines, cached)) # Return the full crypted string if _pythonMajorVersion < 3: diff --git a/rdpy/security/rc4.py b/rdpy/security/rc4.py index 5802cb1a..2dc35c1b 100644 --- a/rdpy/security/rc4.py +++ b/rdpy/security/rc4.py @@ -24,7 +24,7 @@ def KSA(key): keylength = len(key) - S = range(256) + S = list(range(256)) j = 0 for i in range(256): @@ -51,7 +51,7 @@ def RC4(key): return PRGA(S) def RC4Key(key): - return RC4([ord(c) for c in key]) + return RC4([c for c in key]) def crypt(keystream, plaintext): - return "".join([chr(ord(c) ^ keystream.next()) for c in plaintext]) \ No newline at end of file + return b"".join([bytes([c ^ next(keystream)]) for c in plaintext]) \ No newline at end of file diff --git a/rdpy/security/x509.py b/rdpy/security/x509.py index 5b77cc7b..4e36b845 100644 --- a/rdpy/security/x509.py +++ b/rdpy/security/x509.py @@ -23,6 +23,7 @@ from pyasn1.type import tag, namedtype, namedval, univ, constraint, char, useful from pyasn1.codec.ber import decoder +from codecs import decode MAX = 64 @@ -149,8 +150,20 @@ def extractRSAKey(certificate): #http://www.alvestrand.no/objectid/1.2.840.113549.1.1.1.html binaryTuple = certificate.getComponentByName('tbsCertificate').getComponentByName('subjectPublicKeyInfo').getComponentByName('subjectPublicKey') + print(f"rsa binaryTuple {len(binaryTuple)} {binaryTuple}") + l = "".join([str(i) for i in binaryTuple]) + print(f"rsa l {len(l)} {l}") l = int("".join([str(i) for i in binaryTuple]), 2) - return extractRSAKeyFromASN1(hex(l)[2:-1].decode('hex')) + print(f"rsa l {len(str(l))} {l}") + h = hex(l) + print(f"rsa h {len(h)} {h}") + #h = hex(l)[2:-1] + h = hex(l)[2:] + print(f"rsa h {len(h)} {h}") + #h = '0' + h if len(h) % 2 != 0 else h + decoded_hex = decode(h, 'hex') + print(f"rsa binaryTuple {len(binaryTuple)} {binaryTuple} l {l} h {len(h)} {h} decoded_hex={decoded_hex}") + return extractRSAKeyFromASN1(decoded_hex) def extractRSAKeyFromASN1(subjectPublicKey): rsaKey = decoder.decode(subjectPublicKey, asn1Spec=RSAPublicKey())[0] diff --git a/rdpy/ui/qt4.py b/rdpy/ui/qt5.py similarity index 96% rename from rdpy/ui/qt4.py rename to rdpy/ui/qt5.py index 237f974f..6160b0d8 100644 --- a/rdpy/ui/qt4.py +++ b/rdpy/ui/qt5.py @@ -23,7 +23,7 @@ QRemoteDesktop is a widget use for render in rdpy """ -from PyQt4 import QtGui, QtCore +from PyQt5 import QtGui, QtCore, QtWidgets from rdpy.protocol.rfb.rfb import RFBClientObserver from rdpy.protocol.rdp.rdp import RDPClientObserver from rdpy.core.error import CallPureVirtualFuntion @@ -197,7 +197,7 @@ def RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data): rle.bitmap_decompress(buf, width, height, data, 2) image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB555) else: - image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB555).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) + image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB555).transformed(QtGui.QTransform(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) elif bitsPerPixel == 16: if isCompress: @@ -205,7 +205,7 @@ def RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data): rle.bitmap_decompress(buf, width, height, data, 2) image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB16) else: - image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB16).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) + image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB16).transformed(QtGui.QTransform(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) elif bitsPerPixel == 24: if isCompress: @@ -213,7 +213,7 @@ def RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data): rle.bitmap_decompress(buf, width, height, data, 3) image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB888) else: - image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB888).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) + image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB888).transformed(QtGui.QTransform(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) elif bitsPerPixel == 32: if isCompress: @@ -221,7 +221,7 @@ def RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data): rle.bitmap_decompress(buf, width, height, data, 4) image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB32) else: - image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB32).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) + image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB32).transformed(QtGui.QTransform(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) else: log.error("Receive image in bad format") image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32) @@ -281,7 +281,7 @@ def sendWheelEvent(self, e): @param e: QKeyEvent @param isPressed: event come from press or release action """ - self._controller.sendWheelEvent(e.pos().x(), e.pos().y(), (abs(e.delta()) / 8) / 15, e.delta() < 0, e.orientation() == QtCore.Qt.Horizontal) + self._controller.sendWheelEvent(e.pos().x(), e.pos().y(), (abs(e.delta()) // 8) // 15, e.delta() < 0, e.orientation() == QtCore.Qt.Horizontal) def closeEvent(self, e): """ @@ -330,7 +330,7 @@ def onClose(self): #do something maybe a message -class QRemoteDesktop(QtGui.QWidget): +class QRemoteDesktop(QtWidgets.QWidget): """ @summary: Qt display widget """ @@ -370,7 +370,7 @@ def resize(self, width, height): @param height: {int} height of widget """ self._buffer = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32) - QtGui.QWidget.resize(self, width, height) + QtWidgets.QWidget.resize(self, width, height) def paintEvent(self, e): """ diff --git a/rdpy/ui/view.py b/rdpy/ui/view.py index 7976590e..bc9f63cc 100644 --- a/rdpy/ui/view.py +++ b/rdpy/ui/view.py @@ -21,7 +21,7 @@ Fake widget """ from rdpy.core.error import CallPureVirtualFuntion -from PyQt4 import QtGui, QtCore +from PyQt5 import QtGui, QtCore class KeyCode(object): diff --git a/setup.py b/setup.py index ed310902..618f4216 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from distutils.core import setup, Extension setup(name='rdpy', - version='1.3.2', + version='1.3.3.2', description='Remote Desktop Protocol in Python', long_description=""" RDPY 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. @@ -40,7 +40,7 @@ 'twisted', 'pyopenssl', 'service_identity', - 'qt4reactor', + 'qt5reactor', 'rsa', 'pyasn1' ], diff --git a/test/test_core_const.py b/test/test_core_const.py index 0920bbff..756f047c 100644 --- a/test/test_core_const.py +++ b/test/test_core_const.py @@ -55,4 +55,4 @@ class Test: MEMBER_1 = 1 MEMBER_2 = 2 - self.assertEquals(Test.MEMBER_1, Test.MEMBER_1, "handle same type of object") \ No newline at end of file + self.assertEqual(Test.MEMBER_1, Test.MEMBER_1, "handle same type of object") \ No newline at end of file diff --git a/test/test_core_layer.py b/test/test_core_layer.py index b24d5eab..a02495e0 100644 --- a/test/test_core_layer.py +++ b/test/test_core_layer.py @@ -61,7 +61,7 @@ def expectedCallBack(self, data): t = TestAutomata() t.expect(4, t.expectedCallBack) - self.assertRaises(LayerTest.LayerCaseException, t.dataReceived, "\x00\x00\x00\x00\x00") + self.assertRaises(LayerTest.LayerCaseException, t.dataReceived, b"\x00\x00\x00\x00\x00") def test_layer_automata_less_than_expected(self): """ @@ -74,4 +74,4 @@ def expectedCallBack(self, data): t = TestAutomata() t.expect(4, t.expectedCallBack) - self.assertEqual(t.dataReceived("\x00\x00\x00"), None, "Not enough dada") \ No newline at end of file + self.assertEqual(t.dataReceived(b"\x00\x00\x00"), None, "Not enough dada") \ No newline at end of file diff --git a/test/test_core_type.py b/test/test_core_type.py index 1ca9064f..c0f1302d 100644 --- a/test/test_core_type.py +++ b/test/test_core_type.py @@ -139,7 +139,7 @@ def test_stream_write_uint8_type(self): """ s = rdpy.core.type.Stream() s.writeType(rdpy.core.type.UInt8(1)) - self.assertEqual(''.join(s.buflist), '\x01', "invalid stream write") + self.assertEqual(s.getvalue(), b'\x01', "invalid stream write") def test_stream_write_uint16Le_type(self): """ @@ -147,7 +147,7 @@ def test_stream_write_uint16Le_type(self): """ s = rdpy.core.type.Stream() s.writeType(rdpy.core.type.UInt16Le(1)) - self.assertEqual(''.join(s.buflist), '\x01\x00', "invalid stream write") + self.assertEqual(s.getvalue(), b'\x01\x00', "invalid stream write") def test_stream_write_uint16Be_type(self): """ @@ -155,7 +155,7 @@ def test_stream_write_uint16Be_type(self): """ s = rdpy.core.type.Stream() s.writeType(rdpy.core.type.UInt16Be(1)) - self.assertEqual(''.join(s.buflist), '\x00\x01', "invalid stream write") + self.assertEqual(s.getvalue(), b'\x00\x01', "invalid stream write") def test_stream_write_uint24Le_type(self): """ @@ -163,7 +163,7 @@ def test_stream_write_uint24Le_type(self): """ s = rdpy.core.type.Stream() s.writeType(rdpy.core.type.UInt24Le(1)) - self.assertEqual(''.join(s.buflist), '\x01\x00\x00', "invalid stream write") + self.assertEqual(s.getvalue(), b'\x01\x00\x00', "invalid stream write") def test_stream_write_uint24Be_type(self): """ @@ -171,7 +171,7 @@ def test_stream_write_uint24Be_type(self): """ s = rdpy.core.type.Stream() s.writeType(rdpy.core.type.UInt24Be(1)) - self.assertEqual(''.join(s.buflist), '\x00\x00\x01', "invalid stream write") + self.assertEqual(s.getvalue(), b'\x00\x00\x01', "invalid stream write") def test_stream_write_uint32Le_type(self): """ @@ -179,7 +179,7 @@ def test_stream_write_uint32Le_type(self): """ s = rdpy.core.type.Stream() s.writeType(rdpy.core.type.UInt32Le(1)) - self.assertEqual(''.join(s.buflist), '\x01\x00\x00\x00', "invalid stream write") + self.assertEqual(s.getvalue(), b'\x01\x00\x00\x00', "invalid stream write") def test_stream_write_uint32Be_type(self): """ @@ -187,13 +187,13 @@ def test_stream_write_uint32Be_type(self): """ s = rdpy.core.type.Stream() s.writeType(rdpy.core.type.UInt32Be(1)) - self.assertEqual(''.join(s.buflist), '\x00\x00\x00\x01', "invalid stream write") + self.assertEqual(s.getvalue(), b'\x00\x00\x00\x01', "invalid stream write") def test_stream_read_uint8_type(self): """ @summary: test read UInt8 type from stream """ - s = rdpy.core.type.Stream('\x01') + s = rdpy.core.type.Stream(b'\x01') t = rdpy.core.type.UInt8() s.readType(t) self.assertEqual(t.value, 1, "invalid stream read value") @@ -203,7 +203,7 @@ def test_stream_read_uint16Le_type(self): """ @summary: test read UInt16Le type from stream """ - s = rdpy.core.type.Stream('\x01\x00') + s = rdpy.core.type.Stream(b'\x01\x00') t = rdpy.core.type.UInt16Le() s.readType(t) self.assertEqual(t.value, 1, "invalid stream read value") @@ -213,7 +213,7 @@ def test_stream_read_uint16Be_type(self): """ @summary: test read UInt16Be type from stream """ - s = rdpy.core.type.Stream('\x00\x01') + s = rdpy.core.type.Stream(b'\x00\x01') t = rdpy.core.type.UInt16Be() s.readType(t) self.assertEqual(t.value, 1, "invalid stream read value") @@ -223,7 +223,7 @@ def test_stream_read_uint24Le_type(self): """ @summary: test read UInt24Le type from stream """ - s = rdpy.core.type.Stream('\x01\x00\x00') + s = rdpy.core.type.Stream(b'\x01\x00\x00') t = rdpy.core.type.UInt24Le() s.readType(t) self.assertEqual(t.value, 1, "invalid stream read value") @@ -233,7 +233,7 @@ def test_stream_read_uint24Be_type(self): """ @summary: test read UInt24Be type from stream """ - s = rdpy.core.type.Stream('\x00\x00\x01') + s = rdpy.core.type.Stream(b'\x00\x00\x01') t = rdpy.core.type.UInt24Be() s.readType(t) self.assertEqual(t.value, 1, "invalid stream read") @@ -243,7 +243,7 @@ def test_stream_read_uint32Le_type(self): """ @summary: test read UInt32Le type from stream """ - s = rdpy.core.type.Stream('\x01\x00\x00\x00') + s = rdpy.core.type.Stream(b'\x01\x00\x00\x00') t = rdpy.core.type.UInt32Le() s.readType(t) self.assertEqual(t.value, 1, "invalid stream read value") @@ -253,7 +253,7 @@ def test_stream_read_uint32Be_type(self): """ @summary: test read UInt32Be type from stream """ - s = rdpy.core.type.Stream('\x00\x00\x00\x01') + s = rdpy.core.type.Stream(b'\x00\x00\x00\x01') t = rdpy.core.type.UInt32Be() s.readType(t) self.assertEqual(t.value, 1, "invalid stream read") @@ -276,7 +276,7 @@ def test_stream_read_conditional_singletype_false(self): """ #unsigned int case t = rdpy.core.type.SimpleType("I", 4, False, 0, conditional = lambda:False) - s1 = rdpy.core.type.Stream("\x01\x00\x00\x00") + s1 = rdpy.core.type.Stream(b"\x01\x00\x00\x00") s1.readType(t) self.assertEqual(t.value, 0, "invalid stream read conditional value") @@ -286,7 +286,7 @@ def test_stream_read_conditional_singletype_true(self): """ #unsigned int case t = rdpy.core.type.SimpleType("I", 4, False, 0, conditional = lambda:True) - s1 = rdpy.core.type.Stream("\x01\x00\x00\x00") + s1 = rdpy.core.type.Stream(b"\x01\x00\x00\x00") s1.readType(t) self.assertEqual(t.value, 1, "invalid stream read conditional value") @@ -300,7 +300,7 @@ def __init__(self): self.padding = rdpy.core.type.UInt32Le(0) self.constraint = rdpy.core.type.UInt32Le(1, constant = True) - s = rdpy.core.type.Stream("\x00\x00\x00\x00\x00\x00\x00\x00") + s = rdpy.core.type.Stream(b"\x00\x00\x00\x00\x00\x00\x00\x00") try: s.readType(TestComposite()) except Exception: @@ -325,7 +325,7 @@ def __init__(self): self.padding = rdpy.core.type.UInt32Le(0) self.recurcive = TestSubComposite() - s = rdpy.core.type.Stream("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + s = rdpy.core.type.Stream(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") try: s.readType(TestComposite()) except Exception: @@ -350,7 +350,7 @@ def __init__(self): self.padding = rdpy.core.type.UInt32Le(0) self.recurcive = TestSubComposite() - s = rdpy.core.type.Stream("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + s = rdpy.core.type.Stream(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") try: s.readType(TestComposite()) except Exception: @@ -368,7 +368,7 @@ class TestReadLength(rdpy.core.type.CompositeType): def __init__(self, readLen): rdpy.core.type.CompositeType.__init__(self, readLen = readLen) self.padding = rdpy.core.type.UInt32Le(0) - s = rdpy.core.type.Stream("\x00" * 10) + s = rdpy.core.type.Stream(b"\x00" * 10) s.readType(TestReadLength(rdpy.core.type.UInt8(10))) self.assertEqual(s.dataLen(), 0, "invalid stream read trash data as padding") @@ -382,7 +382,7 @@ class TestReadLength(rdpy.core.type.CompositeType): def __init__(self, readLen): rdpy.core.type.CompositeType.__init__(self, readLen = readLen) self.padding = rdpy.core.type.UInt32Le(0) - s = rdpy.core.type.Stream("\x00" * 10) + s = rdpy.core.type.Stream(b"\x00" * 10) self.assertRaises(InvalidSize, s.readType, TestReadLength(rdpy.core.type.UInt8(2))) def test_stream_read_string(self): diff --git a/test/test_protocol_rdp_ber.py b/test/test_protocol_rdp_ber.py index 4b062a5c..e2d927b1 100644 --- a/test/test_protocol_rdp_ber.py +++ b/test/test_protocol_rdp_ber.py @@ -41,7 +41,7 @@ def test_ber_readLength(self): """ s1 = type.Stream() s1.writeType(type.UInt8(0x1a)) - s1.pos = 0 + s1._pos(0) l1 = ber.readLength(s1) @@ -49,7 +49,7 @@ def test_ber_readLength(self): s2 = type.Stream() s2.writeType((type.UInt8(0x81),type.UInt8(0xab))) - s2.pos = 0 + s2._pos(0) l2 = ber.readLength(s2) @@ -57,7 +57,7 @@ def test_ber_readLength(self): s3 = type.Stream() s3.writeType((type.UInt8(0x82),type.UInt16Be(0xabab))) - s3.pos = 0 + s3._pos(0) l3 = ber.readLength(s3) diff --git a/test/test_protocol_rdp_cssp_ntlm.py b/test/test_protocol_rdp_cssp_ntlm.py index 59872731..ffda1f1d 100644 --- a/test/test_protocol_rdp_cssp_ntlm.py +++ b/test/test_protocol_rdp_cssp_ntlm.py @@ -22,6 +22,7 @@ """ import unittest import os, sys +import base64 # Change path so we find rdpy sys.path.insert(1, os.path.join(sys.path[0], '..')) @@ -73,9 +74,9 @@ class TestCsspNtlm(unittest.TestCase): @summary: test generate ntlmv2 over cssp authentication protocol """ def testCSSPNTLMAuthentication(self): - negotiate_data_request = cssp.decodeDERTRequest(peer0_0.decode('base64')) - challenge_data_request = cssp.decodeDERTRequest(peer1_0.decode('base64')) - authenticate_data_request = cssp.decodeDERTRequest(peer0_1.decode('base64')) + negotiate_data_request = cssp.decodeDERTRequest(base64.b64decode(peer0_0)) + challenge_data_request = cssp.decodeDERTRequest(base64.b64decode(peer1_0)) + authenticate_data_request = cssp.decodeDERTRequest(base64.b64decode(peer0_1)) negotiate_data = cssp.getNegoTokens(negotiate_data_request)[0] challenge_data = cssp.getNegoTokens(challenge_data_request)[0] @@ -122,7 +123,7 @@ def testCSSPNTLMAuthentication(self): interface = ntlm.NTLMv2SecurityInterface(rc4.RC4Key(ClientSealingKey), rc4.RC4Key(ServerSealingKey), ClientSigningKey, ServerSigningKey) EncryptedPubKeySrc = cssp.getPubKeyAuth(authenticate_data_request) - EncryptedPubKeyDst = interface.GSS_WrapEx(pubKeyHex.decode('base64')) + EncryptedPubKeyDst = interface.GSS_WrapEx(base64.b64decode(pubKeyHex)) self.assertTrue(EncryptedPubKeySrc == EncryptedPubKeyDst, "Public key must be equals") \ No newline at end of file diff --git a/test/test_protocol_rdp_lic.py b/test/test_protocol_rdp_lic.py index 9627d801..c5d54239 100644 --- a/test/test_protocol_rdp_lic.py +++ b/test/test_protocol_rdp_lic.py @@ -28,9 +28,10 @@ import unittest from rdpy.protocol.rdp import lic, sec import rdpy.core.type as type +import base64 #dump of server request -SERVERREQUEST = """ +SERVERREQUEST = b""" AQNfCBkr6c1CVLRPx7PPYVgzW5uMQ1pSvtzs9XlTt74jwjslAAAGACwAAABNAGkAYwByAG8AcwBv AGYAdAAgAEMAbwByAHAAbwByAGEAdABpAG8AbgAAAAgAAABBADAAMgAAAA0ABAABAAAAAwDZBwIA AAACAAAAWAMAADCCA1QwggJAoAMCAQICCAGemF/kFo3QMAkGBSsOAwIdBQAwODE2MBUGA1UEBx4O @@ -93,7 +94,7 @@ def test_valid_client_licensing_error_message(self): s = type.Stream() s.writeType(lic.createValidClientLicensingErrorMessage()) #reinit position - s.pos = 0 + s._pos(0) self.assertTrue(l.recv(s), "Manager can retrieve valid case") @@ -106,7 +107,7 @@ def sendFlagged(self, flag, message): return s = type.Stream() s.writeType(message) - s.pos = 0 + s._pos(0) s.readType(lic.LicPacket(lic.ClientNewLicenseRequest())) self._state = True def getGCCServerSettings(self): @@ -124,6 +125,6 @@ def __init__(self): t = Transport() l = lic.LicenseManager(t) - s = type.Stream(SERVERREQUEST.decode("base64")) + s = type.Stream(base64.b64decode(SERVERREQUEST)) self.assertFalse(l.recv(s) and t._state, "Bad message after license request") \ No newline at end of file diff --git a/test/test_protocol_rdp_per.py b/test/test_protocol_rdp_per.py index ad3f7a00..ecd787c4 100644 --- a/test/test_protocol_rdp_per.py +++ b/test/test_protocol_rdp_per.py @@ -41,7 +41,7 @@ def test_per_readLength(self): """ s1 = type.Stream() s1.writeType(type.UInt8(0x1a)) - s1.pos = 0 + s1._pos(0) l1 = per.readLength(s1) @@ -49,7 +49,7 @@ def test_per_readLength(self): s2 = type.Stream() s2.writeType(type.UInt16Be(0x1abc | 0x8000)) - s2.pos = 0 + s2._pos(0) l2 = per.readLength(s2) @@ -79,7 +79,7 @@ def test_per_readInteger(self): v = t(3) s = type.Stream() s.writeType((per.writeLength(type.sizeof(v)), v)) - s.pos = 0 + s._pos(0) self.assertTrue(per.readInteger(s) == 3, "invalid readLength for type %s"%t) @@ -87,7 +87,7 @@ def test_per_readInteger(self): for l in [0, 3, 5]: s = type.Stream() s.writeType(per.writeLength(l)) - s.pos = 0 + s._pos(0) self.assertRaises(error.InvalidValue, per.readInteger, s) diff --git a/test/test_protocol_rdp_rc4.py b/test/test_protocol_rdp_rc4.py index 68063463..a6c9f293 100644 --- a/test/test_protocol_rdp_rc4.py +++ b/test/test_protocol_rdp_rc4.py @@ -36,13 +36,13 @@ class RC4Test(unittest.TestCase): """ def test_rc4_key_plaintext(self): - self.assertEqual("\xBB\xF3\x16\xE8\xD9\x40\xAF\x0A\xD3", rc4.crypt(rc4.RC4Key("Key"), "Plaintext"), "RC4 bad crypt") - self.assertEqual("Plaintext", rc4.crypt(rc4.RC4Key("Key"), "\xBB\xF3\x16\xE8\xD9\x40\xAF\x0A\xD3"), "RC4 bad crypt") + self.assertEqual(b"\xBB\xF3\x16\xE8\xD9\x40\xAF\x0A\xD3", rc4.crypt(rc4.RC4Key(b"Key"), b"Plaintext"), "RC4 bad crypt") + self.assertEqual(b"Plaintext", rc4.crypt(rc4.RC4Key(b"Key"), b"\xBB\xF3\x16\xE8\xD9\x40\xAF\x0A\xD3"), "RC4 bad crypt") def test_rc4_wiki_pedia(self): - self.assertEqual("\x10\x21\xBF\x04\x20", rc4.crypt(rc4.RC4Key("Wiki"), "pedia"), "RC4 bad crypt") - self.assertEqual("pedia", rc4.crypt(rc4.RC4Key("Wiki"), "\x10\x21\xBF\x04\x20"), "RC4 bad crypt") + self.assertEqual(b"\x10\x21\xBF\x04\x20", rc4.crypt(rc4.RC4Key(b"Wiki"), b"pedia"), "RC4 bad crypt") + self.assertEqual(b"pedia", rc4.crypt(rc4.RC4Key(b"Wiki"), b"\x10\x21\xBF\x04\x20"), "RC4 bad crypt") def test_rc4_secret_attack_at_down(self): - self.assertEqual("\x45\xA0\x1F\x64\x5F\xC3\x5B\x38\x35\x52\x54\x4B\x9B\xF5", rc4.crypt(rc4.RC4Key("Secret"), "Attack at dawn"), "RC4 bad crypt") - self.assertEqual("Attack at dawn", rc4.crypt(rc4.RC4Key("Secret"), "\x45\xA0\x1F\x64\x5F\xC3\x5B\x38\x35\x52\x54\x4B\x9B\xF5"), "RC4 bad crypt") + self.assertEqual(b"\x45\xA0\x1F\x64\x5F\xC3\x5B\x38\x35\x52\x54\x4B\x9B\xF5", rc4.crypt(rc4.RC4Key(b"Secret"), b"Attack at dawn"), "RC4 bad crypt") + self.assertEqual(b"Attack at dawn", rc4.crypt(rc4.RC4Key(b"Secret"), b"\x45\xA0\x1F\x64\x5F\xC3\x5B\x38\x35\x52\x54\x4B\x9B\xF5"), "RC4 bad crypt") diff --git a/test/test_protocol_rdp_tpkt.py b/test/test_protocol_rdp_tpkt.py index 9e277921..5fb36aeb 100644 --- a/test/test_protocol_rdp_tpkt.py +++ b/test/test_protocol_rdp_tpkt.py @@ -60,10 +60,10 @@ class Presentation(object): def connect(self): pass def recv(self, data): - data.readType(type.String("test_tpkt_layer_recv", constant = True)) + data.readType(type.String(b"test_tpkt_layer_recv", constant = True)) raise TPKTTest.TPKT_PASS() - message = type.String("test_tpkt_layer_recv") + message = type.String(b"test_tpkt_layer_recv") s = type.Stream() s.writeType((type.UInt8(tpkt.Action.FASTPATH_ACTION_X224), type.UInt8(), type.UInt16Be(type.sizeof(message) + 4), message)) @@ -80,10 +80,10 @@ class FastPathLayer(tpkt.IFastPathListener): def setFastPathSender(self, fastPathSender): pass def recvFastPath(self, secFlag, fastPathS): - fastPathS.readType(type.String("test_tpkt_layer_recv_fastpath", constant = True)) + fastPathS.readType(type.String(b"test_tpkt_layer_recv_fastpath", constant = True)) raise TPKTTest.TPKT_PASS() - message = type.String("test_tpkt_layer_recv_fastpath") + message = type.String(b"test_tpkt_layer_recv_fastpath") s = type.Stream() s.writeType((type.UInt8(tpkt.Action.FASTPATH_ACTION_FASTPATH), type.UInt8(type.sizeof(message) + 2), message)) @@ -101,10 +101,10 @@ class FastPathLayer(tpkt.IFastPathListener): def setFastPathSender(self, fastPathSender): pass def recvFastPath(self, secflag, fastPathS): - fastPathS.readType(type.String("test_tpkt_layer_recv_fastpath_ext_length", constant = True)) + fastPathS.readType(type.String(b"test_tpkt_layer_recv_fastpath_ext_length", constant = True)) raise TPKTTest.TPKT_PASS() - message = type.String("test_tpkt_layer_recv_fastpath_ext_length") + message = type.String(b"test_tpkt_layer_recv_fastpath_ext_length") s = type.Stream() s.writeType((type.UInt8(tpkt.Action.FASTPATH_ACTION_FASTPATH), type.UInt16Be((type.sizeof(message) + 3) | 0x8000), message)) diff --git a/test/test_protocol_rdp_x224.py b/test/test_protocol_rdp_x224.py index e396e06f..2d62c81a 100644 --- a/test/test_protocol_rdp_x224.py +++ b/test/test_protocol_rdp_x224.py @@ -53,14 +53,14 @@ def test_x224_layer_recvData(self): """ class Presentation(object): def recv(self, data): - data.readType(type.String('test_x224_layer_recvData', constant = True)) + data.readType(type.String(b'test_x224_layer_recvData', constant = True)) raise X224Test.X224_PASS() layer = x224.X224Layer(Presentation()) s = type.Stream() - s.writeType((x224.X224DataHeader(), type.String('test_x224_layer_recvData'))) + s.writeType((x224.X224DataHeader(), type.String(b'test_x224_layer_recvData'))) #reinit position - s.pos = 0 + s._pos(0) self.assertRaises(X224Test.X224_PASS, layer.recvData, s) @@ -72,15 +72,15 @@ class Transport(object): def send(self, data): s = type.Stream() s.writeType(data) - s.pos = 0 + s._pos(0) s.readType(x224.X224DataHeader()) - s.readType(type.String('test_x224_layer_send', constant = True)) + s.readType(type.String(b'test_x224_layer_send', constant = True)) raise X224Test.X224_PASS() layer = x224.X224Layer(None) layer._transport = Transport() - self.assertRaises(X224Test.X224_PASS, layer.send, type.String('test_x224_layer_send')) + self.assertRaises(X224Test.X224_PASS, layer.send, type.String(b'test_x224_layer_send')) def test_x224_client_connect(self): """ @@ -90,7 +90,7 @@ class Transport(object): def send(self, data): s = type.Stream() s.writeType(data) - s.pos = 0 + s._pos(0) t = x224.ClientConnectionRequestPDU() s.readType(t) @@ -105,7 +105,7 @@ def nextAutomata(data): layer.recvConnectionConfirm = nextAutomata layer.connect() - self.assertRaises(X224Test.X224_PASS, layer.recv, type.String('\x01\x02')) + self.assertRaises(X224Test.X224_PASS, layer.recv, type.String(b'\x01\x02')) def test_x224_client_recvConnectionConfirm_negotiation_failure(self): """ @@ -116,7 +116,7 @@ def test_x224_client_recvConnectionConfirm_negotiation_failure(self): message.protocolNeg.code.value = x224.NegociationType.TYPE_RDP_NEG_FAILURE s = type.Stream() s.writeType(message) - s.pos = 0 + s._pos(0) layer = x224.Client(None) self.assertRaises(error.RDPSecurityNegoFail, layer.recvConnectionConfirm, s) @@ -146,7 +146,7 @@ def recvData(data): s = type.Stream() s.writeType(message) - s.pos = 0 + s._pos(0) layer = x224.Client(Presentation()) layer._transport = Transport() layer.recvData = recvData @@ -155,7 +155,7 @@ def recvData(data): self.assertTrue(tls_begin, "TLS is not started") self.assertTrue(presentation_connect, "connect event is not forwarded") - self.assertRaises(X224Test.X224_PASS, layer.recv, type.String('\x01\x02')) + self.assertRaises(X224Test.X224_PASS, layer.recv, type.String(b'\x01\x02')) def test_x224_server_recvConnectionRequest_client_accept_ssl(self): """ @@ -176,7 +176,7 @@ def close(self): message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_HYBRID s = type.Stream() s.writeType(message) - s.pos = 0 + s._pos(0) layer = x224.Server(None, "key", "cert", True) layer._transport = Transport() @@ -218,7 +218,7 @@ def connect(self): message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_SSL | x224.Protocols.PROTOCOL_RDP s = type.Stream() s.writeType(message) - s.pos = 0 + s._pos(0) layer = x224.Server(Presentation(), "key", "cert") layer._transport = Transport()