23 Commits

Author SHA1 Message Date
citronneur
1c4b42544c Update: Finish mcs connect 2020-05-27 22:27:24 +02:00
citronneur
9550734743 Fix: bad string length 2020-04-21 22:13:20 +02:00
citronneur
73b97d6929 Update: Start MCS layer 2020-04-21 22:02:35 +02:00
citronneur
018c59fe42 Update: refactor cssp code 2020-04-20 22:51:32 +02:00
citronneur
9cac72a8d2 Update: TPKT + x224 asyncio complient 2020-04-17 15:52:37 +02:00
unknown
3f56b25f46 Start python3 2020-04-14 21:56:46 +02:00
Sylvain Peyrefitte
cef16a9f64 Merge pull request #108 from cudeso/master
Add logging for rdphoneypot
2020-04-10 21:12:15 +02:00
Koen Van Impe
9aea135fd9 Add logging 2020-04-10 21:05:18 +02:00
Sylvain Peyrefitte
4109b7a6fe Merge pull request #67 from Mutchako/patch-1
Update setup.py
2018-08-23 22:20:14 +02:00
Sylvain Peyrefitte
d3b0ae5e90 Merge pull request #80 from speidy/pointerex
onPointerEvent: handle 4, 5 mouse buttons based on INPUT_EVENT_MOUSEX event
2018-08-23 22:18:20 +02:00
Idan Freiberg
a1f9afa87a onPointerEvent: handle 4, 5 mouse buttons based on INPUT_EVENT_MOUSEX event 2018-08-06 07:52:32 +03:00
Sylvain Peyrefitte
b8ff4136b6 Merge pull request #78 from speidy/mitm
rdpy-rdpmitm: pep8 fixes, argument parsing improvements
2018-08-05 16:23:28 +02:00
Sylvain Peyrefitte
ce04150790 Merge pull request #77 from speidy/pointerex
data: add support for INPUT_EVENT_MOUSEX event
2018-08-05 16:23:03 +02:00
speidy
bcec1aad25 rdpy-rdpmitm: use argparse for argument parsing 2018-08-05 17:07:29 +03:00
speidy
c18a4c4101 rdpy-rdpmitm: apply pep8 fixes 2018-08-05 15:58:07 +03:00
speidy
3e37899ae4 data: add support for INPUT_EVENT_MOUSEX event 2018-08-05 14:28:23 +03:00
Mutchako
cd6e14e7ef Update setup.py
Syntax error on install_requires. Unnecessary comma on last statement.
2018-02-12 09:48:17 -05:00
Sylvain Peyrefitte
629d2160af Merge pull request #33 from ChrisTruncer/bin_
Small change to reference object attribute
2015-06-01 11:40:37 +02:00
Christopher Truncer
e23def3179 Small changeto reference object attribute 2015-05-28 12:08:55 -04:00
speyrefitte
a23ae25a1f fix issue on unhandle upadte 2015-05-21 10:29:32 +02:00
speyrefitte
763ed2e3ee fix major bug on update handle 2015-05-20 17:51:43 +02:00
speyrefitte
11d66a4818 add onSessionReady event -> user session is ready 2015-05-19 17:53:15 +02:00
speyrefitte
9b99365f80 fix bug on lwin key activation 2015-05-19 16:42:22 +02:00
51 changed files with 2003 additions and 3103 deletions

2
.gitignore vendored
View File

@@ -7,3 +7,5 @@ README.md~
dist/* dist/*
build/* build/*
rdpy.egg-info/* rdpy.egg-info/*
*.pyd
.idea

View File

@@ -145,7 +145,7 @@ In a nutshell RDPY can be used as a protocol library with a twisted engine.
### Simple RDP Client ### Simple RDP Client
```python ```python
from rdpy.protocol.rdp import rdp from rdpy.core import rdp
class MyRDPFactory(rdp.ClientFactory): class MyRDPFactory(rdp.ClientFactory):
@@ -182,6 +182,11 @@ class MyRDPFactory(rdp.ClientFactory):
@param data: bitmap data @param data: bitmap data
""" """
def onSessionReady(self):
"""
@summary: Windows session is ready
"""
def onClose(self): def onClose(self):
""" """
@summary: Call when stack is close @summary: Call when stack is close
@@ -196,7 +201,7 @@ reactor.run()
### Simple RDP Server ### Simple RDP Server
```python ```python
from rdpy.protocol.rdp import rdp from rdpy.core import rdp
class MyRDPFactory(rdp.ServerFactory): class MyRDPFactory(rdp.ServerFactory):
@@ -231,7 +236,7 @@ class MyRDPFactory(rdp.ServerFactory):
@summary: Event call on mouse event @summary: Event call on mouse event
@param x: x position @param x: x position
@param y: y position @param y: y position
@param button: 1, 2 or 3 button @param button: 1, 2, 3, 4 or 5 button
@param isPressed: True if mouse button is pressed @param isPressed: True if mouse button is pressed
@see: rdp.RDPServerObserver.onPointerEvent @see: rdp.RDPServerObserver.onPointerEvent
""" """

View File

@@ -21,268 +21,27 @@
example of use rdpy as rdp client example of use rdpy as rdp client
""" """
import sys, os, getopt, socket import sys
import asyncio
from PyQt4 import QtGui, QtCore from rdpy.core import tpkt, x224
from rdpy.ui.qt4 import RDPClientQt from rdpy.core.nla import ntlm
from rdpy.protocol.rdp import rdp from rdpy.core.t125 import mcs
from rdpy.core.error import RDPSecurityNegoFail from rdpy.model.message import UInt8
from rdpy.core import rss
import rdpy.core.log as log
log._LOG_LEVEL = log.Level.INFO
class RDPClientQtRecorder(RDPClientQt):
"""
@summary: Widget with record session
"""
def __init__(self, controller, width, height, rssRecorder):
"""
@param controller: {RDPClientController} RDP controller
@param width: {int} width of widget
@param height: {int} height of widget
@param rssRecorder: {rss.FileRecorder}
"""
RDPClientQt.__init__(self, controller, width, height)
self._screensize = width, height
self._rssRecorder = rssRecorder
def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
"""
@summary: Notify bitmap update
@param destLeft: {int} xmin position
@param destTop: {int} ymin position
@param destRight: {int} xmax position because RDP can send bitmap with padding
@param destBottom: {int} ymax position because RDP can send bitmap with padding
@param width: {int} width of bitmap
@param height: {int} height of bitmap
@param bitsPerPixel: {int} number of bit per pixel
@param isCompress: {bool} use RLE compression
@param data: {str} bitmap data
"""
#record update
self._rssRecorder.update(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, rss.UpdateFormat.BMP if isCompress else rss.UpdateFormat.RAW, data)
RDPClientQt.onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data)
def onReady(self):
"""
@summary: Call when stack is ready
"""
self._rssRecorder.screen(self._screensize[0], self._screensize[1], self._controller.getColorDepth())
RDPClientQt.onReady(self)
def onClose(self):
"""
@summary: Call when stack is close
"""
self._rssRecorder.close()
RDPClientQt.onClose(self)
def closeEvent(self, e):
"""
@summary: Convert Qt close widget event into close stack event
@param e: QCloseEvent
"""
self._rssRecorder.close()
RDPClientQt.closeEvent(self, e)
class RDPClientQtFactory(rdp.ClientFactory):
"""
@summary: Factory create a RDP GUI client
"""
def __init__(self, width, height, username, password, domain, fullscreen, keyboardLayout, optimized, security, recodedPath):
"""
@param width: {integer} width of client
@param heigth: {integer} heigth of client
@param username: {str} username present to the server
@param password: {str} password present to the server
@param domain: {str} microsoft domain
@param fullscreen: {bool} show widget in fullscreen mode
@param keyboardLayout: {str} (fr|en) keyboard layout
@param optimized: {bool} enable optimized session orders
@param security: {str} (ssl | rdp | nego)
@param recodedPath: {str | None} Rss file Path
"""
self._width = width
self._height = height
self._username = username
self._passwod = password
self._domain = domain
self._fullscreen = fullscreen
self._keyboardLayout = keyboardLayout
self._optimized = optimized
self._nego = security == "nego"
self._recodedPath = recodedPath
if self._nego:
#compute start nego nla need credentials
if username != "" and password != "":
self._security = rdp.SecurityLevel.RDP_LEVEL_NLA
else:
self._security = rdp.SecurityLevel.RDP_LEVEL_SSL
else:
self._security = security
self._w = None
def buildObserver(self, controller, addr):
"""
@summary: Build RFB observer
We use a RDPClientQt as RDP observer
@param controller: build factory and needed by observer
@param addr: destination address
@return: RDPClientQt
"""
#create client observer
if self._recodedPath is None:
self._client = RDPClientQt(controller, self._width, self._height)
else:
self._client = RDPClientQtRecorder(controller, self._width, self._height, rss.createRecorder(self._recodedPath))
#create qt widget
self._w = self._client.getWidget()
self._w.setWindowTitle('rdpy-rdpclient')
if self._fullscreen:
self._w.showFullScreen()
else:
self._w.show()
controller.setUsername(self._username)
controller.setPassword(self._passwod)
controller.setDomain(self._domain)
controller.setKeyboardLayout(self._keyboardLayout)
controller.setHostname(socket.gethostname())
if self._optimized:
controller.setPerformanceSession()
controller.setSecurityLevel(self._security)
return self._client
def clientConnectionLost(self, connector, reason):
"""
@summary: Connection lost event
@param connector: twisted connector use for rdp connection (use reconnect to restart connection)
@param reason: str use to advertise reason of lost connection
"""
#try reconnect with basic RDP security
if reason.type == RDPSecurityNegoFail and self._nego:
#stop nego
log.info("due to security nego error back to standard RDP security layer")
self._nego = False
self._security = rdp.SecurityLevel.RDP_LEVEL_RDP
self._client._widget.hide()
connector.connect()
return
QtGui.QMessageBox.warning(self._w, "Warning", "Lost connection : %s"%reason)
reactor.stop()
app.exit()
def clientConnectionFailed(self, connector, reason):
"""
@summary: Connection failed event
@param connector: twisted connector use for rdp 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()
app.exit()
def autoDetectKeyboardLayout():
"""
@summary: try to auto detect keyboard layout
"""
try:
if os.name == 'posix':
from subprocess import check_output
result = check_output(["setxkbmap", "-print"])
if 'azerty' in result:
return "fr"
elif os.name == 'nt':
import win32api, win32con, win32process
from ctypes import windll
w = windll.user32.GetForegroundWindow()
tid = windll.user32.GetWindowThreadProcessId(w, 0)
result = windll.user32.GetKeyboardLayout(tid)
log.info(result)
if result == 0x40c040c:
return "fr"
except Exception as e:
log.info("failed to auto detect keyboard layout " + str(e))
pass
return "en"
def help():
print """
Usage: rdpy-rdpclient [options] ip[:port]"
\t-u: user name
\t-p: password
\t-d: domain
\t-w: width of screen [default : 1024]
\t-l: height of screen [default : 800]
\t-f: enable full screen mode [default : False]
\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__': if __name__ == '__main__':
#default script argument #sys.exit(app.exec_())
username = ""
password = ""
domain = ""
width = 1024
height = 800
fullscreen = False
optimized = False
recodedPath = None
keyboardLayout = autoDetectKeyboardLayout()
try: async def tcp_echo_client(message):
opts, args = getopt.getopt(sys.argv[1:], "hfou:p:d:w:l:k:r:") reader, writer = await asyncio.open_connection(
except getopt.GetoptError: '127.0.0.1', 33389)
help()
for opt, arg in opts:
if opt == "-h":
help()
sys.exit()
elif opt == "-u":
username = arg
elif opt == "-p":
password = arg
elif opt == "-d":
domain = arg
elif opt == "-w":
width = int(arg)
elif opt == "-l":
height = int(arg)
elif opt == "-f":
fullscreen = True
elif opt == "-o":
optimized = True
elif opt == "-k":
keyboardLayout = arg
elif opt == "-r":
recodedPath = arg
if ':' in args[0]: x224_layer = await x224.connect(tpkt.Tpkt(reader, writer), ntlm.NTLMv2("", "sylvain", "sylvain"))
ip, port = args[0].split(':') mcs_layer = mcs.Client(x224_layer)
else: await mcs_layer.connect()
ip, port = args[0], "3389"
#create application await asyncio.sleep(10)
app = QtGui.QApplication(sys.argv) print("foooooooooooooooooooo")
#add qt4 reactor asyncio.run(tcp_echo_client('Hello World!'))
import qt4reactor
qt4reactor.install()
if fullscreen:
width = QtGui.QDesktopWidget().screenGeometry().width()
height = QtGui.QDesktopWidget().screenGeometry().height()
log.info("keyboard layout set to %s"%keyboardLayout)
from twisted.internet import reactor
reactor.connectTCP(ip, int(port), RDPClientQtFactory(width, height, username, password, domain, fullscreen, keyboardLayout, optimized, "nego", recodedPath))
reactor.runReturn()
app.exec_()

View File

@@ -22,10 +22,10 @@
RDP Honey pot use Rss scenario file to simulate RDP server RDP Honey pot use Rss scenario file to simulate RDP server
""" """
import sys, os, getopt, time import sys, getopt, datetime
from rdpy.core import log, error, rss from rdpy.core import log, rss
from rdpy.protocol.rdp import rdp from rdpy.core import rdp
from twisted.internet import reactor from twisted.internet import reactor
log._LOG_LEVEL = log.Level.INFO log._LOG_LEVEL = log.Level.INFO
@@ -54,23 +54,18 @@ class HoneyPotServer(rdp.RDPServerObserver):
width, height = self._controller.getScreen() width, height = self._controller.getScreen()
size = width * height size = width * height
rssFilePath = sorted(self._rssFileSizeList, key = lambda x: abs(x[0][0] * x[0][1] - size))[0][1] rssFilePath = sorted(self._rssFileSizeList, key = lambda x: abs(x[0][0] * x[0][1] - size))[0][1]
log.info("select file (%s, %s) -> %s"%(width, height, rssFilePath)) log.info("%s --- select file (%s, %s) -> %s"%(datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'),width, height, rssFilePath))
self._rssFile = rss.createReader(rssFilePath) self._rssFile = rss.createReader(rssFilePath)
domain, username, password = self._controller.getCredentials() domain, username, password = self._controller.getCredentials()
hostname = self._controller.getHostname() hostname = self._controller.getHostname()
log.info("""Credentials: log.info("""%s --- Credentials: domain: %s username: %s password: %s hostname: %s"""%(datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'), domain, username, password, hostname));
\tdomain : %s
\tusername : %s
\tpassword : %s
\thostname : %s
"""%(domain, username, password, hostname));
self.start() self.start()
def onClose(self): def onClose(self):
""" HoneyPot """ """ HoneyPot """
def onKeyEventScancode(self, code, isPressed): def onKeyEventScancode(self, code, isPressed, isExtended):
""" HoneyPot """ """ HoneyPot """
def onKeyEventUnicode(self, code, isPressed): def onKeyEventUnicode(self, code, isPressed):
@@ -125,7 +120,7 @@ class HoneyPotServerFactory(rdp.ServerFactory):
@param addr: destination address @param addr: destination address
@see: rdp.ServerFactory.buildObserver @see: rdp.ServerFactory.buildObserver
""" """
log.info("Connection from %s:%s"%(addr.host, addr.port)) log.info("%s --- Connection from %s:%s"%(datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'), addr.host, addr.port))
return HoneyPotServer(controller, self._rssFileSizeList) return HoneyPotServer(controller, self._rssFileSizeList)
def readSize(filePath): def readSize(filePath):
@@ -146,10 +141,12 @@ def help():
@summary: Print help in console @summary: Print help in console
""" """
print """ print """
Usage: rdpy-rdphoneypot.py rss_filepath(1..n) Usage: rdpy-rdphoneypot.py
[-L logfile]
[-l listen_port default 3389] [-l listen_port default 3389]
[-k private_key_file_path (mandatory for SSL)] [-k private_key_file_path (mandatory for SSL)]
[-c certificate_file_path (mandatory for SSL)] [-c certificate_file_path (mandatory for SSL)]
rss_filepath(1..n)
""" """
if __name__ == '__main__': if __name__ == '__main__':
@@ -159,13 +156,15 @@ if __name__ == '__main__':
rssFileSizeList = [] rssFileSizeList = []
try: try:
opts, args = getopt.getopt(sys.argv[1:], "hl:k:c:") opts, args = getopt.getopt(sys.argv[1:], "hl:k:c:L:")
except getopt.GetoptError: except getopt.GetoptError:
help() help()
for opt, arg in opts: for opt, arg in opts:
if opt == "-h": if opt == "-h":
help() help()
sys.exit() sys.exit()
elif opt == "-L":
log._LOG_FILE = arg
elif opt == "-l": elif opt == "-l":
listen = arg listen = arg
elif opt == "-k": elif opt == "-k":
@@ -174,11 +173,12 @@ if __name__ == '__main__':
certificateFilePath = arg certificateFilePath = arg
#build size map #build size map
log.info("Build size map") log.info("%s --- Start rdphoneypot"%datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'))
log.info("%s --- Build size map"%datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'))
for arg in args: for arg in args:
size = readSize(arg) size = readSize(arg)
rssFileSizeList.append((size, arg)) rssFileSizeList.append((size, arg))
log.info("(%s, %s) -> %s"%(size[0], size[1], arg)) log.info("%s --- (%s, %s) -> %s"%(datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'), size[0], size[1], arg))
reactor.listenTCP(int(listen), HoneyPotServerFactory(rssFileSizeList, privateKeyFilePath, certificateFilePath)) reactor.listenTCP(int(listen), HoneyPotServerFactory(rssFileSizeList, privateKeyFilePath, certificateFilePath))
reactor.run() reactor.run()

View File

@@ -29,18 +29,22 @@ Client RDP -> | ProxyServer | ProxyClient | -> Server RDP
----------------- -----------------
""" """
import sys, os, getopt, time import os
import argparse
import time
from rdpy.core import log, error, rss from rdpy.core import log, rss
from rdpy.protocol.rdp import rdp from rdpy.core import rdp
from twisted.internet import reactor from twisted.internet import reactor
log._LOG_LEVEL = log.Level.INFO log._LOG_LEVEL = log.Level.INFO
class ProxyServer(rdp.RDPServerObserver): class ProxyServer(rdp.RDPServerObserver):
""" """
@summary: Server side of proxy @summary: Server side of proxy
""" """
def __init__(self, controller, target, clientSecurityLevel, rssRecorder): def __init__(self, controller, target, clientSecurityLevel, rssRecorder):
""" """
@param controller: {RDPServerController} @param controller: {RDPServerController}
@@ -71,7 +75,8 @@ class ProxyServer(rdp.RDPServerObserver):
if self._client is None: if self._client is None:
# try a connection # try a connection
domain, username, password = self._controller.getCredentials() domain, username, password = self._controller.getCredentials()
self._rss.credentials(username, password, domain, self._controller.getHostname()) self._rss.credentials(username, password,
domain, self._controller.getHostname())
width, height = self._controller.getScreen() width, height = self._controller.getScreen()
self._rss.screen(width, height, self._controller.getColorDepth()) self._rss.screen(width, height, self._controller.getColorDepth())
@@ -92,16 +97,18 @@ class ProxyServer(rdp.RDPServerObserver):
return return
self._client._controller.close() self._client._controller.close()
def onKeyEventScancode(self, code, isPressed): def onKeyEventScancode(self, code, isPressed, isExtended):
""" """
@summary: Event call when a keyboard event is catch in scan code format @summary: Event call when a keyboard event is catch in scan code format
@param code: {int} scan code of key @param code: {integer} scan code of key
@param isPressed: {bool} True if key is down @param isPressed: {boolean} True if key is down
@param isExtended: {boolean} True if a special key
@see: rdp.RDPServerObserver.onKeyEventScancode @see: rdp.RDPServerObserver.onKeyEventScancode
""" """
if self._client is None: if self._client is None:
return return
self._client._controller.sendKeyEventScancode(code, isPressed) self._client._controller.sendKeyEventScancode(
code, isPressed, isExtended)
self._rss.keyScancode(code, isPressed) self._rss.keyScancode(code, isPressed)
def onKeyEventUnicode(self, code, isPressed): def onKeyEventUnicode(self, code, isPressed):
@@ -121,7 +128,7 @@ class ProxyServer(rdp.RDPServerObserver):
@summary: Event call on mouse event @summary: Event call on mouse event
@param x: {int} x position @param x: {int} x position
@param y: {int} y position @param y: {int} y position
@param button: {int} 1, 2 or 3 button @param button: {int} 1, 2, 3, 4 or 5 button
@param isPressed: {bool} True if mouse button is pressed @param isPressed: {bool} True if mouse button is pressed
@see: rdp.RDPServerObserver.onPointerEvent @see: rdp.RDPServerObserver.onPointerEvent
""" """
@@ -129,10 +136,12 @@ class ProxyServer(rdp.RDPServerObserver):
return return
self._client._controller.sendPointerEvent(x, y, button, isPressed) self._client._controller.sendPointerEvent(x, y, button, isPressed)
class ProxyServerFactory(rdp.ServerFactory): class ProxyServerFactory(rdp.ServerFactory):
""" """
@summary: Factory on listening events @summary: Factory on listening events
""" """
def __init__(self, target, ouputDir, privateKeyFilePath, certificateFilePath, clientSecurity): def __init__(self, target, ouputDir, privateKeyFilePath, certificateFilePath, clientSecurity):
""" """
@param target: {tuple(ip, prt)} @param target: {tuple(ip, prt)}
@@ -140,7 +149,8 @@ class ProxyServerFactory(rdp.ServerFactory):
@param certificateFilePath: {str} file contain server certificate (if none -> back to standard RDP security) @param certificateFilePath: {str} file contain server certificate (if none -> back to standard RDP security)
@param clientSecurity: {str(ssl|rdp)} security layer use in client connection side @param clientSecurity: {str(ssl|rdp)} security layer use in client connection side
""" """
rdp.ServerFactory.__init__(self, 16, privateKeyFilePath, certificateFilePath) rdp.ServerFactory.__init__(
self, 16, privateKeyFilePath, certificateFilePath)
self._target = target self._target = target
self._ouputDir = ouputDir self._ouputDir = ouputDir
self._clientSecurity = clientSecurity self._clientSecurity = clientSecurity
@@ -156,10 +166,12 @@ class ProxyServerFactory(rdp.ServerFactory):
self._uniqueId += 1 self._uniqueId += 1
return ProxyServer(controller, self._target, self._clientSecurity, rss.createRecorder(os.path.join(self._ouputDir, "%s_%s_%s.rss" % (time.strftime('%Y%m%d%H%M%S'), addr.host, self._uniqueId)))) return ProxyServer(controller, self._target, self._clientSecurity, rss.createRecorder(os.path.join(self._ouputDir, "%s_%s_%s.rss" % (time.strftime('%Y%m%d%H%M%S'), addr.host, self._uniqueId))))
class ProxyClient(rdp.RDPClientObserver): class ProxyClient(rdp.RDPClientObserver):
""" """
@summary: Client side of proxy @summary: Client side of proxy
""" """
def __init__(self, controller, server): def __init__(self, controller, server):
""" """
@param controller: {rdp.RDPClientController} @param controller: {rdp.RDPClientController}
@@ -176,7 +188,15 @@ class ProxyClient(rdp.RDPClientObserver):
""" """
self._server.setClient(self) self._server.setClient(self)
# maybe color depth change # maybe color depth change
self._server._controller.setColorDepth(self._controller.getColorDepth()) self._server._controller.setColorDepth(
self._controller.getColorDepth())
def onSessionReady(self):
"""
@summary: Windows session is ready
@see: rdp.RDPClientObserver.onSessionReady
"""
pass
def onClose(self): def onClose(self):
""" """
@@ -201,13 +221,17 @@ class ProxyClient(rdp.RDPClientObserver):
@param data: {str} bitmap data @param data: {str} bitmap data
@see: rdp.RDPClientObserver.onUpdate @see: rdp.RDPClientObserver.onUpdate
""" """
self._server._rss.update(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, rss.UpdateFormat.BMP if isCompress else rss.UpdateFormat.RAW, data) self._server._rss.update(destLeft, destTop, destRight, destBottom, width, height,
self._server._controller.sendUpdate(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data) bitsPerPixel, rss.UpdateFormat.BMP if isCompress else rss.UpdateFormat.RAW, data)
self._server._controller.sendUpdate(
destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data)
class ProxyClientFactory(rdp.ClientFactory): class ProxyClientFactory(rdp.ClientFactory):
""" """
@summary: Factory for proxy client @summary: Factory for proxy client
""" """
def __init__(self, server, width, height, domain, username, password, security): def __init__(self, server, width, height, domain, username, password, security):
""" """
@param server: {ProxyServer} @param server: {ProxyServer}
@@ -244,59 +268,55 @@ class ProxyClientFactory(rdp.ClientFactory):
controller.setPerformanceSession() controller.setPerformanceSession()
return ProxyClient(controller, self._server) return ProxyClient(controller, self._server)
def help():
"""
@summary: Print help in console
"""
print """
Usage: rdpy-rdpmitm.py -o output_directory target
[-l listen_port default 3389]
[-k private_key_file_path (mandatory for SSL)]
[-c certificate_file_path (mandatory for SSL)]
[-o output directory for recoded files]
[-r RDP standard security (XP or server 2003 client or older)]
[-n For NLA Client authentication (need to provide credentials)]
"""
def parseIpPort(interface, defaultPort="3389"): def parseIpPort(interface, defaultPort="3389"):
if ':' in interface: if ':' in interface:
return interface.split(':') s = interface.split(':')
return s[0], int(s[1])
else: else:
return interface, defaultPort return interface, int(defaultPort)
def isDirectory(outputDirectory):
if outputDirectory is None or not os.path.dirname(outputDirectory):
log.error("{} is an invalid output directory or directory doesn't exist".format(
outputDirectory))
return outputDirectory
def mapSecurityLayer(layer):
return {
"rdp": rdp.SecurityLevel.RDP_LEVEL_RDP,
"tls": rdp.SecurityLevel.RDP_LEVEL_SSL,
"nla": rdp.SecurityLevel.RDP_LEVEL_NLA
}[layer]
if __name__ == '__main__': if __name__ == '__main__':
listen = "3389" p = argparse.ArgumentParser(
privateKeyFilePath = None formatter_class=argparse.ArgumentDefaultsHelpFormatter)
certificateFilePath = None
ouputDirectory = None
#for anonymous authentication
clientSecurity = rdp.SecurityLevel.RDP_LEVEL_SSL
try: p.add_argument('-l', '--listen', type=parseIpPort, default="0.0.0.0:3389",
opts, args = getopt.getopt(sys.argv[1:], "hl:k:c:o:rn") help="<addr>[:<port>] to bind the server")
except getopt.GetoptError: p.add_argument('-t', '--target', type=parseIpPort, required=True,
help() help="<addr>[:<port>] of the target you want to connect to via proxy")
for opt, arg in opts: p.add_argument('-o', '--output', type=isDirectory,
if opt == "-h": help="output directory", required=True)
help() p.add_argument('-s', '--sec', choices=["rdp", "tls", "nla"],
sys.exit() default="rdp", help="set protocol security layer")
elif opt == "-l": ssl = p.add_argument_group()
listen = arg ssl.add_argument('-c', '--certificate', help="certificate for TLS connections")
elif opt == "-k": ssl.add_argument('-k', '--key', help="private key of the given certificate for TLS connections")
privateKeyFilePath = arg
elif opt == "-c":
certificateFilePath = arg
elif opt == "-o":
ouputDirectory = arg
elif opt == "-r":
clientSecurity = rdp.SecurityLevel.RDP_LEVEL_RDP
elif opt == "-n":
clientSecurity = rdp.SecurityLevel.RDP_LEVEL_NLA
if ouputDirectory is None or not os.path.dirname(ouputDirectory): args = p.parse_args()
log.error("%s is an invalid output directory"%ouputDirectory)
help() if args.certificate and args.key and not args.sec == "nla":
sys.exit() args.sec = "tls"
log.info("running server on {addr}, using {sec} security layer, proxying to {target}".format(
addr=args.listen, sec=args.sec.upper(), target=args.target))
reactor.listenTCP(args.listen[1], ProxyServerFactory(
args.target, args.output, args.key, args.certificate, mapSecurityLayer(args.sec)),
interface=args.listen[0])
reactor.listenTCP(int(listen), ProxyServerFactory(parseIpPort(args[0]), ouputDirectory, privateKeyFilePath, certificateFilePath, clientSecurity))
reactor.run() reactor.run()

View File

@@ -23,24 +23,26 @@ example of use rdpy
take screenshot of login page take screenshot of login page
""" """
import sys, os, getopt import getopt
import sys
from PyQt4 import QtCore, QtGui from PyQt4 import QtGui
from rdpy.protocol.rdp import rdp from rdpy.core import rdp
from rdpy.ui.qt4 import RDPBitmapToQtImage from rdpy.ui.qt4 import RDPBitmapToQtImage
import rdpy.core.log as log import rdpy.core.log as log
from rdpy.core.error import RDPSecurityNegoFail from rdpy.core.error import RDPSecurityNegoFail
from twisted.internet import task
# set log level # set log level
log._LOG_LEVEL = log.Level.INFO log._LOG_LEVEL = log.Level.INFO
class RDPScreenShotFactory(rdp.ClientFactory): class RDPScreenShotFactory(rdp.ClientFactory):
""" """
@summary: Factory for screenshot exemple @summary: Factory for screenshot exemple
""" """
__INSTANCE__ = 0 __INSTANCE__ = 0
__STATE__ = [] __STATE__ = []
def __init__(self, reactor, app, width, height, path, timeout): def __init__(self, reactor, app, width, height, path, timeout):
""" """
@param reactor: twisted reactor @param reactor: twisted reactor
@@ -91,7 +93,6 @@ class RDPScreenShotFactory(rdp.ClientFactory):
self._reactor.stop() self._reactor.stop()
self._app.exit() self._app.exit()
def buildObserver(self, controller, addr): def buildObserver(self, controller, addr):
""" """
@summary: build ScreenShot observer @summary: build ScreenShot observer
@@ -136,6 +137,13 @@ class RDPScreenShotFactory(rdp.ClientFactory):
""" """
log.info("connected %s" % addr) log.info("connected %s" % addr)
def onSessionReady(self):
"""
@summary: Windows session is ready
@see: rdp.RDPClientObserver.onSessionReady
"""
pass
def onClose(self): def onClose(self):
""" """
@summary: callback use when RDP stack is closed @summary: callback use when RDP stack is closed
@@ -146,7 +154,7 @@ class RDPScreenShotFactory(rdp.ClientFactory):
def checkUpdate(self): def checkUpdate(self):
self._controller.close(); self._controller.close();
controller.setScreen(width, height); controller.setScreen(self._width, self._height);
controller.setSecurityLevel(self._security) controller.setSecurityLevel(self._security)
return ScreenShotObserver(controller, self._width, self._height, self._path, self._timeout, self._reactor) return ScreenShotObserver(controller, self._width, self._height, self._path, self._timeout, self._reactor)
@@ -180,6 +188,7 @@ def main(width, height, path, timeout, hosts):
app.exec_() app.exec_()
return RDPScreenShotFactory.__STATE__ return RDPScreenShotFactory.__STATE__
def help(): def help():
print "Usage: rdpy-rdpscreenshot [options] ip[:port]" print "Usage: rdpy-rdpscreenshot [options] ip[:port]"
print "\t-w: width of screen default value is 1024" print "\t-w: width of screen default value is 1024"

View File

@@ -939,9 +939,18 @@ static PyMethodDef rle_methods[] =
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };
PyMODINIT_FUNC static struct PyModuleDef rle =
initrle(void)
{ {
(void) Py_InitModule("rle", rle_methods); 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
PyInit_rle(void)
{
(void) PyModule_Create(&rle);
} }

View File

@@ -22,11 +22,11 @@
@see: http://msdn.microsoft.com/en-us/library/cc241880.aspx @see: http://msdn.microsoft.com/en-us/library/cc241880.aspx
""" """
from rdpy.core.type import CompositeType, CallableValue, UInt8, UInt16Le, UInt32Le, String, sizeof, FactoryType, ArrayType, Stream from rdpy.model.type import CompositeType, CallableValue, UInt8, UInt16Le, UInt32Le, Buffer, sizeof, FactoryType, ArrayType, Stream
from rdpy.core.error import InvalidExpectedDataException from rdpy.model.error import InvalidExpectedDataException
import rdpy.core.log as log import rdpy.model.log as log
import sec from rdpy.core import sec
from t125 import gcc from rdpy.core.t125 import gcc
from rdpy.security import rc4 from rdpy.security import rc4
from rdpy.security import rsa_wrapper as rsa from rdpy.security import rsa_wrapper as rsa
@@ -102,7 +102,7 @@ class LicenseBinaryBlob(CompositeType):
CompositeType.__init__(self, optional = optional) CompositeType.__init__(self, optional = optional)
self.wBlobType = UInt16Le(blobType, constant = True if blobType != BinaryBlobType.BB_ANY_BLOB else False) self.wBlobType = UInt16Le(blobType, constant = True if blobType != BinaryBlobType.BB_ANY_BLOB else False)
self.wBlobLen = UInt16Le(lambda:sizeof(self.blobData)) self.wBlobLen = UInt16Le(lambda:sizeof(self.blobData))
self.blobData = String(readLen = self.wBlobLen) self.blobData = Buffer(readLen = self.wBlobLen)
class LicensingErrorMessage(CompositeType): class LicensingErrorMessage(CompositeType):
""" """
@@ -127,10 +127,10 @@ class ProductInformation(CompositeType):
self.dwVersion = UInt32Le() self.dwVersion = UInt32Le()
self.cbCompanyName = UInt32Le(lambda:sizeof(self.pbCompanyName)) self.cbCompanyName = UInt32Le(lambda:sizeof(self.pbCompanyName))
#may contain "Microsoft Corporation" from server microsoft #may contain "Microsoft Corporation" from server microsoft
self.pbCompanyName = String("Microsoft Corporation", readLen = self.cbCompanyName, unicode = True) self.pbCompanyName = Buffer("Microsoft Corporation", readLen = self.cbCompanyName, unicode = True)
self.cbProductId = UInt32Le(lambda:sizeof(self.pbProductId)) self.cbProductId = UInt32Le(lambda:sizeof(self.pbProductId))
#may contain "A02" from microsoft license server #may contain "A02" from microsoft license server
self.pbProductId = String("A02", readLen = self.cbProductId, unicode = True) self.pbProductId = Buffer("A02", readLen = self.cbProductId, unicode = True)
class Scope(CompositeType): class Scope(CompositeType):
@@ -162,7 +162,7 @@ class ServerLicenseRequest(CompositeType):
def __init__(self, readLen = None): def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen) CompositeType.__init__(self, readLen = readLen)
self.serverRandom = String("\x00" * 32, readLen = CallableValue(32)) self.serverRandom = Buffer("\x00" * 32, readLen = CallableValue(32))
self.productInfo = ProductInformation() self.productInfo = ProductInformation()
self.keyExchangeList = LicenseBinaryBlob(BinaryBlobType.BB_KEY_EXCHG_ALG_BLOB) self.keyExchangeList = LicenseBinaryBlob(BinaryBlobType.BB_KEY_EXCHG_ALG_BLOB)
self.serverCertificate = LicenseBinaryBlob(BinaryBlobType.BB_CERTIFICATE_BLOB) self.serverCertificate = LicenseBinaryBlob(BinaryBlobType.BB_CERTIFICATE_BLOB)
@@ -183,7 +183,7 @@ class ClientNewLicenseRequest(CompositeType):
#pure microsoft client ;-) #pure microsoft client ;-)
#http://msdn.microsoft.com/en-us/library/1040af38-c733-4fb3-acd1-8db8cc979eda#id10 #http://msdn.microsoft.com/en-us/library/1040af38-c733-4fb3-acd1-8db8cc979eda#id10
self.platformId = UInt32Le(0x04000000 | 0x00010000) self.platformId = UInt32Le(0x04000000 | 0x00010000)
self.clientRandom = String("\x00" * 32, readLen = CallableValue(32)) self.clientRandom = Buffer("\x00" * 32, readLen = CallableValue(32))
self.encryptedPreMasterSecret = LicenseBinaryBlob(BinaryBlobType.BB_RANDOM_BLOB) self.encryptedPreMasterSecret = LicenseBinaryBlob(BinaryBlobType.BB_RANDOM_BLOB)
self.ClientUserName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_USER_NAME_BLOB) self.ClientUserName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_USER_NAME_BLOB)
self.ClientMachineName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_MACHINE_NAME_BLOB) self.ClientMachineName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_MACHINE_NAME_BLOB)
@@ -199,7 +199,7 @@ class ServerPlatformChallenge(CompositeType):
CompositeType.__init__(self, readLen = readLen) CompositeType.__init__(self, readLen = readLen)
self.connectFlags = UInt32Le() self.connectFlags = UInt32Le()
self.encryptedPlatformChallenge = LicenseBinaryBlob(BinaryBlobType.BB_ANY_BLOB) self.encryptedPlatformChallenge = LicenseBinaryBlob(BinaryBlobType.BB_ANY_BLOB)
self.MACData = String(readLen = CallableValue(16)) self.MACData = Buffer(readLen = CallableValue(16))
class ClientPLatformChallengeResponse(CompositeType): class ClientPLatformChallengeResponse(CompositeType):
""" """
@@ -212,7 +212,7 @@ class ClientPLatformChallengeResponse(CompositeType):
CompositeType.__init__(self, readLen = readLen) CompositeType.__init__(self, readLen = readLen)
self.encryptedPlatformChallengeResponse = LicenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB) self.encryptedPlatformChallengeResponse = LicenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB)
self.encryptedHWID = LicenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB) self.encryptedHWID = LicenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB)
self.MACData = String(readLen = CallableValue(16)) self.MACData = Buffer(readLen = CallableValue(16))
class LicPacket(CompositeType): class LicPacket(CompositeType):
""" """
@@ -234,7 +234,7 @@ class LicPacket(CompositeType):
if self.bMsgtype.value == c._MESSAGE_TYPE_: if self.bMsgtype.value == c._MESSAGE_TYPE_:
return c(readLen = self.wMsgSize - 4) return c(readLen = self.wMsgSize - 4)
log.debug("unknown license message : %s"%self.bMsgtype.value) log.debug("unknown license message : %s"%self.bMsgtype.value)
return String() return Buffer(readLen =self.wMsgSize - 4)
if message is None: if message is None:
message = FactoryType(LicensingMessageFactory) message = FactoryType(LicensingMessageFactory)
@@ -272,7 +272,7 @@ class LicenseManager(object):
@return true when license automata is finish @return true when license automata is finish
""" """
licPacket = LicPacket() licPacket = LicPacket()
s.readType(licPacket) s.read_type(licPacket)
#end of automata #end of automata
if licPacket.bMsgtype.value == MessageType.ERROR_ALERT and licPacket.licensingMessage.dwErrorCode.value == ErrorCode.STATUS_VALID_CLIENT and licPacket.licensingMessage.dwStateTransition.value == StateTransition.ST_NO_TRANSITION: if licPacket.bMsgtype.value == MessageType.ERROR_ALERT and licPacket.licensingMessage.dwErrorCode.value == ErrorCode.STATUS_VALID_CLIENT and licPacket.licensingMessage.dwStateTransition.value == StateTransition.ST_NO_TRANSITION:
@@ -308,7 +308,7 @@ class LicenseManager(object):
else: else:
s = Stream(licenseRequest.serverCertificate.blobData.value) s = Stream(licenseRequest.serverCertificate.blobData.value)
serverCertificate = gcc.ServerCertificate() serverCertificate = gcc.ServerCertificate()
s.readType(serverCertificate) s.read_type(serverCertificate)
#generate crypto values #generate crypto values
clientRandom = rsa.random(256) clientRandom = rsa.random(256)
@@ -340,7 +340,7 @@ class LicenseManager(object):
#generate hwid #generate hwid
s = Stream() s = Stream()
s.writeType((UInt32Le(2), String(self._hostname + self._username + "\x00" * 16))) s.write_type((UInt32Le(2), Buffer(self._hostname + self._username + "\x00" * 16)))
hwid = s.getvalue()[:20] hwid = s.getvalue()[:20]
message = ClientPLatformChallengeResponse() message = ClientPLatformChallengeResponse()

206
rdpy/core/nla/cssp.py Normal file
View File

@@ -0,0 +1,206 @@
#
# Copyright (c) 2014-2015 Sylvain Peyrefitte
#
# This file is part of rdpy.
#
# rdpy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
"""
@summary: Credential Security Support Provider
@see: https://msdn.microsoft.com/en-us/library/cc226764.aspx
"""
from pyasn1.type import namedtype, univ, tag
import pyasn1.codec.der.encoder as der_encoder
import pyasn1.codec.der.decoder as der_decoder
from rdpy.core.nla import sspi
from rdpy.model.message import Stream
from rdpy.model import error
from rdpy.security.x509 import X509Certificate
class NegoToken(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('negoToken', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
)
class NegoData(univ.SequenceOf):
"""
@summary: contain spnego ntlm of kerberos data
@see: https://msdn.microsoft.com/en-us/library/cc226781.aspx
"""
componentType = NegoToken()
class TSRequest(univ.Sequence):
"""
@summary: main structure
@see: https://msdn.microsoft.com/en-us/library/cc226780.aspx
"""
componentType = namedtype.NamedTypes(
namedtype.NamedType('version', univ.Integer().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.OptionalNamedType('negoTokens', NegoData().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
namedtype.OptionalNamedType('authInfo', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))),
namedtype.OptionalNamedType('pubKeyAuth', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))),
namedtype.OptionalNamedType('errorCode', univ.Integer().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4)))
)
class TSCredentials(univ.Sequence):
"""
@summary: contain user information
@see: https://msdn.microsoft.com/en-us/library/cc226782.aspx
"""
componentType = namedtype.NamedTypes(
namedtype.NamedType('credType', univ.Integer().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.NamedType('credentials', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
)
class TSPasswordCreds(univ.Sequence):
"""
@summary: contain username and password
@see: https://msdn.microsoft.com/en-us/library/cc226783.aspx
"""
componentType = namedtype.NamedTypes(
namedtype.NamedType('domainName', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.NamedType('userName', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
namedtype.NamedType('password', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)))
)
class TSCspDataDetail(univ.Sequence):
"""
@summary: smart card credentials
@see: https://msdn.microsoft.com/en-us/library/cc226785.aspx
"""
componentType = namedtype.NamedTypes(
namedtype.NamedType('keySpec', univ.Integer().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.OptionalNamedType('cardName', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
namedtype.OptionalNamedType('readerName', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))),
namedtype.OptionalNamedType('containerName', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))),
namedtype.OptionalNamedType('cspName', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4)))
)
class TSSmartCardCreds(univ.Sequence):
"""
@summary: smart card credentials
@see: https://msdn.microsoft.com/en-us/library/cc226784.aspx
"""
componentType = namedtype.NamedTypes(
namedtype.NamedType('pin', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.NamedType('cspData', TSCspDataDetail().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
namedtype.OptionalNamedType('userHint', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))),
namedtype.OptionalNamedType('domainHint', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3)))
)
def encode_der_trequest(nego_types=[], auth_info=None, pub_key_auth=None):
"""
@summary: create TSRequest from list of Type
@param nego_types: {list(Type)}
@param auth_info: {str} authentication info TSCredentials encrypted with authentication protocol
@param pub_key_auth: {str} public key encrypted with authentication protocol
@return: {str} TRequest der encoded
"""
negoData = NegoData().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))
#fill nego data tokens
i = 0
for negoType in nego_types:
s = Stream()
s.write_type(negoType)
negoToken = NegoToken()
negoToken.setComponentByPosition(0, s.getvalue())
negoData.setComponentByPosition(i, negoToken)
i += 1
request = TSRequest()
request.setComponentByName("version", univ.Integer(2).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
if i > 0:
request.setComponentByName("negoTokens", negoData)
if not auth_info is None:
request.setComponentByName("authInfo", univ.OctetString(auth_info).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)))
if not pub_key_auth is None:
request.setComponentByName("pubKeyAuth", univ.OctetString(pub_key_auth).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3)))
return der_encoder.encode(request)
def decode_der_trequest(s):
"""
@summary: Decode the stream as
@param s: {str}
"""
return der_decoder.decode(s, asn1Spec=TSRequest())[0]
def getNegoTokens(tRequest):
negoData = tRequest.getComponentByName("negoTokens")
return [Stream(negoData.getComponentByPosition(i).getComponentByPosition(0).asOctets()) for i in range(len(negoData))]
def encode_der_tcredentials(domain, username, password):
passwordCred = TSPasswordCreds()
passwordCred.setComponentByName("domainName", domain)
passwordCred.setComponentByName("userName", username)
passwordCred.setComponentByName("password", password)
credentials = TSCredentials()
credentials.setComponentByName("credType", 1)
credentials.setComponentByName("credentials", der_encoder.encode(passwordCred))
return der_encoder.encode(credentials)
async def connect(reader, writer, authentication_protocol: sspi.IAuthenticationProtocol):
"""
CSSP connection sequence
"""
# send negotiate message
writer.write(encode_der_trequest(nego_types=[authentication_protocol.getNegotiateMessage()]))
await writer.drain()
trequest = decode_der_trequest(await reader.read(1500))
message, interface = authentication_protocol.getAuthenticateMessage(getNegoTokens(trequest)[0])
# get binary certificate
# There is no other way to get certificate that have net been validated
peer_certificate = writer.transport._ssl_protocol._sslpipe.ssl_object._sslobj.getpeercert(True)
x509_certificate = der_decoder.decode(peer_certificate, asn1Spec=X509Certificate())[0]
public_key = x509_certificate.getComponentByName("tbsCertificate").getComponentByName("subjectPublicKeyInfo").getComponentByName("subjectPublicKey").asOctets()
# send back public key encrypted with NTLM
writer.write(encode_der_trequest(nego_types=[message], pub_key_auth=interface.GSS_WrapEx(public_key)))
await writer.drain()
# now check the increment
# sever must respond with the same key incremented to one
trequest = decode_der_trequest(await reader.read(1500))
public_key_inc = interface.GSS_UnWrapEx(trequest.getComponentByName("pubKeyAuth").asOctets())
if int.from_bytes(public_key, "little") + 1 != int.from_bytes(public_key_inc, "little"):
raise error.InvalidExpectedDataException("CSSP : Invalid public key increment")
domain, user, password = authentication_protocol.getEncodedCredentials()
writer.write(encode_der_trequest(auth_info=interface.GSS_WrapEx(encode_der_tcredentials(domain, user, password))))
await writer.drain()

View File

@@ -23,12 +23,13 @@
""" """
import hashlib, hmac, struct, datetime import hashlib, hmac, struct, datetime
import sspi from rdpy.core.nla import sspi
import rdpy.security.pyDes as pyDes import rdpy.security.pyDes as pyDes
import rdpy.security.rc4 as rc4 import rdpy.security.rc4 as rc4
from rdpy.security.rsa_wrapper import random from rdpy.security.rsa_wrapper import random
from rdpy.core.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt24Le, UInt32Le, sizeof, Stream from rdpy.model.message import CompositeType, Buffer, UInt8, UInt16Le, UInt24Le, UInt32Le, sizeof, Stream
from rdpy.core import filetimes, error from rdpy.model import filetimes, error
class MajorVersion(object): class MajorVersion(object):
""" """
@@ -38,6 +39,7 @@ class MajorVersion(object):
WINDOWS_MAJOR_VERSION_5 = 0x05 WINDOWS_MAJOR_VERSION_5 = 0x05
WINDOWS_MAJOR_VERSION_6 = 0x06 WINDOWS_MAJOR_VERSION_6 = 0x06
class MinorVersion(object): class MinorVersion(object):
""" """
@see: https://msdn.microsoft.com/en-us/library/cc236654.aspx @see: https://msdn.microsoft.com/en-us/library/cc236654.aspx
@@ -48,12 +50,14 @@ class MinorVersion(object):
WINDOWS_MINOR_VERSION_2 = 0x02 WINDOWS_MINOR_VERSION_2 = 0x02
WINDOWS_MINOR_VERSION_3 = 0x03 WINDOWS_MINOR_VERSION_3 = 0x03
class NTLMRevision(object): class NTLMRevision(object):
""" """
@see: https://msdn.microsoft.com/en-us/library/cc236654.aspx @see: https://msdn.microsoft.com/en-us/library/cc236654.aspx
""" """
NTLMSSP_REVISION_W2K3 = 0x0F NTLMSSP_REVISION_W2K3 = 0x0F
class Negotiate(object): class Negotiate(object):
""" """
@see: https://msdn.microsoft.com/en-us/library/cc236650.aspx @see: https://msdn.microsoft.com/en-us/library/cc236650.aspx
@@ -80,6 +84,7 @@ class Negotiate(object):
NTLM_NEGOTIATE_OEM = 0x00000002 NTLM_NEGOTIATE_OEM = 0x00000002
NTLMSSP_NEGOTIATE_UNICODE = 0x00000001 NTLMSSP_NEGOTIATE_UNICODE = 0x00000001
class AvId(object): class AvId(object):
""" """
@see: https://msdn.microsoft.com/en-us/library/cc236646.aspx @see: https://msdn.microsoft.com/en-us/library/cc236646.aspx
@@ -125,7 +130,7 @@ class AvPair(CompositeType):
CompositeType.__init__(self) CompositeType.__init__(self)
self.AvId = UInt16Le() self.AvId = UInt16Le()
self.AvLen = UInt16Le(lambda: sizeof(self.Value)) self.AvLen = UInt16Le(lambda: sizeof(self.Value))
self.Value = String(readLen = self.AvLen) self.Value = Buffer(read_len=lambda: self.AvLen.value)
class MessageSignatureEx(CompositeType): class MessageSignatureEx(CompositeType):
""" """
@@ -135,7 +140,7 @@ class MessageSignatureEx(CompositeType):
def __init__(self): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.Version = UInt32Le(0x00000001, constant = True) self.Version = UInt32Le(0x00000001, constant = True)
self.Checksum = String(readLen = CallableValue(8)) self.Checksum = Buffer(read_len=lambda: 8)
self.SeqNum = UInt32Le() self.SeqNum = UInt32Le()
class NegotiateMessage(CompositeType): class NegotiateMessage(CompositeType):
@@ -144,8 +149,8 @@ class NegotiateMessage(CompositeType):
@see: https://msdn.microsoft.com/en-us/library/cc236641.aspx @see: https://msdn.microsoft.com/en-us/library/cc236641.aspx
""" """
def __init__(self): def __init__(self):
CompositeType.__init__(self) super().__init__()
self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True) self.Signature = Buffer(b"NTLMSSP\x00", read_len=lambda: 8, constant=True)
self.MessageType = UInt32Le(0x00000001, constant=True) self.MessageType = UInt32Le(0x00000001, constant=True)
self.NegotiateFlags = UInt32Le() self.NegotiateFlags = UInt32Le()
@@ -160,7 +165,7 @@ class NegotiateMessage(CompositeType):
self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION)) self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION))
self.Payload = String() self.Payload = Buffer()
class ChallengeMessage(CompositeType): class ChallengeMessage(CompositeType):
""" """
@@ -169,7 +174,7 @@ class ChallengeMessage(CompositeType):
""" """
def __init__(self): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True) self.Signature = Buffer(b"NTLMSSP\x00", read_len=lambda: 8, constant=True)
self.MessageType = UInt32Le(0x00000002, constant=True) self.MessageType = UInt32Le(0x00000002, constant=True)
self.TargetNameLen = UInt16Le() self.TargetNameLen = UInt16Le()
@@ -178,15 +183,15 @@ class ChallengeMessage(CompositeType):
self.NegotiateFlags = UInt32Le() self.NegotiateFlags = UInt32Le()
self.ServerChallenge = String(readLen = CallableValue(8)) self.ServerChallenge = Buffer(read_len=lambda: 8)
self.Reserved = String("\x00" * 8, readLen = CallableValue(8)) self.Reserved = Buffer(b"\x00" * 8, read_len=lambda: 8)
self.TargetInfoLen = UInt16Le() self.TargetInfoLen = UInt16Le()
self.TargetInfoMaxLen = UInt16Le(lambda: self.TargetInfoLen.value) self.TargetInfoMaxLen = UInt16Le(lambda: self.TargetInfoLen.value)
self.TargetInfoBufferOffset = UInt32Le() self.TargetInfoBufferOffset = UInt32Le()
self.Version = Version(conditional=lambda: (self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION)) self.Version = Version(conditional=lambda: (self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION))
self.Payload = String() self.Payload = Buffer()
def getTargetName(self): def getTargetName(self):
return getPayLoadField(self, self.TargetNameLen.value, self.TargetNameBufferOffset.value) return getPayLoadField(self, self.TargetNameLen.value, self.TargetNameBufferOffset.value)
@@ -203,7 +208,7 @@ class ChallengeMessage(CompositeType):
s = Stream(self.getTargetInfo()) s = Stream(self.getTargetInfo())
while(True): while(True):
avPair = AvPair() avPair = AvPair()
s.readType(avPair) s.read_type(avPair)
if avPair.AvId.value == AvId.MsvAvEOL: if avPair.AvId.value == AvId.MsvAvEOL:
return result return result
result[avPair.AvId.value] = avPair.Value.value result[avPair.AvId.value] = avPair.Value.value
@@ -216,7 +221,7 @@ class AuthenticateMessage(CompositeType):
""" """
def __init__(self): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True) self.Signature = Buffer(b"NTLMSSP\x00", read_len=lambda: 8, constant = True)
self.MessageType = UInt32Le(0x00000003, constant=True) self.MessageType = UInt32Le(0x00000003, constant=True)
self.LmChallengeResponseLen = UInt16Le() self.LmChallengeResponseLen = UInt16Le()
@@ -246,8 +251,8 @@ class AuthenticateMessage(CompositeType):
self.NegotiateFlags = UInt32Le() self.NegotiateFlags = UInt32Le()
self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION)) self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION))
self.MIC = String("\x00" * 16, readLen = CallableValue(16)) self.MIC = Buffer(b"\x00" * 16, read_len=lambda: 16)
self.Payload = String() self.Payload = Buffer()
def getUserName(self): def getUserName(self):
return getPayLoadField(self, self.UserNameLen.value, self.UserNameBufferOffset.value) return getPayLoadField(self, self.UserNameLen.value, self.UserNameBufferOffset.value)
@@ -347,6 +352,7 @@ def DESL(key, 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] + "\x00" * 5, data)
def UNICODE(s): def UNICODE(s):
""" """
@param s: source @param s: source
@@ -354,6 +360,7 @@ def UNICODE(s):
""" """
return s.encode('utf-16le') return s.encode('utf-16le')
def MD4(s): def MD4(s):
""" """
@summary: compute the md4 sum @summary: compute the md4 sum
@@ -362,6 +369,7 @@ def MD4(s):
""" """
return hashlib.new('md4', s).digest() return hashlib.new('md4', s).digest()
def MD5(s): def MD5(s):
""" """
@summary: compute the md5 sum @summary: compute the md5 sum
@@ -370,13 +378,15 @@ def MD5(s):
""" """
return hashlib.new('md5', s).digest() return hashlib.new('md5', s).digest()
def Z(m): def Z(m):
""" """
@summary: fill m zero in string @summary: fill m zero in string
@param m: {int} size of string @param m: {int} size of string
@return: \x00 * m @return: \x00 * m
""" """
return "\x00" * m return b"\x00" * m
def RC4K(key, plaintext): def RC4K(key, plaintext):
""" """
@@ -387,6 +397,7 @@ def RC4K(key, plaintext):
""" """
return rc4.crypt(rc4.RC4Key(key), plaintext) return rc4.crypt(rc4.RC4Key(key), plaintext)
def KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge): def KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge):
""" """
@summary: Key eXchange Key for NTLMv2 @summary: Key eXchange Key for NTLMv2
@@ -397,17 +408,20 @@ def KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge):
""" """
return SessionBaseKey return SessionBaseKey
def SEALKEY(ExportedSessionKey, client): def SEALKEY(ExportedSessionKey, client):
if 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: 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): def SIGNKEY(ExportedSessionKey, client):
if 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: 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): def HMAC_MD5(key, data):
""" """
@@ -417,6 +431,7 @@ def HMAC_MD5(key, data):
""" """
return hmac.new(key, data, hashlib.md5).digest() return hmac.new(key, data, hashlib.md5).digest()
def NTOWFv2(Passwd, User, UserDom): def NTOWFv2(Passwd, User, UserDom):
""" """
@summary: Version 2 of NTLM hash function @summary: Version 2 of NTLM hash function
@@ -427,6 +442,7 @@ def NTOWFv2(Passwd, User, UserDom):
""" """
return HMAC_MD5(MD4(UNICODE(Passwd)), UNICODE(User.upper() + UserDom)) return HMAC_MD5(MD4(UNICODE(Passwd)), UNICODE(User.upper() + UserDom))
def LMOWFv2(Passwd, User, UserDom): def LMOWFv2(Passwd, User, UserDom):
""" """
@summary: Same as NTOWFv2 @summary: Same as NTOWFv2
@@ -437,14 +453,15 @@ def LMOWFv2(Passwd, User, UserDom):
""" """
return NTOWFv2(Passwd, User, UserDom) return NTOWFv2(Passwd, User, UserDom)
def ComputeResponsev2(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChallenge, Time, ServerName): def ComputeResponsev2(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChallenge, Time, ServerName):
""" """
@summary: process NTLMv2 Authenticate hash @summary: process NTLMv2 Authenticate hash
@param NegFlg: {int} Negotiation flags come from challenge message @param NegFlg: {int} Negotiation flags come from challenge message
@see: https://msdn.microsoft.com/en-us/library/cc236700.aspx @see: https://msdn.microsoft.com/en-us/library/cc236700.aspx
""" """
Responserversion = "\x01" Responserversion = b"\x01"
HiResponserversion = "\x01" HiResponserversion = b"\x01"
temp = Responserversion + HiResponserversion + Z(6) + Time + ClientChallenge + Z(4) + ServerName temp = Responserversion + HiResponserversion + Z(6) + Time + ClientChallenge + Z(4) + ServerName
NTProofStr = HMAC_MD5(ResponseKeyNT, ServerChallenge + temp) NTProofStr = HMAC_MD5(ResponseKeyNT, ServerChallenge + temp)
@@ -455,6 +472,7 @@ def ComputeResponsev2(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChall
return NtChallengeResponse, LmChallengeResponse, SessionBaseKey return NtChallengeResponse, LmChallengeResponse, SessionBaseKey
def MAC(handle, SigningKey, SeqNum, Message): def MAC(handle, SigningKey, SeqNum, Message):
""" """
@summary: generate signature for application message @summary: generate signature for application message
@@ -469,12 +487,13 @@ def MAC(handle, SigningKey, SeqNum, Message):
#write the SeqNum #write the SeqNum
s = Stream() s = Stream()
s.writeType(signature.SeqNum) s.write_type(signature.SeqNum)
signature.Checksum.value = rc4.crypt(handle, HMAC_MD5(SigningKey, s.getvalue() + Message)[:8]) signature.Checksum.value = rc4.crypt(handle, HMAC_MD5(SigningKey, s.getvalue() + Message)[:8])
return signature return signature
def MIC(ExportedSessionKey, negotiateMessage, challengeMessage, authenticateMessage): def MIC(ExportedSessionKey, negotiateMessage, challengeMessage, authenticateMessage):
""" """
@summary: Compute MIC signature @summary: Compute MIC signature
@@ -485,14 +504,15 @@ def MIC(ExportedSessionKey, negotiateMessage, challengeMessage, authenticateMess
@see: https://msdn.microsoft.com/en-us/library/cc236676.aspx @see: https://msdn.microsoft.com/en-us/library/cc236676.aspx
""" """
s = Stream() s = Stream()
s.writeType((negotiateMessage, challengeMessage, authenticateMessage)) s.write_type((negotiateMessage, challengeMessage, authenticateMessage))
return HMAC_MD5(ExportedSessionKey, s.getvalue()) return HMAC_MD5(ExportedSessionKey, s.getvalue())
class NTLMv2(sspi.IAuthenticationProtocol): class NTLMv2(sspi.IAuthenticationProtocol):
""" """
@summary: Handle NTLMv2 Authentication @summary: Handle NTLMv2 Authentication
""" """
def __init__(self, domain, user, password): def __init__(self, domain: str, user: str, password: str):
self._domain = domain self._domain = domain
self._user = user self._user = user
self._password = password self._password = password
@@ -530,7 +550,7 @@ class NTLMv2(sspi.IAuthenticationProtocol):
@see: https://msdn.microsoft.com/en-us/library/cc236676.aspx @see: https://msdn.microsoft.com/en-us/library/cc236676.aspx
""" """
self._challengeMessage = ChallengeMessage() self._challengeMessage = ChallengeMessage()
s.readType(self._challengeMessage) s.read_type(self._challengeMessage)
ServerChallenge = self._challengeMessage.ServerChallenge.value ServerChallenge = self._challengeMessage.ServerChallenge.value
ClientChallenge = random(64) ClientChallenge = random(64)
@@ -538,7 +558,7 @@ class NTLMv2(sspi.IAuthenticationProtocol):
computeMIC = False computeMIC = False
ServerName = self._challengeMessage.getTargetInfo() ServerName = self._challengeMessage.getTargetInfo()
infos = self._challengeMessage.getTargetInfoAsAvPairArray() infos = self._challengeMessage.getTargetInfoAsAvPairArray()
if infos.has_key(AvId.MsvAvTimestamp): if AvId.MsvAvTimestamp in infos.keys():
Timestamp = infos[AvId.MsvAvTimestamp] Timestamp = infos[AvId.MsvAvTimestamp]
computeMIC = True computeMIC = True
else: else:
@@ -554,7 +574,7 @@ class NTLMv2(sspi.IAuthenticationProtocol):
if self._challengeMessage.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_UNICODE: if self._challengeMessage.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_UNICODE:
self._enableUnicode = True self._enableUnicode = True
domain, user = UNICODE(domain), UNICODE(user) domain, user = UNICODE(domain), UNICODE(user)
self._authenticateMessage = createAuthenticationMessage(self._challengeMessage.NegotiateFlags.value, domain, user, NtChallengeResponse, LmChallengeResponse, EncryptedRandomSessionKey, "") self._authenticateMessage = createAuthenticationMessage(self._challengeMessage.NegotiateFlags.value, domain, user, NtChallengeResponse, LmChallengeResponse, EncryptedRandomSessionKey, b"")
if computeMIC: if computeMIC:
self._authenticateMessage.MIC.value = MIC(ExportedSessionKey, self._negotiateMessage, self._challengeMessage, self._authenticateMessage) self._authenticateMessage.MIC.value = MIC(ExportedSessionKey, self._negotiateMessage, self._challengeMessage, self._authenticateMessage)
@@ -608,7 +628,7 @@ class NTLMv2SecurityInterface(sspi.IGenericSecurityService):
signature = MAC(self._encryptHandle, self._signingKey, self._seqNum, data) signature = MAC(self._encryptHandle, self._signingKey, self._seqNum, data)
self._seqNum += 1 self._seqNum += 1
s = Stream() s = Stream()
s.writeType(signature) s.write_type(signature)
return s.getvalue() + encryptedData return s.getvalue() + encryptedData
def GSS_UnWrapEx(self, data): def GSS_UnWrapEx(self, data):
@@ -616,10 +636,7 @@ class NTLMv2SecurityInterface(sspi.IGenericSecurityService):
@summary: decrypt data with key exchange in Authentication protocol @summary: decrypt data with key exchange in Authentication protocol
@param data: {str} @param data: {str}
""" """
signature = MessageSignatureEx() signature, message = Stream(data).read_type((MessageSignatureEx(), Buffer()))
message = String()
s = Stream(data)
s.readType((signature, message))
#decrypt message #decrypt message
plaintextMessage = rc4.crypt(self._decryptHandle, message.value) plaintextMessage = rc4.crypt(self._decryptHandle, message.value)
@@ -627,7 +644,7 @@ class NTLMv2SecurityInterface(sspi.IGenericSecurityService):
# recompute checksum # recompute checksum
t = Stream() t = Stream()
t.writeType(signature.SeqNum) t.write_type(signature.SeqNum)
verify = HMAC_MD5(self._verifyKey, t.getvalue() + plaintextMessage)[:8] verify = HMAC_MD5(self._verifyKey, t.getvalue() + plaintextMessage)[:8]
if verify != checksum: if verify != checksum:
raise error.InvalidExpectedDataException("NTLMv2SecurityInterface : Invalid checksum") raise error.InvalidExpectedDataException("NTLMv2SecurityInterface : Invalid checksum")

View File

@@ -21,7 +21,7 @@
@summary: security service provider interface (Microsoft) @summary: security service provider interface (Microsoft)
""" """
from rdpy.core.error import CallPureVirtualFuntion from rdpy.model.error import CallPureVirtualFuntion
class IAuthenticationProtocol(object): class IAuthenticationProtocol(object):
""" """

View File

@@ -16,15 +16,16 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from rdpy.core.error import InvalidExpectedDataException from rdpy.model.error import InvalidExpectedDataException
import rdpy.core.log as log import rdpy.model.log as log
""" """
Definition of structure use for capabilities nego Definition of structure use for capabilities nego
Use in PDU layer Use in PDU layer
""" """
from rdpy.core.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType from rdpy.model.type import CompositeType, CallableValue, Buffer, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType
class CapsType(object): class CapsType(object):
""" """
@@ -240,7 +241,7 @@ class Capability(CompositeType):
return c(readLen = self.lengthCapability - 4) return c(readLen = self.lengthCapability - 4)
log.debug("unknown Capability type : %s"%hex(self.capabilitySetType.value)) log.debug("unknown Capability type : %s"%hex(self.capabilitySetType.value))
#read entire packet #read entire packet
return String(readLen = self.lengthCapability - 4) return Buffer(readLen =self.lengthCapability - 4)
if capability is None: if capability is None:
capability = FactoryType(CapabilityFactory) capability = FactoryType(CapabilityFactory)
@@ -308,7 +309,7 @@ class OrderCapability(CompositeType):
def __init__(self, readLen = None): def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen) CompositeType.__init__(self, readLen = readLen)
self.terminalDescriptor = String("\x00" * 16, readLen = CallableValue(16)) self.terminalDescriptor = Buffer("\x00" * 16, readLen = CallableValue(16))
self.pad4octetsA = UInt32Le(0) self.pad4octetsA = UInt32Le(0)
self.desktopSaveXGranularity = UInt16Le(1) self.desktopSaveXGranularity = UInt16Le(1)
self.desktopSaveYGranularity = UInt16Le(20) self.desktopSaveYGranularity = UInt16Le(20)
@@ -388,7 +389,7 @@ class InputCapability(CompositeType):
#same value as gcc.ClientCoreSettings.keyboardFnKeys #same value as gcc.ClientCoreSettings.keyboardFnKeys
self.keyboardFunctionKey = UInt32Le() self.keyboardFunctionKey = UInt32Le()
#same value as gcc.ClientCoreSettingrrs.imeFileName #same value as gcc.ClientCoreSettingrrs.imeFileName
self.imeFileName = String("\x00" * 64, readLen = CallableValue(64)) self.imeFileName = Buffer("\x00" * 64, readLen = CallableValue(64))
class BrushCapability(CompositeType): class BrushCapability(CompositeType):
""" """

View File

@@ -22,10 +22,10 @@ Implement the main graphic layer
In this layer are managed all mains bitmap update orders end user inputs In this layer are managed all mains bitmap update orders end user inputs
""" """
from rdpy.core.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType from rdpy.model.type import CompositeType, CallableValue, Buffer, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType
from rdpy.core.error import InvalidExpectedDataException from rdpy.model.error import InvalidExpectedDataException
import rdpy.core.log as log import rdpy.model.log as log
import caps, order from rdpy.core.pdu import caps, order
class PDUType(object): class PDUType(object):
""" """
@@ -161,6 +161,15 @@ class PointerFlag(object):
PTRFLAGS_BUTTON2 = 0x2000 PTRFLAGS_BUTTON2 = 0x2000
PTRFLAGS_BUTTON3 = 0x4000 PTRFLAGS_BUTTON3 = 0x4000
class PointerExFlag(object):
"""
@summary: Use in Pointer event
@see: https://msdn.microsoft.com/en-us/library/cc240587.aspx
"""
PTRXFLAGS_DOWN = 0x8000
PTRXFLAGS_BUTTON1 = 0x0001
PTRXFLAGS_BUTTON2 = 0x0002
class KeyboardFlag(object): class KeyboardFlag(object):
""" """
@summary: Use in scan code key event @summary: Use in scan code key event
@@ -202,6 +211,16 @@ class Display(object):
SUPPRESS_DISPLAY_UPDATES = 0x00 SUPPRESS_DISPLAY_UPDATES = 0x00
ALLOW_DISPLAY_UPDATES = 0x01 ALLOW_DISPLAY_UPDATES = 0x01
class ToogleFlag(object):
"""
@summary: Use to known state of keyboard
@see: https://msdn.microsoft.com/en-us/library/cc240588.aspx
"""
TS_SYNC_SCROLL_LOCK = 0x00000001
TS_SYNC_NUM_LOCK = 0x00000002
TS_SYNC_CAPS_LOCK = 0x00000004
TS_SYNC_KANA_LOCK = 0x00000008
class ErrorInfo(object): class ErrorInfo(object):
""" """
@summary: Error code use in Error info PDU @summary: Error code use in Error info PDU
@@ -413,8 +432,6 @@ class ErrorInfo(object):
ERRINFO_VCDATATOOLONG : "The size of a received Virtual Channel PDU (section 2.2.6.1) exceeds the chunking size specified in the Virtual Channel Capability Set (section 2.2.7.1.10).", ERRINFO_VCDATATOOLONG : "The size of a received Virtual Channel PDU (section 2.2.6.1) exceeds the chunking size specified in the Virtual Channel Capability Set (section 2.2.7.1.10).",
} }
class ShareControlHeader(CompositeType): class ShareControlHeader(CompositeType):
""" """
@summary: PDU share control header @summary: PDU share control header
@@ -461,10 +478,10 @@ class PDU(CompositeType):
""" """
for c in [DemandActivePDU, ConfirmActivePDU, DataPDU, DeactiveAllPDU]: for c in [DemandActivePDU, ConfirmActivePDU, DataPDU, DeactiveAllPDU]:
if self.shareControlHeader.pduType.value == c._PDUTYPE_: if self.shareControlHeader.pduType.value == c._PDUTYPE_:
return c() return c(readLen = CallableValue(self.shareControlHeader.totalLength.value - sizeof(self.shareControlHeader)))
log.debug("unknown PDU type : %s"%hex(self.shareControlHeader.pduType.value)) log.debug("unknown PDU type : %s"%hex(self.shareControlHeader.pduType.value))
#read entire packet #read entire packet
return String() return Buffer(readLen = CallableValue(self.shareControlHeader.totalLength.value - sizeof(self.shareControlHeader)))
if pduMessage is None: if pduMessage is None:
pduMessage = FactoryType(PDUMessageFactory) pduMessage = FactoryType(PDUMessageFactory)
@@ -481,12 +498,12 @@ class DemandActivePDU(CompositeType):
#may declare the PDU type #may declare the PDU type
_PDUTYPE_ = PDUType.PDUTYPE_DEMANDACTIVEPDU _PDUTYPE_ = PDUType.PDUTYPE_DEMANDACTIVEPDU
def __init__(self): def __init__(self, readLen = None):
CompositeType.__init__(self) CompositeType.__init__(self, readLen = readLen)
self.shareId = UInt32Le() self.shareId = UInt32Le()
self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor))
self.lengthCombinedCapabilities = UInt16Le(lambda:(sizeof(self.numberCapabilities) + sizeof(self.pad2Octets) + sizeof(self.capabilitySets))) self.lengthCombinedCapabilities = UInt16Le(lambda:(sizeof(self.numberCapabilities) + sizeof(self.pad2Octets) + sizeof(self.capabilitySets)))
self.sourceDescriptor = String("rdpy", readLen = self.lengthSourceDescriptor) self.sourceDescriptor = Buffer("rdpy", readLen = self.lengthSourceDescriptor)
self.numberCapabilities = UInt16Le(lambda:len(self.capabilitySets._array)) self.numberCapabilities = UInt16Le(lambda:len(self.capabilitySets._array))
self.pad2Octets = UInt16Le() self.pad2Octets = UInt16Le()
self.capabilitySets = ArrayType(caps.Capability, readLen = self.numberCapabilities) self.capabilitySets = ArrayType(caps.Capability, readLen = self.numberCapabilities)
@@ -500,13 +517,13 @@ class ConfirmActivePDU(CompositeType):
#may declare the PDU type #may declare the PDU type
_PDUTYPE_ = PDUType.PDUTYPE_CONFIRMACTIVEPDU _PDUTYPE_ = PDUType.PDUTYPE_CONFIRMACTIVEPDU
def __init__(self): def __init__(self, readLen = None):
CompositeType.__init__(self) CompositeType.__init__(self, readLen = readLen)
self.shareId = UInt32Le() self.shareId = UInt32Le()
self.originatorId = UInt16Le(0x03EA, constant = True) self.originatorId = UInt16Le(0x03EA, constant = True)
self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor))
self.lengthCombinedCapabilities = UInt16Le(lambda:(sizeof(self.numberCapabilities) + sizeof(self.pad2Octets) + sizeof(self.capabilitySets))) self.lengthCombinedCapabilities = UInt16Le(lambda:(sizeof(self.numberCapabilities) + sizeof(self.pad2Octets) + sizeof(self.capabilitySets)))
self.sourceDescriptor = String("rdpy", readLen = self.lengthSourceDescriptor) self.sourceDescriptor = Buffer("rdpy", readLen = self.lengthSourceDescriptor)
self.numberCapabilities = UInt16Le(lambda:len(self.capabilitySets._array)) self.numberCapabilities = UInt16Le(lambda:len(self.capabilitySets._array))
self.pad2Octets = UInt16Le() self.pad2Octets = UInt16Le()
self.capabilitySets = ArrayType(caps.Capability, readLen = self.numberCapabilities) self.capabilitySets = ArrayType(caps.Capability, readLen = self.numberCapabilities)
@@ -519,13 +536,13 @@ class DeactiveAllPDU(CompositeType):
#may declare the PDU type #may declare the PDU type
_PDUTYPE_ = PDUType.PDUTYPE_DEACTIVATEALLPDU _PDUTYPE_ = PDUType.PDUTYPE_DEACTIVATEALLPDU
def __init__(self): def __init__(self, readLen = None):
#in old version this packet is empty i don't know #in old version this packet is empty i don't know
#and not specified #and not specified
CompositeType.__init__(self, optional = True) CompositeType.__init__(self, optional = True, readLen = readLen)
self.shareId = UInt32Le() self.shareId = UInt32Le()
self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor))
self.sourceDescriptor = String("rdpy", readLen = self.lengthSourceDescriptor) self.sourceDescriptor = Buffer("rdpy", readLen = self.lengthSourceDescriptor)
class DataPDU(CompositeType): class DataPDU(CompositeType):
""" """
@@ -534,19 +551,19 @@ class DataPDU(CompositeType):
#may declare the PDU type #may declare the PDU type
_PDUTYPE_ = PDUType.PDUTYPE_DATAPDU _PDUTYPE_ = PDUType.PDUTYPE_DATAPDU
def __init__(self, pduData = None, shareId = 0): def __init__(self, pduData = None, shareId = 0, readLen = None):
CompositeType.__init__(self) CompositeType.__init__(self, readLen = readLen)
self.shareDataHeader = ShareDataHeader(lambda:sizeof(self), lambda:self.pduData.__class__._PDUTYPE2_, shareId) self.shareDataHeader = ShareDataHeader(lambda:sizeof(self), lambda:self.pduData.__class__._PDUTYPE2_, shareId)
def PDUDataFactory(): def PDUDataFactory():
""" """
@summary: Create object in accordance self.shareDataHeader.pduType2 value @summary: Create object in accordance self.shareDataHeader.pduType2 value
""" """
for c in [UpdateDataPDU, SynchronizeDataPDU, ControlDataPDU, ErrorInfoDataPDU, FontListDataPDU, FontMapDataPDU, PersistentListPDU, ClientInputEventPDU, ShutdownDeniedPDU, ShutdownRequestPDU, SupressOutputDataPDU]: for c in [UpdateDataPDU, SynchronizeDataPDU, ControlDataPDU, ErrorInfoDataPDU, FontListDataPDU, FontMapDataPDU, PersistentListPDU, ClientInputEventPDU, ShutdownDeniedPDU, ShutdownRequestPDU, SupressOutputDataPDU, SaveSessionInfoPDU]:
if self.shareDataHeader.pduType2.value == c._PDUTYPE2_: if self.shareDataHeader.pduType2.value == c._PDUTYPE2_:
return c() return c(readLen = CallableValue(readLen.value - sizeof(self.shareDataHeader)))
log.debug("unknown PDU data type : %s"%hex(self.shareDataHeader.pduType2.value)) log.debug("unknown PDU data type : %s"%hex(self.shareDataHeader.pduType2.value))
return String() return Buffer(readLen = CallableValue(readLen.value - sizeof(self.shareDataHeader)))
if pduData is None: if pduData is None:
pduData = FactoryType(PDUDataFactory) pduData = FactoryType(PDUDataFactory)
@@ -655,8 +672,8 @@ class PersistentListPDU(CompositeType):
""" """
_PDUTYPE2_ = PDUType2.PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST _PDUTYPE2_ = PDUType2.PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST
def __init__(self, userId = 0, shareId = 0): def __init__(self, userId = 0, shareId = 0, readLen = None):
CompositeType.__init__(self) CompositeType.__init__(self, readLen = readLen)
self.numEntriesCache0 = UInt16Le() self.numEntriesCache0 = UInt16Le()
self.numEntriesCache1 = UInt16Le() self.numEntriesCache1 = UInt16Le()
self.numEntriesCache2 = UInt16Le() self.numEntriesCache2 = UInt16Le()
@@ -679,8 +696,8 @@ class ClientInputEventPDU(CompositeType):
""" """
_PDUTYPE2_ = PDUType2.PDUTYPE2_INPUT _PDUTYPE2_ = PDUType2.PDUTYPE2_INPUT
def __init__(self): def __init__(self, readLen = None):
CompositeType.__init__(self) CompositeType.__init__(self, readLen = readLen)
self.numEvents = UInt16Le(lambda:len(self.slowPathInputEvents._array)) self.numEvents = UInt16Le(lambda:len(self.slowPathInputEvents._array))
self.pad2Octets = UInt16Le() self.pad2Octets = UInt16Le()
self.slowPathInputEvents = ArrayType(SlowPathInputEvent, readLen = self.numEvents) self.slowPathInputEvents = ArrayType(SlowPathInputEvent, readLen = self.numEvents)
@@ -691,8 +708,8 @@ class ShutdownRequestPDU(CompositeType):
client -> server client -> server
""" """
_PDUTYPE2_ = PDUType2.PDUTYPE2_SHUTDOWN_REQUEST _PDUTYPE2_ = PDUType2.PDUTYPE2_SHUTDOWN_REQUEST
def __init__(self): def __init__(self, readLen = None):
CompositeType.__init__(self) CompositeType.__init__(self, readLen = readLen)
class ShutdownDeniedPDU(CompositeType): class ShutdownDeniedPDU(CompositeType):
""" """
@@ -700,8 +717,8 @@ class ShutdownDeniedPDU(CompositeType):
server -> client server -> client
""" """
_PDUTYPE2_ = PDUType2.PDUTYPE2_SHUTDOWN_DENIED _PDUTYPE2_ = PDUType2.PDUTYPE2_SHUTDOWN_DENIED
def __init__(self): def __init__(self, readLen = None):
CompositeType.__init__(self) CompositeType.__init__(self, readLen = readLen)
class InclusiveRectangle(CompositeType): class InclusiveRectangle(CompositeType):
""" """
@@ -761,9 +778,9 @@ class UpdateDataPDU(CompositeType):
""" """
for c in [BitmapUpdateDataPDU]: for c in [BitmapUpdateDataPDU]:
if self.updateType.value == c._UPDATE_TYPE_: if self.updateType.value == c._UPDATE_TYPE_:
return c() return c(readLen = CallableValue(readLen.value - 2))
log.debug("unknown PDU update data type : %s"%hex(self.updateType.value)) log.debug("unknown PDU update data type : %s"%hex(self.updateType.value))
return String() return Buffer(readLen = CallableValue(readLen.value - 2))
if updateData is None: if updateData is None:
updateData = FactoryType(UpdateDataFactory, conditional = lambda:(self.updateType.value != UpdateType.UPDATETYPE_SYNCHRONIZE)) updateData = FactoryType(UpdateDataFactory, conditional = lambda:(self.updateType.value != UpdateType.UPDATETYPE_SYNCHRONIZE))
@@ -772,6 +789,18 @@ class UpdateDataPDU(CompositeType):
self.updateData = updateData self.updateData = updateData
class SaveSessionInfoPDU(CompositeType):
"""
@see: https://msdn.microsoft.com/en-us/library/cc240636.aspx
"""
_PDUTYPE2_ = PDUType2.PDUTYPE2_SAVE_SESSION_INFO
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.infoType = UInt32Le()
#TODO parse info data
self.infoData = Buffer()
class FastPathUpdatePDU(CompositeType): class FastPathUpdatePDU(CompositeType):
""" """
@summary: Fast path update PDU packet @summary: Fast path update PDU packet
@@ -789,9 +818,9 @@ class FastPathUpdatePDU(CompositeType):
""" """
for c in [FastPathBitmapUpdateDataPDU]: for c in [FastPathBitmapUpdateDataPDU]:
if (self.updateHeader.value & 0xf) == c._FASTPATH_UPDATE_TYPE_: if (self.updateHeader.value & 0xf) == c._FASTPATH_UPDATE_TYPE_:
return c() return c(readLen = self.size)
log.debug("unknown Fast Path PDU update data type : %s"%hex(self.updateHeader.value & 0xf)) log.debug("unknown Fast Path PDU update data type : %s"%hex(self.updateHeader.value & 0xf))
return String() return Buffer(readLen = self.size)
if updateData is None: if updateData is None:
updateData = FactoryType(UpdateDataFactory) updateData = FactoryType(UpdateDataFactory)
@@ -821,8 +850,8 @@ class OrderUpdateDataPDU(CompositeType):
@see: http://msdn.microsoft.com/en-us/library/cc241571.aspx @see: http://msdn.microsoft.com/en-us/library/cc241571.aspx
@todo: not implemented yet but need it @todo: not implemented yet but need it
""" """
def __init__(self): def __init__(self, readLen = None):
CompositeType.__init__(self) CompositeType.__init__(self, readLen = readLen)
self.pad2OctetsA = UInt16Le() self.pad2OctetsA = UInt16Le()
self.numberOrders = UInt16Le(lambda:len(self.orderData._array)) self.numberOrders = UInt16Le(lambda:len(self.orderData._array))
self.pad2OctetsB = UInt16Le() self.pad2OctetsB = UInt16Le()
@@ -873,7 +902,7 @@ class BitmapData(CompositeType):
self.flags = UInt16Le() self.flags = UInt16Le()
self.bitmapLength = UInt16Le(lambda:(sizeof(self.bitmapComprHdr) + sizeof(self.bitmapDataStream))) self.bitmapLength = UInt16Le(lambda:(sizeof(self.bitmapComprHdr) + sizeof(self.bitmapDataStream)))
self.bitmapComprHdr = BitmapCompressedDataHeader(bodySize = lambda:sizeof(self.bitmapDataStream), scanWidth = lambda:self.width.value, uncompressedSize = lambda:(self.width.value * self.height.value * self.bitsPerPixel.value), conditional = lambda:((self.flags.value & BitmapFlag.BITMAP_COMPRESSION) and not (self.flags.value & BitmapFlag.NO_BITMAP_COMPRESSION_HDR))) self.bitmapComprHdr = BitmapCompressedDataHeader(bodySize = lambda:sizeof(self.bitmapDataStream), scanWidth = lambda:self.width.value, uncompressedSize = lambda:(self.width.value * self.height.value * self.bitsPerPixel.value), conditional = lambda:((self.flags.value & BitmapFlag.BITMAP_COMPRESSION) and not (self.flags.value & BitmapFlag.NO_BITMAP_COMPRESSION_HDR)))
self.bitmapDataStream = String(bitmapDataStream, readLen = CallableValue(lambda:(self.bitmapLength.value if (not self.flags.value & BitmapFlag.BITMAP_COMPRESSION or self.flags.value & BitmapFlag.NO_BITMAP_COMPRESSION_HDR) else self.bitmapComprHdr.cbCompMainBodySize.value))) self.bitmapDataStream = Buffer(bitmapDataStream, readLen = CallableValue(lambda:(self.bitmapLength.value if (not self.flags.value & BitmapFlag.BITMAP_COMPRESSION or self.flags.value & BitmapFlag.NO_BITMAP_COMPRESSION_HDR) else self.bitmapComprHdr.cbCompMainBodySize.value)))
class FastPathBitmapUpdateDataPDU(CompositeType): class FastPathBitmapUpdateDataPDU(CompositeType):
""" """
@@ -882,8 +911,8 @@ class FastPathBitmapUpdateDataPDU(CompositeType):
""" """
_FASTPATH_UPDATE_TYPE_ = FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP _FASTPATH_UPDATE_TYPE_ = FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP
def __init__(self): def __init__(self, readLen = None):
CompositeType.__init__(self) CompositeType.__init__(self, readLen = readLen)
self.header = UInt16Le(FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP, constant = True) self.header = UInt16Le(FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP, constant = True)
self.numberRectangles = UInt16Le(lambda:len(self.rectangles._array)) self.numberRectangles = UInt16Le(lambda:len(self.rectangles._array))
self.rectangles = ArrayType(BitmapData, readLen = self.numberRectangles) self.rectangles = ArrayType(BitmapData, readLen = self.numberRectangles)
@@ -899,11 +928,10 @@ class SlowPathInputEvent(CompositeType):
self.messageType = UInt16Le(lambda:self.slowPathInputData.__class__._INPUT_MESSAGE_TYPE_) self.messageType = UInt16Le(lambda:self.slowPathInputData.__class__._INPUT_MESSAGE_TYPE_)
def SlowPathInputDataFactory(): def SlowPathInputDataFactory():
for c in [PointerEvent, ScancodeKeyEvent, UnicodeKeyEvent]: for c in [PointerEvent, PointerExEvent, ScancodeKeyEvent, UnicodeKeyEvent, SynchronizeEvent]:
if self.messageType.value == c._INPUT_MESSAGE_TYPE_: if self.messageType.value == c._INPUT_MESSAGE_TYPE_:
return c() return c()
log.debug("unknown slow path input : %s"%hex(self.messageType.value)) raise InvalidExpectedDataException("unknown slow path input : %s"%hex(self.messageType.value))
return String()
if messageData is None: if messageData is None:
messageData = FactoryType(SlowPathInputDataFactory) messageData = FactoryType(SlowPathInputDataFactory)
@@ -912,6 +940,18 @@ class SlowPathInputEvent(CompositeType):
self.slowPathInputData = messageData self.slowPathInputData = messageData
class SynchronizeEvent(CompositeType):
"""
@summary: Synchronize keyboard
@see: https://msdn.microsoft.com/en-us/library/cc240588.aspx
"""
_INPUT_MESSAGE_TYPE_ = InputMessageType.INPUT_EVENT_SYNC
def __init__(self):
CompositeType.__init__(self)
self.pad2Octets = UInt16Le()
self.toggleFlags = UInt32Le()
class PointerEvent(CompositeType): class PointerEvent(CompositeType):
""" """
@summary: Event use to communicate mouse position @summary: Event use to communicate mouse position
@@ -925,6 +965,19 @@ class PointerEvent(CompositeType):
self.xPos = UInt16Le() self.xPos = UInt16Le()
self.yPos = UInt16Le() self.yPos = UInt16Le()
class PointerExEvent(CompositeType):
"""
@summary: Event use to communicate mouse position
@see: http://msdn.microsoft.com/en-us/library/cc240587.aspx
"""
_INPUT_MESSAGE_TYPE_ = InputMessageType.INPUT_EVENT_MOUSEX
def __init__(self):
CompositeType.__init__(self)
self.pointerFlags = UInt16Le()
self.xPos = UInt16Le()
self.yPos = UInt16Le()
class ScancodeKeyEvent(CompositeType): class ScancodeKeyEvent(CompositeType):
""" """
@summary: Event use to communicate keyboard informations @summary: Event use to communicate keyboard informations

View File

@@ -23,11 +23,13 @@ Implement the main graphic layer
In this layer are managed all mains bitmap update orders end user inputs In this layer are managed all mains bitmap update orders end user inputs
""" """
from rdpy.core.layer import LayerAutomata from rdpy.model.layer import LayerAutomata
from rdpy.core.error import CallPureVirtualFuntion from rdpy.model.error import CallPureVirtualFuntion
import rdpy.core.log as log from rdpy.model.type import ArrayType
import rdpy.protocol.rdp.tpkt as tpkt import rdpy.model.log as log
import data, caps from rdpy.core import tpkt
from rdpy.core.pdu import data, caps
class PDUClientListener(object): class PDUClientListener(object):
""" """
@@ -39,6 +41,13 @@ class PDUClientListener(object):
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "PDUClientListener")) raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "PDUClientListener"))
def onSessionReady(self):
"""
@summary: Event call when Windows session is ready
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onSessionReady", "PDUClientListener"))
def onUpdate(self, rectangles): def onUpdate(self, rectangles):
""" """
@summary: call when a bitmap data is received from update PDU @summary: call when a bitmap data is received from update PDU
@@ -167,7 +176,7 @@ class Client(PDULayer):
@param s: Stream @param s: Stream
""" """
pdu = data.PDU() pdu = data.PDU()
s.readType(pdu) s.read_type(pdu)
if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DEMANDACTIVEPDU: if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DEMANDACTIVEPDU:
#not a blocking error because in deactive reactive sequence #not a blocking error because in deactive reactive sequence
@@ -195,7 +204,7 @@ class Client(PDULayer):
@param s: Stream from transport layer @param s: Stream from transport layer
""" """
pdu = data.PDU() pdu = data.PDU()
s.readType(pdu) s.read_type(pdu)
if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_SYNCHRONIZE: if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_SYNCHRONIZE:
#not a blocking error because in deactive reactive sequence #not a blocking error because in deactive reactive sequence
#input can be send too but ignored #input can be send too but ignored
@@ -211,7 +220,7 @@ class Client(PDULayer):
@param s: Stream from transport layer @param s: Stream from transport layer
""" """
pdu = data.PDU() pdu = data.PDU()
s.readType(pdu) s.read_type(pdu)
if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_CONTROL or pdu.pduMessage.pduData.action.value != data.Action.CTRLACTION_COOPERATE: if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_CONTROL or pdu.pduMessage.pduData.action.value != data.Action.CTRLACTION_COOPERATE:
#not a blocking error because in deactive reactive sequence #not a blocking error because in deactive reactive sequence
#input can be send too but ignored #input can be send too but ignored
@@ -227,7 +236,7 @@ class Client(PDULayer):
@param s: Stream from transport layer @param s: Stream from transport layer
""" """
pdu = data.PDU() pdu = data.PDU()
s.readType(pdu) s.read_type(pdu)
if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_CONTROL or pdu.pduMessage.pduData.action.value != data.Action.CTRLACTION_GRANTED_CONTROL: if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_CONTROL or pdu.pduMessage.pduData.action.value != data.Action.CTRLACTION_GRANTED_CONTROL:
#not a blocking error because in deactive reactive sequence #not a blocking error because in deactive reactive sequence
#input can be send too but ignored #input can be send too but ignored
@@ -243,7 +252,7 @@ class Client(PDULayer):
@param s: Stream from transport layer @param s: Stream from transport layer
""" """
pdu = data.PDU() pdu = data.PDU()
s.readType(pdu) s.read_type(pdu)
if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_FONTMAP: if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_FONTMAP:
#not a blocking error because in deactive reactive sequence #not a blocking error because in deactive reactive sequence
#input can be send too but ignored #input can be send too but ignored
@@ -259,8 +268,9 @@ class Client(PDULayer):
@summary: Main receive function after connection sequence @summary: Main receive function after connection sequence
@param s: Stream from transport layer @param s: Stream from transport layer
""" """
pdu = data.PDU() pdus = ArrayType(data.PDU)
s.readType(pdu) s.read_type(pdus)
for pdu in pdus:
if pdu.shareControlHeader.pduType.value == data.PDUType.PDUTYPE_DATAPDU: if pdu.shareControlHeader.pduType.value == data.PDUType.PDUTYPE_DATAPDU:
self.readDataPDU(pdu.pduMessage) self.readDataPDU(pdu.pduMessage)
elif pdu.shareControlHeader.pduType.value == data.PDUType.PDUTYPE_DEACTIVATEALLPDU: elif pdu.shareControlHeader.pduType.value == data.PDUType.PDUTYPE_DEACTIVATEALLPDU:
@@ -276,10 +286,11 @@ class Client(PDULayer):
@param fastPathS: {Stream} that contain fast path data @param fastPathS: {Stream} that contain fast path data
@param secFlag: {SecFlags} @param secFlag: {SecFlags}
""" """
fastPathPDU = data.FastPathUpdatePDU() updates = ArrayType(data.FastPathUpdatePDU)
fastPathS.readType(fastPathPDU) fastPathS.read_type(updates)
if fastPathPDU.updateHeader.value == data.FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP: for update in updates:
self._listener.onUpdate(fastPathPDU.updateData.rectangles._array) if update.updateHeader.value == data.FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP:
self._listener.onUpdate(update.updateData.rectangles._array)
def readDataPDU(self, dataPDU): def readDataPDU(self, dataPDU):
""" """
@@ -298,6 +309,9 @@ class Client(PDULayer):
elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SHUTDOWN_DENIED: elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SHUTDOWN_DENIED:
#may be an event to ask to user #may be an event to ask to user
self._transport.close() self._transport.close()
elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SAVE_SESSION_INFO:
#handle session event
self._listener.onSessionReady()
elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_UPDATE: elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_UPDATE:
self.readUpdateDataPDU(dataPDU.pduData) self.readUpdateDataPDU(dataPDU.pduData)
@@ -405,7 +419,7 @@ class Server(PDULayer):
@param s: Stream @param s: Stream
""" """
pdu = data.PDU() pdu = data.PDU()
s.readType(pdu) s.read_type(pdu)
if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_CONFIRMACTIVEPDU: if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_CONFIRMACTIVEPDU:
#not a blocking error because in deactive reactive sequence #not a blocking error because in deactive reactive sequence
@@ -431,7 +445,7 @@ class Server(PDULayer):
@param s: Stream from transport layer @param s: Stream from transport layer
""" """
pdu = data.PDU() pdu = data.PDU()
s.readType(pdu) s.read_type(pdu)
if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_SYNCHRONIZE: if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_SYNCHRONIZE:
#not a blocking error because in deactive reactive sequence #not a blocking error because in deactive reactive sequence
#input can be send too but ignored #input can be send too but ignored
@@ -446,7 +460,7 @@ class Server(PDULayer):
@param s: Stream from transport layer @param s: Stream from transport layer
""" """
pdu = data.PDU() pdu = data.PDU()
s.readType(pdu) s.read_type(pdu)
if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_CONTROL or pdu.pduMessage.pduData.action.value != data.Action.CTRLACTION_COOPERATE: if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_CONTROL or pdu.pduMessage.pduData.action.value != data.Action.CTRLACTION_COOPERATE:
#not a blocking error because in deactive reactive sequence #not a blocking error because in deactive reactive sequence
#input can be send too but ignored #input can be send too but ignored
@@ -461,7 +475,7 @@ class Server(PDULayer):
@param s: Stream from transport layer @param s: Stream from transport layer
""" """
pdu = data.PDU() pdu = data.PDU()
s.readType(pdu) s.read_type(pdu)
if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_CONTROL or pdu.pduMessage.pduData.action.value != data.Action.CTRLACTION_REQUEST_CONTROL: if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_CONTROL or pdu.pduMessage.pduData.action.value != data.Action.CTRLACTION_REQUEST_CONTROL:
#not a blocking error because in deactive reactive sequence #not a blocking error because in deactive reactive sequence
#input can be send too but ignored #input can be send too but ignored
@@ -477,7 +491,7 @@ class Server(PDULayer):
@param s: Stream from transport layer @param s: Stream from transport layer
""" """
pdu = data.PDU() pdu = data.PDU()
s.readType(pdu) s.read_type(pdu)
if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_FONTLIST: if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_FONTLIST:
#not a blocking error because in deactive reactive sequence #not a blocking error because in deactive reactive sequence
#input can be send but ignored #input can be send but ignored
@@ -496,7 +510,7 @@ class Server(PDULayer):
@param s: Stream from transport layer @param s: Stream from transport layer
""" """
pdu = data.PDU() pdu = data.PDU()
s.readType(pdu) s.read_type(pdu)
if pdu.shareControlHeader.pduType.value == data.PDUType.PDUTYPE_DATAPDU: if pdu.shareControlHeader.pduType.value == data.PDUType.PDUTYPE_DATAPDU:
self.readDataPDU(pdu.pduMessage) self.readDataPDU(pdu.pduMessage)

View File

@@ -21,9 +21,9 @@
GDI order structure GDI order structure
""" """
from rdpy.core import log from rdpy.model import log
from rdpy.core.error import InvalidExpectedDataException from rdpy.model.error import InvalidExpectedDataException
from rdpy.core.type import CompositeType, UInt8, String, FactoryType, SInt8, SInt16Le from rdpy.model.type import CompositeType, UInt8, Buffer, FactoryType, SInt8, SInt16Le
class ControlFlag(object): class ControlFlag(object):
""" """
@@ -100,7 +100,7 @@ class PrimaryDrawingOrder(CompositeType):
return c(self.controlFlags) return c(self.controlFlags)
log.debug("unknown Order type : %s"%hex(self.orderType.value)) log.debug("unknown Order type : %s"%hex(self.orderType.value))
#read entire packet #read entire packet
return String() return Buffer()
if order is None: if order is None:
order = FactoryType(OrderFactory) order = FactoryType(OrderFactory)

View File

@@ -21,15 +21,19 @@
Use to manage RDP stack in twisted Use to manage RDP stack in twisted
""" """
from rdpy.core import layer from rdpy.model import layer
from rdpy.core.error import CallPureVirtualFuntion, InvalidValue from rdpy.model.error import CallPureVirtualFuntion, InvalidValue
import pdu.layer from rdpy.core.pdu.layer import PDUClientListener, PDUServerListener
import pdu.data from rdpy.core.pdu import data
import pdu.caps from rdpy.core.pdu import caps
import rdpy.core.log as log from rdpy.core.pdu import layer as pdu
import tpkt, x224, sec import rdpy.model.log as log
from t125 import mcs, gcc import rdpy.core.tpkt as tpkt
from nla import cssp, ntlm import rdpy.core.x224 as x224
import rdpy.core.sec as sec
from rdpy.core.t125 import mcs, gcc
from rdpy.core.nla import cssp, ntlm
class SecurityLevel(object): class SecurityLevel(object):
""" """
@@ -39,7 +43,8 @@ class SecurityLevel(object):
RDP_LEVEL_SSL = 1 RDP_LEVEL_SSL = 1
RDP_LEVEL_NLA = 2 RDP_LEVEL_NLA = 2
class RDPClientController(pdu.layer.PDUClientListener):
class RDPClientController(PDUClientListener):
""" """
Manage RDP stack as client Manage RDP stack as client
""" """
@@ -47,7 +52,7 @@ class RDPClientController(pdu.layer.PDUClientListener):
#list of observer #list of observer
self._clientObserver = [] self._clientObserver = []
#PDU layer #PDU layer
self._pduLayer = pdu.layer.Client(self) self._pduLayer = pdu.Client(self)
#secure layer #secure layer
self._secLayer = sec.Client(self._pduLayer) self._secLayer = sec.Client(self._pduLayer)
#multi channel service #multi channel service
@@ -94,13 +99,13 @@ class RDPClientController(pdu.layer.PDUClientListener):
@param height: height in pixel of screen @param height: height in pixel of screen
""" """
#set screen definition in MCS layer #set screen definition in MCS layer
self._mcsLayer._clientSettings.getBlock(gcc.MessageType.CS_CORE).desktopHeight.value = height self._mcsLayer._clientSettings.get_block(gcc.MessageType.CS_CORE).desktopHeight.value = height
self._mcsLayer._clientSettings.getBlock(gcc.MessageType.CS_CORE).desktopWidth.value = width self._mcsLayer._clientSettings.get_block(gcc.MessageType.CS_CORE).desktopWidth.value = width
def setUsername(self, username): def setUsername(self, username):
""" """
@summary: Set the username for session @summary: Set the username for session
@param username: username of session @param username: {string} username of session
""" """
#username in PDU info packet #username in PDU info packet
self._secLayer._info.userName.value = username self._secLayer._info.userName.value = username
@@ -109,7 +114,7 @@ class RDPClientController(pdu.layer.PDUClientListener):
def setPassword(self, password): def setPassword(self, password):
""" """
@summary: Set password for session @summary: Set password for session
@param password: password of session @param password: {string} password of session
""" """
self.setAutologon() self.setAutologon()
self._secLayer._info.password.value = password self._secLayer._info.password.value = password
@@ -117,7 +122,7 @@ class RDPClientController(pdu.layer.PDUClientListener):
def setDomain(self, domain): def setDomain(self, domain):
""" """
@summary: Set the windows domain of session @summary: Set the windows domain of session
@param domain: domain of session @param domain: {string} domain of session
""" """
self._secLayer._info.domain.value = domain self._secLayer._info.domain.value = domain
@@ -127,6 +132,13 @@ class RDPClientController(pdu.layer.PDUClientListener):
""" """
self._secLayer._info.flag |= sec.InfoFlag.INFO_AUTOLOGON self._secLayer._info.flag |= sec.InfoFlag.INFO_AUTOLOGON
def setAlternateShell(self, appName):
"""
@summary: set application name of app which start at the begining of session
@param appName: {string} application name
"""
self._secLayer._info.alternateShell.value = appName
def setKeyboardLayout(self, layout): def setKeyboardLayout(self, layout):
""" """
@summary: keyboard layout @summary: keyboard layout
@@ -192,6 +204,15 @@ class RDPClientController(pdu.layer.PDUClientListener):
for observer in self._clientObserver: for observer in self._clientObserver:
observer.onReady() observer.onReady()
def onSessionReady(self):
"""
@summary: Call when Windows session is ready (connected)
"""
self._isReady = True
#signal all listener
for observer in self._clientObserver:
observer.onSessionReady()
def onClose(self): def onClose(self):
""" """
@summary: Event call when RDP stack is closed @summary: Event call when RDP stack is closed
@@ -212,6 +233,17 @@ class RDPClientController(pdu.layer.PDUClientListener):
return return
try: try:
if button == 4 or button == 5:
event = pdu.data.PointerExEvent()
if isPressed:
event.pointerFlags.value |= pdu.data.PointerExFlag.PTRXFLAGS_DOWN
if button == 4:
event.pointerFlags.value |= pdu.data.PointerExFlag.PTRXFLAGS_BUTTON1
elif button == 5:
event.pointerFlags.value |= pdu.data.PointerExFlag.PTRXFLAGS_BUTTON2
else:
event = pdu.data.PointerEvent() event = pdu.data.PointerEvent()
if isPressed: if isPressed:
event.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_DOWN event.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_DOWN
@@ -269,11 +301,12 @@ class RDPClientController(pdu.layer.PDUClientListener):
except InvalidValue: except InvalidValue:
log.info("try send wheel event with incorrect position") log.info("try send wheel event with incorrect position")
def sendKeyEventScancode(self, code, isPressed): def sendKeyEventScancode(self, code, isPressed, extended = False):
""" """
@summary: Send a scan code to RDP stack @summary: Send a scan code to RDP stack
@param code: scan code @param code: scan code
@param isPressed: True if key is pressed and false if it's released @param isPressed: True if key is pressed and false if it's released
@param extended: {boolean} extended scancode like ctr or win button
""" """
if not self._isReady: if not self._isReady:
return return
@@ -281,11 +314,12 @@ class RDPClientController(pdu.layer.PDUClientListener):
try: try:
event = pdu.data.ScancodeKeyEvent() event = pdu.data.ScancodeKeyEvent()
event.keyCode.value = code event.keyCode.value = code
if isPressed: if not isPressed:
event.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_DOWN
else:
event.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_RELEASE event.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_RELEASE
if extended:
event.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_EXTENDED
#send event #send event
self._pduLayer.sendInputEvents([event]) self._pduLayer.sendInputEvents([event])
@@ -336,7 +370,8 @@ class RDPClientController(pdu.layer.PDUClientListener):
""" """
self._pduLayer.close() self._pduLayer.close()
class RDPServerController(pdu.layer.PDUServerListener):
class RDPServerController(PDUServerListener):
""" """
@summary: Controller use in server side mode @summary: Controller use in server side mode
""" """
@@ -478,11 +513,11 @@ class RDPServerController(pdu.layer.PDUServerListener):
for event in slowPathInputEvents: for event in slowPathInputEvents:
#scan code #scan code
if event.messageType.value == pdu.data.InputMessageType.INPUT_EVENT_SCANCODE: if event.messageType.value == pdu.data.InputMessageType.INPUT_EVENT_SCANCODE:
observer.onKeyEventScancode(event.slowPathInputData.keyCode.value, not (event.slowPathInputData.keyboardFlags.value & pdu.data.KeyboardFlag.KBDFLAGS_RELEASE)) observer.onKeyEventScancode(event.slowPathInputData.keyCode.value, not (event.slowPathInputData.keyboardFlags.value & pdu.data.KeyboardFlag.KBDFLAGS_RELEASE), bool(event.slowPathInputData.keyboardFlags.value & pdu.data.KeyboardFlag.KBDFLAGS_EXTENDED))
#unicode #unicode
elif event.messageType.value == pdu.data.InputMessageType.INPUT_EVENT_UNICODE: elif event.messageType.value == pdu.data.InputMessageType.INPUT_EVENT_UNICODE:
observer.onKeyEventUnicode(event.slowPathInputData.unicode.value, not (event.slowPathInputData.keyboardFlags.value & pdu.data.KeyboardFlag.KBDFLAGS_RELEASE)) observer.onKeyEventUnicode(event.slowPathInputData.unicode.value, not (event.slowPathInputData.keyboardFlags.value & pdu.data.KeyboardFlag.KBDFLAGS_RELEASE))
#mouse event #mouse events
elif event.messageType.value == pdu.data.InputMessageType.INPUT_EVENT_MOUSE: elif event.messageType.value == pdu.data.InputMessageType.INPUT_EVENT_MOUSE:
isPressed = event.slowPathInputData.pointerFlags.value & pdu.data.PointerFlag.PTRFLAGS_DOWN isPressed = event.slowPathInputData.pointerFlags.value & pdu.data.PointerFlag.PTRFLAGS_DOWN
button = 0 button = 0
@@ -493,6 +528,15 @@ class RDPServerController(pdu.layer.PDUServerListener):
elif event.slowPathInputData.pointerFlags.value & pdu.data.PointerFlag.PTRFLAGS_BUTTON3: elif event.slowPathInputData.pointerFlags.value & pdu.data.PointerFlag.PTRFLAGS_BUTTON3:
button = 3 button = 3
observer.onPointerEvent(event.slowPathInputData.xPos.value, event.slowPathInputData.yPos.value, button, isPressed) observer.onPointerEvent(event.slowPathInputData.xPos.value, event.slowPathInputData.yPos.value, button, isPressed)
elif event.messageType.value == pdu.data.InputMessageType.INPUT_EVENT_MOUSEX:
isPressed = event.slowPathInputData.pointerFlags.value & pdu.data.PointerExFlag.PTRXFLAGS_DOWN
button = 0
if event.slowPathInputData.pointerFlags.value & pdu.data.PointerExFlag.PTRXFLAGS_BUTTON1:
button = 4
elif event.slowPathInputData.pointerFlags.value & pdu.data.PointerExFlag.PTRXFLAGS_BUTTON2:
button = 5
observer.onPointerEvent(event.slowPathInputData.xPos.value, event.slowPathInputData.yPos.value, button, isPressed)
def sendUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data): def sendUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
""" """
@@ -547,49 +591,50 @@ class ClientFactory(layer.RawLayerClientFactory):
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ClientFactory")) raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ClientFactory"))
class ServerFactory(layer.RawLayerServerFactory):
"""
@summary: Factory of Server RDP protocol
"""
def __init__(self, colorDepth, privateKeyFileName = None, certificateFileName = None):
"""
@param colorDepth: color depth of session
@param privateKeyFileName: file contain server private key (if none -> back to standard RDP security)
@param certficiateFileName: file that contain public key (if none -> back to standard RDP security)
"""
self._colorDepth = colorDepth
self._privateKeyFileName = privateKeyFileName
self._certificateFileName = certificateFileName
def connectionLost(self, tpktLayer, reason):
"""
@param reason: twisted reason
"""
#retrieve controller
x224Layer = tpktLayer._presentation
mcsLayer = x224Layer._presentation
secLayer = mcsLayer._channels[mcs.Channel.MCS_GLOBAL_CHANNEL]
pduLayer = secLayer._presentation
controller = pduLayer._listener
controller.onClose()
def buildRawLayer(self, addr):
"""
@summary: Function call from twisted and build rdp protocol stack
@param addr: destination address
"""
controller = RDPServerController(self._colorDepth, self._privateKeyFileName, self._certificateFileName)
self.buildObserver(controller, addr)
return controller.getProtocol()
def buildObserver(self, controller, addr):
"""
@summary: Build observer use for connection
@param controller: RDP stack controller
@param addr: destination address
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ServerFactory"))
# class ServerFactory(RawLayerServerFactory):
# """
# @summary: Factory of Server RDP protocol
# """
# def __init__(self, colorDepth, privateKeyFileName = None, certificateFileName = None):
# """
# @param colorDepth: color depth of session
# @param privateKeyFileName: file contain server private key (if none -> back to standard RDP security)
# @param certficiateFileName: file that contain public key (if none -> back to standard RDP security)
# """
# self._colorDepth = colorDepth
# self._privateKeyFileName = privateKeyFileName
# self._certificateFileName = certificateFileName
#
# def connectionLost(self, tpktLayer, reason):
# """
# @param reason: twisted reason
# """
# #retrieve controller
# x224Layer = tpktLayer._presentation
# mcsLayer = x224Layer._presentation
# secLayer = mcsLayer._channels[mcs.Channel.MCS_GLOBAL_CHANNEL]
# pduLayer = secLayer._presentation
# controller = pduLayer._listener
# controller.onClose()
#
# def buildRawLayer(self, addr):
# """
# @summary: Function call from twisted and build rdp protocol stack
# @param addr: destination address
# """
# controller = RDPServerController(self._colorDepth, self._privateKeyFileName, self._certificateFileName)
# self.buildObserver(controller, addr)
# return controller.getProtocol()
#
# def buildObserver(self, controller, addr):
# """
# @summary: Build observer use for connection
# @param controller: RDP stack controller
# @param addr: destination address
# """
# raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ServerFactory"))
#
class RDPClientObserver(object): class RDPClientObserver(object):
""" """
@summary: Class use to inform all RDP event handle by RDPY @summary: Class use to inform all RDP event handle by RDPY
@@ -607,6 +652,12 @@ class RDPClientObserver(object):
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RDPClientObserver")) raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RDPClientObserver"))
def onSessionReady(self):
"""
@summary: Windows session is ready
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onSessionReady", "RDPClientObserver"))
def onClose(self): def onClose(self):
""" """
@summary: Stack is closes @summary: Stack is closes
@@ -652,11 +703,12 @@ class RDPServerObserver(object):
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onClose", "RDPClientObserver")) raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onClose", "RDPClientObserver"))
def onKeyEventScancode(self, code, isPressed): def onKeyEventScancode(self, code, isPressed, isExtended):
""" """
@summary: Event call when a keyboard event is catch in scan code format @summary: Event call when a keyboard event is catch in scan code format
@param code: scan code of key @param code: {integer} scan code of key
@param isPressed: True if key is down @param isPressed: {boolean} True if key is down
@param isExtended: {boolean} True if a special key
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onKeyEventScanCode", "RDPServerObserver")) raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onKeyEventScanCode", "RDPServerObserver"))
@@ -673,7 +725,7 @@ class RDPServerObserver(object):
@summary: Event call on mouse event @summary: Event call on mouse event
@param x: x position @param x: x position
@param y: y position @param y: y position
@param button: 1, 2 or 3 button @param button: 1, 2, 3, 4 or 5 button
@param isPressed: True if mouse button is pressed @param isPressed: True if mouse button is pressed
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onPointerEvent", "RDPServerObserver")) raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onPointerEvent", "RDPServerObserver"))

View File

@@ -21,13 +21,14 @@
RDP Standard security layer RDP Standard security layer
""" """
import sha, md5 from hashlib import sha1 as sha
import lic, tpkt from hashlib import md5
from t125 import gcc, mcs from rdpy.core import tpkt, lic
from rdpy.core.type import CompositeType, CallableValue, Stream, UInt32Le, UInt16Le, String, sizeof, UInt8 from rdpy.core.t125 import gcc, mcs
from rdpy.core.layer import LayerAutomata, IStreamSender from rdpy.model.type import CompositeType, CallableValue, Stream, UInt32Le, UInt16Le, Buffer, sizeof, UInt8
from rdpy.core.error import InvalidExpectedDataException from rdpy.model.layer import LayerAutomata, IStreamSender
from rdpy.core import log from rdpy.model.error import InvalidExpectedDataException
from rdpy.model import log
from rdpy.security import rc4 from rdpy.security import rc4
import rdpy.security.rsa_wrapper as rsa import rdpy.security.rsa_wrapper as rsa
@@ -166,7 +167,7 @@ def macData(macSaltKey, data):
#encode length #encode length
dataLength = Stream() dataLength = Stream()
dataLength.writeType(UInt32Le(len(data))) dataLength.write_type(UInt32Le(len(data)))
sha1Digest.update(macSaltKey) sha1Digest.update(macSaltKey)
sha1Digest.update("\x36" * 40) sha1Digest.update("\x36" * 40)
@@ -194,10 +195,10 @@ def macSaltedData(macSaltKey, data, encryptionCount):
#encode length #encode length
dataLengthS = Stream() dataLengthS = Stream()
dataLengthS.writeType(UInt32Le(len(data))) dataLengthS.write_type(UInt32Le(len(data)))
encryptionCountS = Stream() encryptionCountS = Stream()
encryptionCountS.writeType(UInt32Le(encryptionCount)) encryptionCountS.write_type(UInt32Le(encryptionCount))
sha1Digest.update(macSaltKey) sha1Digest.update(macSaltKey)
sha1Digest.update("\x36" * 40) sha1Digest.update("\x36" * 40)
@@ -309,8 +310,8 @@ class ClientSecurityExchangePDU(CompositeType):
def __init__(self): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.length = UInt32Le(lambda:(sizeof(self) - 4)) self.length = UInt32Le(lambda:(sizeof(self) - 4))
self.encryptedClientRandom = String(readLen = CallableValue(lambda:(self.length.value - 8))) self.encryptedClientRandom = Buffer(readLen = CallableValue(lambda:(self.length.value - 8)))
self.padding = String("\x00" * 8, readLen = CallableValue(8)) self.padding = Buffer("\x00" * 8, readLen = CallableValue(8))
class RDPInfo(CompositeType): class RDPInfo(CompositeType):
""" """
@@ -323,20 +324,20 @@ class RDPInfo(CompositeType):
#code page #code page
self.codePage = UInt32Le() self.codePage = UInt32Le()
#support flag #support flag
self.flag = UInt32Le(InfoFlag.INFO_MOUSE | InfoFlag.INFO_UNICODE | InfoFlag.INFO_LOGONNOTIFY | InfoFlag.INFO_LOGONERRORS | InfoFlag.INFO_DISABLECTRLALTDEL) self.flag = UInt32Le(InfoFlag.INFO_MOUSE | InfoFlag.INFO_UNICODE | InfoFlag.INFO_LOGONNOTIFY | InfoFlag.INFO_LOGONERRORS | InfoFlag.INFO_DISABLECTRLALTDEL | InfoFlag.INFO_ENABLEWINDOWSKEY)
self.cbDomain = UInt16Le(lambda:sizeof(self.domain) - 2) self.cbDomain = UInt16Le(lambda:sizeof(self.domain) - 2)
self.cbUserName = UInt16Le(lambda:sizeof(self.userName) - 2) self.cbUserName = UInt16Le(lambda:sizeof(self.userName) - 2)
self.cbPassword = UInt16Le(lambda:sizeof(self.password) - 2) self.cbPassword = UInt16Le(lambda:sizeof(self.password) - 2)
self.cbAlternateShell = UInt16Le(lambda:sizeof(self.alternateShell) - 2) self.cbAlternateShell = UInt16Le(lambda:sizeof(self.alternateShell) - 2)
self.cbWorkingDir = UInt16Le(lambda:sizeof(self.workingDir) - 2) self.cbWorkingDir = UInt16Le(lambda:sizeof(self.workingDir) - 2)
#microsoft domain #microsoft domain
self.domain = String(readLen = CallableValue(lambda:self.cbDomain.value + 2), unicode = True) self.domain = Buffer(readLen = CallableValue(lambda: self.cbDomain.value + 2), unicode = True)
self.userName = String(readLen = CallableValue(lambda:self.cbUserName.value + 2), unicode = True) self.userName = Buffer(readLen = CallableValue(lambda: self.cbUserName.value + 2), unicode = True)
self.password = String(readLen = CallableValue(lambda:self.cbPassword.value + 2), unicode = True) self.password = Buffer(readLen = CallableValue(lambda: self.cbPassword.value + 2), unicode = True)
#shell execute at start of session #shell execute at start of session
self.alternateShell = String(readLen = CallableValue(lambda:self.cbAlternateShell.value + 2), unicode = True) self.alternateShell = Buffer(readLen = CallableValue(lambda: self.cbAlternateShell.value + 2), unicode = True)
#working directory for session #working directory for session
self.workingDir = String(readLen = CallableValue(lambda:self.cbWorkingDir.value + 2), unicode = True) self.workingDir = Buffer(readLen = CallableValue(lambda: self.cbWorkingDir.value + 2), unicode = True)
self.extendedInfo = RDPExtendedInfo(conditional = extendedInfoConditional) self.extendedInfo = RDPExtendedInfo(conditional = extendedInfoConditional)
class RDPExtendedInfo(CompositeType): class RDPExtendedInfo(CompositeType):
@@ -347,11 +348,11 @@ class RDPExtendedInfo(CompositeType):
CompositeType.__init__(self, conditional = conditional) CompositeType.__init__(self, conditional = conditional)
self.clientAddressFamily = UInt16Le(AfInet.AF_INET) self.clientAddressFamily = UInt16Le(AfInet.AF_INET)
self.cbClientAddress = UInt16Le(lambda:sizeof(self.clientAddress)) self.cbClientAddress = UInt16Le(lambda:sizeof(self.clientAddress))
self.clientAddress = String(readLen = self.cbClientAddress, unicode = True) self.clientAddress = Buffer(readLen = self.cbClientAddress, unicode = True)
self.cbClientDir = UInt16Le(lambda:sizeof(self.clientDir)) self.cbClientDir = UInt16Le(lambda:sizeof(self.clientDir))
self.clientDir = String(readLen = self.cbClientDir, unicode = True) self.clientDir = Buffer(readLen = self.cbClientDir, unicode = True)
#TODO make tiomezone #TODO make tiomezone
self.clientTimeZone = String("\x00" * 172) self.clientTimeZone = Buffer("\x00" * 172)
self.clientSessionId = UInt32Le() self.clientSessionId = UInt32Le()
self.performanceFlags = UInt32Le() self.performanceFlags = UInt32Le()
@@ -409,9 +410,9 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
self._decryptRc4 = rc4.RC4Key(self._currentDecrytKey) self._decryptRc4 = rc4.RC4Key(self._currentDecrytKey)
self._nbDecryptedPacket = 0 self._nbDecryptedPacket = 0
signature = String(readLen = CallableValue(8)) signature = Buffer(readLen = CallableValue(8))
encryptedPayload = String() encryptedPayload = Buffer()
s.readType((signature, encryptedPayload)) s.read_type((signature, encryptedPayload))
decrypted = rc4.crypt(self._decryptRc4, encryptedPayload.value) decrypted = rc4.crypt(self._decryptRc4, encryptedPayload.value)
#ckeck signature #ckeck signature
@@ -443,12 +444,12 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
self._nbEncryptedPacket += 1 self._nbEncryptedPacket += 1
s = Stream() s = Stream()
s.writeType(data) s.write_type(data)
if saltedMacGeneration: if saltedMacGeneration:
return (String(macSaltedData(self._macKey, s.getvalue(), self._nbEncryptedPacket - 1)[:8]), String(rc4.crypt(self._encryptRc4, s.getvalue()))) return (Buffer(macSaltedData(self._macKey, s.getvalue(), self._nbEncryptedPacket - 1)[:8]), Buffer(rc4.crypt(self._encryptRc4, s.getvalue())))
else: else:
return (String(macData(self._macKey, s.getvalue())[:8]), String(rc4.crypt(self._encryptRc4, s.getvalue()))) return (Buffer(macData(self._macKey, s.getvalue())[:8]), Buffer(rc4.crypt(self._encryptRc4, s.getvalue())))
def recv(self, data): def recv(self, data):
""" """
@@ -462,7 +463,7 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
securityFlag = UInt16Le() securityFlag = UInt16Le()
securityFlagHi = UInt16Le() securityFlagHi = UInt16Le()
data.readType((securityFlag, securityFlagHi)) data.read_type((securityFlag, securityFlagHi))
if securityFlag.value & SecurityFlag.SEC_ENCRYPT: if securityFlag.value & SecurityFlag.SEC_ENCRYPT:
data = self.readEncryptedPayload(data, securityFlag.value & SecurityFlag.SEC_SECURE_CHECKSUM) data = self.readEncryptedPayload(data, securityFlag.value & SecurityFlag.SEC_SECURE_CHECKSUM)
@@ -630,7 +631,7 @@ class Client(SecLayer):
#packet preambule #packet preambule
securityFlag = UInt16Le() securityFlag = UInt16Le()
securityFlagHi = UInt16Le() securityFlagHi = UInt16Le()
s.readType((securityFlag, securityFlagHi)) s.read_type((securityFlag, securityFlagHi))
if not (securityFlag.value & SecurityFlag.SEC_LICENSE_PKT): if not (securityFlag.value & SecurityFlag.SEC_LICENSE_PKT):
raise InvalidExpectedDataException("waiting license packet") raise InvalidExpectedDataException("waiting license packet")
@@ -679,13 +680,13 @@ class Server(SecLayer):
#packet preambule #packet preambule
securityFlag = UInt16Le() securityFlag = UInt16Le()
securityFlagHi = UInt16Le() securityFlagHi = UInt16Le()
s.readType((securityFlag, securityFlagHi)) s.read_type((securityFlag, securityFlagHi))
if not (securityFlag.value & SecurityFlag.SEC_EXCHANGE_PKT): if not (securityFlag.value & SecurityFlag.SEC_EXCHANGE_PKT):
raise InvalidExpectedDataException("waiting client random") raise InvalidExpectedDataException("waiting client random")
message = ClientSecurityExchangePDU() message = ClientSecurityExchangePDU()
s.readType(message) s.read_type(message)
clientRandom = rsa.decrypt(message.encryptedClientRandom.value[::-1], self._rsaPrivateKey)[::-1] clientRandom = rsa.decrypt(message.encryptedClientRandom.value[::-1], self._rsaPrivateKey)[::-1]
self._macKey, self._initialEncryptKey, self._initialDecrytKey = generateKeys( clientRandom, self._macKey, self._initialEncryptKey, self._initialDecrytKey = generateKeys( clientRandom,
@@ -710,7 +711,7 @@ class Server(SecLayer):
""" """
securityFlag = UInt16Le() securityFlag = UInt16Le()
securityFlagHi = UInt16Le() securityFlagHi = UInt16Le()
s.readType((securityFlag, securityFlagHi)) s.read_type((securityFlag, securityFlagHi))
if not (securityFlag.value & SecurityFlag.SEC_INFO_PKT): if not (securityFlag.value & SecurityFlag.SEC_INFO_PKT):
raise InvalidExpectedDataException("Waiting info packet") raise InvalidExpectedDataException("Waiting info packet")
@@ -718,7 +719,7 @@ class Server(SecLayer):
if securityFlag.value & SecurityFlag.SEC_ENCRYPT: if securityFlag.value & SecurityFlag.SEC_ENCRYPT:
s = self.readEncryptedPayload(s, securityFlag.value & SecurityFlag.SEC_SECURE_CHECKSUM) s = self.readEncryptedPayload(s, securityFlag.value & SecurityFlag.SEC_SECURE_CHECKSUM)
s.readType(self._info) s.read_type(self._info)
#next state send error license #next state send error license
self.sendLicensingErrorMessage() self.sendLicensingErrorMessage()
#reinit state #reinit state

View File

@@ -22,22 +22,25 @@ Basic Encoding Rules use in RDP.
ASN.1 standard ASN.1 standard
""" """
from rdpy.core.type import UInt8, UInt16Be, UInt32Be, String from rdpy.model.message import UInt8, UInt16Be, UInt32Be, Buffer
from rdpy.core.error import InvalidExpectedDataException, InvalidSize from rdpy.model.error import InvalidExpectedDataException, InvalidSize
class BerPc(object):
class BerPc:
BER_PC_MASK = 0x20 BER_PC_MASK = 0x20
BER_PRIMITIVE = 0x00 BER_PRIMITIVE = 0x00
BER_CONSTRUCT = 0x20 BER_CONSTRUCT = 0x20
class Class(object):
class Class:
BER_CLASS_MASK = 0xC0 BER_CLASS_MASK = 0xC0
BER_CLASS_UNIV = 0x00 BER_CLASS_UNIV = 0x00
BER_CLASS_APPL = 0x40 BER_CLASS_APPL = 0x40
BER_CLASS_CTXT = 0x80 BER_CLASS_CTXT = 0x80
BER_CLASS_PRIV = 0xC0 BER_CLASS_PRIV = 0xC0
class Tag(object):
class Tag:
BER_TAG_MASK = 0x1F BER_TAG_MASK = 0x1F
BER_TAG_BOOLEAN = 0x01 BER_TAG_BOOLEAN = 0x01
BER_TAG_INTEGER = 0x02 BER_TAG_INTEGER = 0x02
@@ -48,6 +51,7 @@ class Tag(object):
BER_TAG_SEQUENCE = 0x10 BER_TAG_SEQUENCE = 0x10
BER_TAG_SEQUENCE_OF = 0x10 BER_TAG_SEQUENCE_OF = 0x10
def berPC(pc): def berPC(pc):
""" """
@summary: Return BER_CONSTRUCT if true @summary: Return BER_CONSTRUCT if true
@@ -60,6 +64,7 @@ def berPC(pc):
else: else:
return BerPc.BER_PRIMITIVE return BerPc.BER_PRIMITIVE
def readLength(s): def readLength(s):
""" """
@summary: Read length of BER structure @summary: Read length of BER structure
@@ -69,7 +74,7 @@ def readLength(s):
""" """
size = None size = None
length = UInt8() length = UInt8()
s.readType(length) s.read_type(length)
byte = length.value byte = length.value
if byte & 0x80: if byte & 0x80:
byte &= ~0x80 byte &= ~0x80
@@ -79,11 +84,12 @@ def readLength(s):
size = UInt16Be() size = UInt16Be()
else: else:
raise InvalidExpectedDataException("BER length may be 1 or 2") raise InvalidExpectedDataException("BER length may be 1 or 2")
s.readType(size) s.read_type(size)
else: else:
size = length size = length
return size.value return size.value
def writeLength(size): def writeLength(size):
""" """
@summary: Return structure length as expected in BER specification @summary: Return structure length as expected in BER specification
@@ -95,6 +101,7 @@ def writeLength(size):
else: else:
return UInt8(size) return UInt8(size)
def readUniversalTag(s, tag, pc): def readUniversalTag(s, tag, pc):
""" """
@summary: Read tag of BER packet @summary: Read tag of BER packet
@@ -103,9 +110,10 @@ def readUniversalTag(s, tag, pc):
@return: true if tag is correctly read @return: true if tag is correctly read
""" """
byte = UInt8() byte = UInt8()
s.readType(byte) s.read_type(byte)
return byte.value == ((Class.BER_CLASS_UNIV | berPC(pc)) | (Tag.BER_TAG_MASK & tag)) return byte.value == ((Class.BER_CLASS_UNIV | berPC(pc)) | (Tag.BER_TAG_MASK & tag))
def writeUniversalTag(tag, pc): def writeUniversalTag(tag, pc):
""" """
@summary: Return universal tag byte @summary: Return universal tag byte
@@ -115,6 +123,7 @@ def writeUniversalTag(tag, pc):
""" """
return UInt8((Class.BER_CLASS_UNIV | berPC(pc)) | (Tag.BER_TAG_MASK & tag)) return UInt8((Class.BER_CLASS_UNIV | berPC(pc)) | (Tag.BER_TAG_MASK & tag))
def readApplicationTag(s, tag): def readApplicationTag(s, tag):
""" """
@summary: Read application tag @summary: Read application tag
@@ -123,11 +132,11 @@ def readApplicationTag(s, tag):
@return: length of application packet @return: length of application packet
""" """
byte = UInt8() byte = UInt8()
s.readType(byte) s.read_type(byte)
if tag.value > 30: if tag.value > 30:
if byte.value != ((Class.BER_CLASS_APPL | BerPc.BER_CONSTRUCT) | Tag.BER_TAG_MASK): if byte.value != ((Class.BER_CLASS_APPL | BerPc.BER_CONSTRUCT) | Tag.BER_TAG_MASK):
raise InvalidExpectedDataException() raise InvalidExpectedDataException()
s.readType(byte) s.read_type(byte)
if byte.value != tag.value: if byte.value != tag.value:
raise InvalidExpectedDataException("bad tag") raise InvalidExpectedDataException("bad tag")
else: else:
@@ -136,6 +145,7 @@ def readApplicationTag(s, tag):
return readLength(s) return readLength(s)
def writeApplicationTag(tag, size): def writeApplicationTag(tag, size):
""" """
@summary: Return structure that represent BER application tag @summary: Return structure that represent BER application tag
@@ -159,7 +169,7 @@ def readBoolean(s):
if size != 1: if size != 1:
raise InvalidExpectedDataException("bad boolean size") raise InvalidExpectedDataException("bad boolean size")
b = UInt8() b = UInt8()
s.readType(b) s.read_type(b)
return bool(b.value) return bool(b.value)
def writeBoolean(b): def writeBoolean(b):
@@ -186,21 +196,21 @@ def readInteger(s):
if size == 1: if size == 1:
integer = UInt8() integer = UInt8()
s.readType(integer) s.read_type(integer)
return integer.value return integer.value
elif size == 2: elif size == 2:
integer = UInt16Be() integer = UInt16Be()
s.readType(integer) s.read_type(integer)
return integer.value return integer.value
elif size == 3: elif size == 3:
integer1 = UInt8() integer1 = UInt8()
integer2 = UInt16Be() integer2 = UInt16Be()
s.readType(integer1) s.read_type(integer1)
s.readType(integer2) s.read_type(integer2)
return integer2.value + (integer1.value << 16) return integer2.value + (integer1.value << 16)
elif size == 4: elif size == 4:
integer = UInt32Be() integer = UInt32Be()
s.readType(integer) s.read_type(integer)
return integer.value return integer.value
else: else:
raise InvalidExpectedDataException("Wrong integer size") raise InvalidExpectedDataException("Wrong integer size")
@@ -235,7 +245,7 @@ def writeOctetstring(value):
@param value: string @param value: string
@return: BER octet string block @return: BER octet string block
""" """
return (writeUniversalTag(Tag.BER_TAG_OCTET_STRING, False), writeLength(len(value)), String(value)) return (writeUniversalTag(Tag.BER_TAG_OCTET_STRING, False), writeLength(len(value)), Buffer(value))
def readEnumerated(s): def readEnumerated(s):
""" """
@@ -248,7 +258,7 @@ def readEnumerated(s):
if readLength(s) != 1: if readLength(s) != 1:
raise InvalidSize("enumerate size is wrong") raise InvalidSize("enumerate size is wrong")
enumer = UInt8() enumer = UInt8()
s.readType(enumer) s.read_type(enumer)
return enumer.value return enumer.value
def writeEnumerated(enumerated): def writeEnumerated(enumerated):

View File

@@ -22,18 +22,18 @@ Implement GCC structure use in RDP protocol
http://msdn.microsoft.com/en-us/library/cc240508.aspx 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 from rdpy.model.message import UInt8, UInt16Le, UInt32Le, CompositeType, Buffer, Stream, sizeof, FactoryType, ArrayType
import per, mcs from rdpy.core.t125 import per, mcs
from rdpy.core.error import InvalidExpectedDataException from rdpy.model.error import InvalidExpectedDataException
from rdpy.core import log from rdpy.model import log
from rdpy.security import x509 from rdpy.security import x509
import rdpy.security.rsa_wrapper as rsa import rdpy.security.rsa_wrapper as rsa
t124_02_98_oid = ( 0, 0, 20, 124, 0, 1 ) t124_02_98_oid = ( 0, 0, 20, 124, 0, 1 )
h221_cs_key = "Duca"; h221_cs_key = b"Duca";
h221_sc_key = "McDn"; h221_sc_key = b"McDn";
class MessageType(object): class MessageType(object):
""" """
@@ -209,42 +209,46 @@ class CertificateType(object):
CERT_CHAIN_VERSION_1 = 0x00000001 CERT_CHAIN_VERSION_1 = 0x00000001
CERT_CHAIN_VERSION_2 = 0x00000002 CERT_CHAIN_VERSION_2 = 0x00000002
class DataBlock(CompositeType): class DataBlock(CompositeType):
""" """
@summary: Block settings @summary: Block settings
""" """
def __init__(self, dataBlock = None): def __init__(self, data_block=None):
CompositeType.__init__(self) super().__init__()
self.type = UInt16Le(lambda:self.dataBlock.__class__._TYPE_) self.type = UInt16Le(lambda:data_block._TYPE_)
self.length = UInt16Le(lambda: sizeof(self)) self.length = UInt16Le(lambda: sizeof(self))
def DataBlockFactory(): def factory():
""" """
@summary: build settings in accordance of type self.type.value
""" """
for c in [ClientCoreData, ClientSecurityData, ClientNetworkData, ServerCoreData, ServerNetworkData, ServerSecurityData]: gcc_type = [
ClientCoreData, ClientSecurityData, ClientNetworkData,
ServerCoreData, ServerNetworkData, ServerSecurityData
]
for c in gcc_type:
if self.type.value == c._TYPE_: if self.type.value == c._TYPE_:
return c(readLen = self.length - 4) return c(read_len=lambda: (self.length.value - 4))
log.debug("unknown GCC block type : %s"%hex(self.type.value)) log.debug("unknown GCC block type : %s"%hex(self.type.value))
# read entire packet # read entire packet
return String(readLen = self.length - 4) return Buffer(read_len=lambda: (self.length.value - 4))
if dataBlock is None: if data_block is None:
dataBlock = FactoryType(DataBlockFactory) data_block = FactoryType(factory)
elif not "_TYPE_" in dataBlock.__class__.__dict__: elif "_TYPE_" not in data_block.__class__.__dict__:
raise InvalidExpectedDataException("Try to send an invalid GCC blocks") raise InvalidExpectedDataException("Try to send an invalid GCC blocks")
self.dataBlock = dataBlock self.dataBlock = data_block
class ClientCoreData(CompositeType): class ClientCoreData(CompositeType):
""" """
@summary: Class that represent core setting of client
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
""" """
_TYPE_ = MessageType.CS_CORE _TYPE_ = MessageType.CS_CORE
def __init__(self, readLen = None): def __init__(self, read_len=None):
CompositeType.__init__(self, readLen = readLen) super().__init__(read_len=read_len)
self.rdpVersion = UInt32Le(Version.RDP_VERSION_5_PLUS) self.rdpVersion = UInt32Le(Version.RDP_VERSION_5_PLUS)
self.desktopWidth = UInt16Le(1280) self.desktopWidth = UInt16Le(1280)
self.desktopHeight = UInt16Le(800) self.desktopHeight = UInt16Le(800)
@@ -252,70 +256,68 @@ class ClientCoreData(CompositeType):
self.sasSequence = UInt16Le(Sequence.RNS_UD_SAS_DEL) self.sasSequence = UInt16Le(Sequence.RNS_UD_SAS_DEL)
self.kbdLayout = UInt32Le(KeyboardLayout.US) self.kbdLayout = UInt32Le(KeyboardLayout.US)
self.clientBuild = UInt32Le(3790) self.clientBuild = UInt32Le(3790)
self.clientName = String("rdpy" + "\x00"*11, readLen = CallableValue(32), unicode = True) self.clientName = Buffer(("rdpy" + "\x00" * 12).encode("utf-16le"), read_len=lambda: 32)
self.keyboardType = UInt32Le(KeyboardType.IBM_101_102_KEYS) self.keyboardType = UInt32Le(KeyboardType.IBM_101_102_KEYS)
self.keyboardSubType = UInt32Le(0) self.keyboardSubType = UInt32Le(0)
self.keyboardFnKeys = UInt32Le(12) self.keyboardFnKeys = UInt32Le(12)
self.imeFileName = String("\x00"*64, readLen = CallableValue(64), optional = True) self.imeFileName = Buffer(b"\x00" * 64, read_len=lambda: 64, optional=True)
self.postBeta2ColorDepth = UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP, optional=True) self.postBeta2ColorDepth = UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP, optional=True)
self.clientProductId = UInt16Le(1, optional=True) self.clientProductId = UInt16Le(1, optional=True)
self.serialNumber = UInt32Le(0, optional=True) self.serialNumber = UInt32Le(0, optional=True)
self.highColorDepth = UInt16Le(HighColor.HIGH_COLOR_24BPP, 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.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.earlyCapabilityFlags = UInt16Le(CapabilityFlags.RNS_UD_CS_SUPPORT_ERRINFO_PDU, optional=True)
self.clientDigProductId = String("\x00"*64, readLen = CallableValue(64), optional = True) self.clientDigProductId = Buffer(b"\x00" * 64, read_len=lambda: 64, optional=True)
self.connectionType = UInt8(optional=True) self.connectionType = UInt8(optional=True)
self.pad1octet = UInt8(optional=True) self.pad1octet = UInt8(optional=True)
self.serverSelectedProtocol = UInt32Le(optional=True) self.serverSelectedProtocol = UInt32Le(optional=True)
class ServerCoreData(CompositeType): class ServerCoreData(CompositeType):
""" """
@summary: Server side core settings structure
@see: http://msdn.microsoft.com/en-us/library/cc240517.aspx
""" """
_TYPE_ = MessageType.SC_CORE _TYPE_ = MessageType.SC_CORE
def __init__(self, readLen = None): def __init__(self, read_len=None):
CompositeType.__init__(self, readLen = readLen) super().__init__(read_len=read_len)
self.rdpVersion = UInt32Le(Version.RDP_VERSION_5_PLUS) self.rdpVersion = UInt32Le(Version.RDP_VERSION_5_PLUS)
self.clientRequestedProtocol = UInt32Le(optional=True) self.clientRequestedProtocol = UInt32Le(optional=True)
self.earlyCapabilityFlags = UInt32Le(optional=True) self.earlyCapabilityFlags = UInt32Le(optional=True)
class ClientSecurityData(CompositeType): class ClientSecurityData(CompositeType):
""" """
@summary: Client security setting
@see: http://msdn.microsoft.com/en-us/library/cc240511.aspx
""" """
_TYPE_ = MessageType.CS_SECURITY _TYPE_ = MessageType.CS_SECURITY
def __init__(self, readLen = None): def __init__(self, read_len=None):
CompositeType.__init__(self, readLen = readLen) super().__init__(read_len=read_len)
self.encryptionMethods = UInt32Le(EncryptionMethod.ENCRYPTION_FLAG_40BIT | EncryptionMethod.ENCRYPTION_FLAG_56BIT | EncryptionMethod.ENCRYPTION_FLAG_128BIT) self.encryptionMethods = UInt32Le(EncryptionMethod.ENCRYPTION_FLAG_40BIT | EncryptionMethod.ENCRYPTION_FLAG_56BIT | EncryptionMethod.ENCRYPTION_FLAG_128BIT)
self.extEncryptionMethods = UInt32Le() self.extEncryptionMethods = UInt32Le()
class ServerSecurityData(CompositeType): class ServerSecurityData(CompositeType):
""" """
@summary: Server security settings
@see: http://msdn.microsoft.com/en-us/library/cc240518.aspx
""" """
_TYPE_ = MessageType.SC_SECURITY _TYPE_ = MessageType.SC_SECURITY
def __init__(self, readLen = None): def __init__(self, read_len=None):
CompositeType.__init__(self, readLen = readLen) super().__init__(read_len=read_len)
self.encryptionMethod = UInt32Le() self.encryptionMethod = UInt32Le()
self.encryptionLevel = UInt32Le() self.encryptionLevel = UInt32Le()
self.serverRandomLen = UInt32Le(0x00000020, constant = True, conditional = lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel == 0)) self.serverRandomLen = UInt32Le(0x00000020, constant=True, conditional=lambda: not(self.encryptionMethod.value == 0 and self.encryptionLevel.value == 0))
self.serverCertLen = UInt32Le(lambda:sizeof(self.serverCertificate), conditional = lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel == 0)) self.serverCertLen = UInt32Le(lambda: sizeof(self.serverCertificate), conditional=lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel.value == 0))
self.serverRandom = String(readLen = self.serverRandomLen, conditional = lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel == 0)) self.serverRandom = Buffer(read_len=lambda: self.serverRandomLen.value, conditional=lambda: not(self.encryptionMethod.value == 0 and self.encryptionLevel.value == 0))
self.serverCertificate = ServerCertificate(readLen = self.serverCertLen, conditional = lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel == 0)) self.serverCertificate = ServerCertificate(read_len=lambda: self.serverCertLen.value, conditional=lambda: not(self.encryptionMethod.value == 0 and self.encryptionLevel.value == 0))
class ServerCertificate(CompositeType): class ServerCertificate(CompositeType):
""" """
@summary: Server certificate structure @summary: Server certificate structure
@see: http://msdn.microsoft.com/en-us/library/cc240521.aspx @see: http://msdn.microsoft.com/en-us/library/cc240521.aspx
""" """
def __init__(self, certData = None, readLen = None, conditional = lambda:True): def __init__(self, certData = None, read_len = None, conditional = lambda:True):
CompositeType.__init__(self, readLen = readLen, conditional = conditional) CompositeType.__init__(self, read_len=read_len, conditional = conditional)
self.dwVersion = UInt32Le(lambda:(self.certData.__class__._TYPE_)) self.dwVersion = UInt32Le(lambda:(self.certData.__class__._TYPE_))
def CertificateFactory(): def CertificateFactory():
@@ -355,8 +357,8 @@ class ProprietaryServerCertificate(CompositeType):
self.PublicKeyBlob = RSAPublicKey(readLen = self.wPublicKeyBlobLen) self.PublicKeyBlob = RSAPublicKey(readLen = self.wPublicKeyBlobLen)
self.wSignatureBlobType = UInt16Le(0x0008, constant = True) self.wSignatureBlobType = UInt16Le(0x0008, constant = True)
self.wSignatureBlobLen = UInt16Le(lambda:(sizeof(self.SignatureBlob) + sizeof(self.padding))) self.wSignatureBlobLen = UInt16Le(lambda:(sizeof(self.SignatureBlob) + sizeof(self.padding)))
self.SignatureBlob = String(readLen = CallableValue(lambda:(self.wSignatureBlobLen.value - sizeof(self.padding)))) self.SignatureBlob = Buffer(readLen = CallableValue(lambda:(self.wSignatureBlobLen.value - sizeof(self.padding))))
self.padding = String(b"\x00" * 8, readLen = CallableValue(8)) self.padding = Buffer(b"\x00" * 8, readLen = CallableValue(8))
def getPublicKey(self): def getPublicKey(self):
""" """
@@ -371,12 +373,12 @@ class ProprietaryServerCertificate(CompositeType):
@summary: compute hash @summary: compute hash
""" """
s = Stream() s = Stream()
s.writeType(UInt32Le(self.__class__._TYPE_)) s.write_type(UInt32Le(self.__class__._TYPE_))
s.writeType(self.dwSigAlgId) s.write_type(self.dwSigAlgId)
s.writeType(self.dwKeyAlgId) s.write_type(self.dwKeyAlgId)
s.writeType(self.wPublicKeyBlobType) s.write_type(self.wPublicKeyBlobType)
s.writeType(self.wPublicKeyBlobLen) s.write_type(self.wPublicKeyBlobLen)
s.writeType(self.PublicKeyBlob) s.write_type(self.PublicKeyBlob)
md5Digest = md5.new() md5Digest = md5.new()
md5Digest.update(s.getvalue()) md5Digest.update(s.getvalue())
@@ -405,7 +407,7 @@ class CertBlob(CompositeType):
def __init__(self): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.cbCert = UInt32Le(lambda:sizeof(self.abCert)) self.cbCert = UInt32Le(lambda:sizeof(self.abCert))
self.abCert = String(readLen = self.cbCert) self.abCert = Buffer(readLen = self.cbCert)
class X509CertificateChain(CompositeType): class X509CertificateChain(CompositeType):
""" """
@@ -418,7 +420,7 @@ class X509CertificateChain(CompositeType):
CompositeType.__init__(self) CompositeType.__init__(self)
self.NumCertBlobs = UInt32Le() self.NumCertBlobs = UInt32Le()
self.CertBlobArray = ArrayType(CertBlob, readLen = self.NumCertBlobs) self.CertBlobArray = ArrayType(CertBlob, readLen = self.NumCertBlobs)
self.padding = String(readLen = CallableValue(lambda:(8 + 4 * self.NumCertBlobs.value))) self.padding = Buffer(readLen = CallableValue(lambda:(8 + 4 * self.NumCertBlobs.value)))
def getPublicKey(self): def getPublicKey(self):
""" """
@@ -447,80 +449,63 @@ class RSAPublicKey(CompositeType):
self.bitlen = UInt32Le(lambda:((self.keylen.value - 8) * 8)) 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.pubExp = UInt32Le()
self.modulus = String(readLen = CallableValue(lambda:(self.keylen.value - 8))) self.modulus = Buffer(readLen = CallableValue(lambda:(self.keylen.value - 8)))
self.padding = String("\x00" * 8, readLen = CallableValue(8)) self.padding = Buffer(b"\x00" * 8, readLen = CallableValue(8))
class ChannelDef(CompositeType): class ChannelDef(CompositeType):
""" """
Channels structure share between client and server
@see: http://msdn.microsoft.com/en-us/library/cc240513.aspx
""" """
def __init__(self, name = "", options = 0): def __init__(self, name=b""):
CompositeType.__init__(self) super().__init__()
# name of channel # name of channel
self.name = String(name[0:8] + "\x00" * (8 - len(name)), readLen = CallableValue(8)) self.name = Buffer(name[0:8] + b"\x00" * (8 - len(name)), read_len=lambda: 8)
# unknown # unknown
self.options = UInt32Le() self.options = UInt32Le()
class ClientNetworkData(CompositeType): class ClientNetworkData(CompositeType):
""" """
@summary: GCC client network block
All channels asked by client are listed here
@see: http://msdn.microsoft.com/en-us/library/cc240512.aspx
""" """
_TYPE_ = MessageType.CS_NET _TYPE_ = MessageType.CS_NET
def __init__(self, readLen = None): def __init__(self, read_len=None):
CompositeType.__init__(self, readLen = readLen) CompositeType.__init__(self, read_len=read_len)
self.channelCount = UInt32Le(lambda:len(self.channelDefArray._array)) self.channelCount = UInt32Le(lambda: len(self.channelDefArray))
self.channelDefArray = ArrayType(ChannelDef, readLen = self.channelCount) self.channelDefArray = ArrayType(ChannelDef, read_len=lambda: self.channelCount.value)
class ServerNetworkData(CompositeType): class ServerNetworkData(CompositeType):
""" """
@summary: GCC server network block
All channels asked by client are listed here
@see: All channels asked by client are listed here
""" """
_TYPE_ = MessageType.SC_NET _TYPE_ = MessageType.SC_NET
def __init__(self, readLen = None): def __init__(self, read_len=None):
CompositeType.__init__(self, readLen = readLen) super().__init__(read_len=read_len)
self.MCSChannelId = UInt16Le(mcs.Channel.MCS_GLOBAL_CHANNEL) self.MCSChannelId = UInt16Le(mcs.Channel.MCS_GLOBAL_CHANNEL)
self.channelCount = UInt16Le(lambda:len(self.channelIdArray._array)) self.channelCount = UInt16Le(lambda: len(self.channelIdArray))
self.channelIdArray = ArrayType(UInt16Le, readLen = self.channelCount) self.channelIdArray = ArrayType(UInt16Le, read_len=lambda: self.channelCount.value)
self.pad = UInt16Le(conditional=lambda: ((self.channelCount.value % 2) == 1)) self.pad = UInt16Le(conditional=lambda: ((self.channelCount.value % 2) == 1))
class Settings(CompositeType): class Settings(CompositeType):
""" """
@summary: Class which group all clients settings supported by RDPY
""" """
def __init__(self, init = [], readLen = None): def __init__(self, init=None, read_len=None):
CompositeType.__init__(self, readLen = readLen) super().__init__(read_len=read_len)
self.settings = ArrayType(DataBlock, [DataBlock(i) for i in init]) self.settings = ArrayType(DataBlock, [DataBlock(i) for i in init or []])
def getBlock(self, messageType): def get_block(self, message_type):
""" """
@param messageType: type of block
@return: specific block of type messageType
""" """
for i in self.settings._array: for i in self.settings._array:
if i.type.value == messageType: if i.type.value == message_type:
return i.dataBlock return i.dataBlock
return None return None
def __getattr__(self, name):
"""
@summary: Magic function for better access
@return: _value parameter
"""
if not name in MessageType.__dict__:
return None
return self.getBlock(MessageType.__dict__[name])
def clientSettings(): def client_settings():
""" """
@summary: Build settings for client
@return: Settings
""" """
return Settings([ClientCoreData(), ClientNetworkData(), ClientSecurityData()]) return Settings([ClientCoreData(), ClientNetworkData(), ClientSecurityData()])
@@ -555,7 +540,7 @@ def readConferenceCreateRequest(s):
per.readOctetStream(s, h221_cs_key, 4) per.readOctetStream(s, h221_cs_key, 4)
length = per.readLength(s) length = per.readLength(s)
clientSettings = Settings(readLen = CallableValue(length)) clientSettings = Settings(readLen = CallableValue(length))
s.readType(clientSettings) s.read_type(clientSettings)
return clientSettings return clientSettings
def readConferenceCreateResponse(s): def readConferenceCreateResponse(s):
@@ -578,9 +563,9 @@ def readConferenceCreateResponse(s):
raise InvalidExpectedDataException("cannot read h221_sc_key") raise InvalidExpectedDataException("cannot read h221_sc_key")
length = per.readLength(s) length = per.readLength(s)
serverSettings = Settings(readLen = CallableValue(length)) server_settings = Settings(read_len=lambda: length)
s.readType(serverSettings) s.read_type(server_settings)
return serverSettings return server_settings
def writeConferenceCreateRequest(userData): def writeConferenceCreateRequest(userData):
""" """
@@ -589,11 +574,11 @@ def writeConferenceCreateRequest(userData):
@return: GCC packet @return: GCC packet
""" """
userDataStream = Stream() userDataStream = Stream()
userDataStream.writeType(userData) userDataStream.write_type(userData)
return (per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid), return (per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid),
per.writeLength(len(userDataStream.getvalue()) + 14), per.writeChoice(0), per.writeLength(len(userDataStream.getvalue()) + 14), per.writeChoice(0),
per.writeSelection(0x08), per.writeNumericString("1", 1), per.writePadding(1), per.writeSelection(0x08), per.writeNumericString(b"1", 1), per.writePadding(1),
per.writeNumberOfSet(1), per.writeChoice(0xc0), per.writeNumberOfSet(1), per.writeChoice(0xc0),
per.writeOctetStream(h221_cs_key, 4), per.writeOctetStream(userDataStream.getvalue())) per.writeOctetStream(h221_cs_key, 4), per.writeOctetStream(userDataStream.getvalue()))
@@ -604,7 +589,7 @@ def writeConferenceCreateResponse(serverData):
@return: gcc packet @return: gcc packet
""" """
serverDataStream = Stream() serverDataStream = Stream()
serverDataStream.writeType(serverData) serverDataStream.write_type(serverData)
return (per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid), return (per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid),
per.writeLength(len(serverDataStream.getvalue()) + 14), per.writeChoice(0x14), per.writeLength(len(serverDataStream.getvalue()) + 14), per.writeChoice(0x14),

View File

@@ -24,25 +24,28 @@ Each channel have a particular role.
The main channel is the graphical channel. The main channel is the graphical channel.
It exist channel for file system order, audio channel, clipboard etc... It exist channel for file system order, audio channel, clipboard etc...
""" """
from rdpy.core.layer import LayerAutomata, IStreamSender, Layer from typing import Tuple
from rdpy.core.type import sizeof, Stream, UInt8, UInt16Le, String
from rdpy.core.error import InvalidExpectedDataException, InvalidValue, InvalidSize, CallPureVirtualFuntion
from ber import writeLength
import rdpy.core.log as log
import ber, gcc, per from rdpy.core import x224
from rdpy.model.layer import LayerAutomata, IStreamSender, Layer
from rdpy.model.message import sizeof, Stream, UInt8, UInt16Le, Buffer
from rdpy.model.error import InvalidExpectedDataException, InvalidValue, InvalidSize, CallPureVirtualFuntion
from rdpy.core.t125.ber import writeLength
import rdpy.model.log as log
from rdpy.core.t125 import ber, gcc, per
import rdpy.security.rsa_wrapper as rsa import rdpy.security.rsa_wrapper as rsa
class Message(object):
class Message:
""" """
@summary: Message type
""" """
MCS_TYPE_CONNECT_INITIAL = 0x65 MCS_TYPE_CONNECT_INITIAL = 0x65
MCS_TYPE_CONNECT_RESPONSE = 0x66 MCS_TYPE_CONNECT_RESPONSE = 0x66
class DomainMCSPDU: class DomainMCSPDU:
""" """
@summary: Domain MCS PDU header
""" """
ERECT_DOMAIN_REQUEST = 1 ERECT_DOMAIN_REQUEST = 1
DISCONNECT_PROVIDER_ULTIMATUM = 8 DISCONNECT_PROVIDER_ULTIMATUM = 8
@@ -53,17 +56,19 @@ class DomainMCSPDU:
SEND_DATA_REQUEST = 25 SEND_DATA_REQUEST = 25
SEND_DATA_INDICATION = 26 SEND_DATA_INDICATION = 26
class Channel: class Channel:
""" """
@summary: Channel id of main channels use in RDP
""" """
MCS_GLOBAL_CHANNEL = 1003 MCS_GLOBAL_CHANNEL = 1003
MCS_USERCHANNEL_BASE = 1001 MCS_USERCHANNEL_BASE = 1001
class IGCCConfig(object): class IGCCConfig(object):
""" """
@summary: Channel information @summary: Channel information
""" """
def getUserId(self): def getUserId(self):
""" """
@return: {integer} mcs user id @return: {integer} mcs user id
@@ -83,14 +88,150 @@ class IGCCConfig(object):
@return: {gcc.Settings} mcs layer gcc client settings @return: {gcc.Settings} mcs layer gcc client settings
@see: mcs.IGCCConfig @see: mcs.IGCCConfig
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "getGCCClientSettings", "IGCCConfig")) raise CallPureVirtualFuntion(
"%s:%s defined by interface %s" % (self.__class__, "getGCCClientSettings", "IGCCConfig"))
def getGCCServerSettings(self): def getGCCServerSettings(self):
""" """
@return: {gcc.Settings} mcs layer gcc server settings @return: {gcc.Settings} mcs layer gcc server settings
@see: mcs.IGCCConfig @see: mcs.IGCCConfig
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "getGCCServerSettings", "IGCCConfig")) raise CallPureVirtualFuntion(
"%s:%s defined by interface %s" % (self.__class__, "getGCCServerSettings", "IGCCConfig"))
def write_domain_params(max_channels: int, max_users: int, max_tokens: int, max_pdu_size: int) -> tuple:
"""
"""
domain_param = (ber.writeInteger(max_channels), ber.writeInteger(max_users), ber.writeInteger(max_tokens),
ber.writeInteger(1), ber.writeInteger(0), ber.writeInteger(1),
ber.writeInteger(max_pdu_size), ber.writeInteger(2))
return ber.writeUniversalTag(ber.Tag.BER_TAG_SEQUENCE, True), writeLength(sizeof(domain_param)), domain_param
def read_domain_params(stream: Stream) -> Tuple[int, int, int, int]:
"""
"""
if not ber.readUniversalTag(stream, ber.Tag.BER_TAG_SEQUENCE, True):
raise InvalidValue("bad BER tags")
ber.readLength(stream) # length
max_channels = ber.readInteger(stream)
max_users = ber.readInteger(stream)
max_tokens = ber.readInteger(stream)
ber.readInteger(stream)
ber.readInteger(stream)
ber.readInteger(stream)
max_pdu_size = ber.readInteger(stream)
ber.readInteger(stream)
return max_channels, max_users, max_tokens, max_pdu_size
def mcs_pdu_header(mcs_pdu: UInt8, options=0) -> UInt8:
return (mcs_pdu << 2) | options
def check_mcs_pdu_header(opcode: UInt8, mcs_pdu):
return (opcode >> 2) == mcs_pdu
def erect_domain_request() -> Tuple:
return mcs_pdu_header(UInt8(DomainMCSPDU.ERECT_DOMAIN_REQUEST)), per.writeInteger(0), per.writeInteger(0)
def read_attach_confirm(data: Stream) -> int:
"""
"""
opcode = data.read_type(UInt8())
if not check_mcs_pdu_header(opcode, DomainMCSPDU.ATTACH_USER_CONFIRM):
raise InvalidExpectedDataException("Invalid MCS PDU : ATTACH_USER_CONFIRM expected")
if per.readEnumerates(data) != 0:
raise InvalidExpectedDataException("Server reject user")
return per.readInteger16(data, Channel.MCS_USERCHANNEL_BASE)
def attach_user_request() -> UInt8:
return mcs_pdu_header(UInt8(DomainMCSPDU.ATTACH_USER_REQUEST))
def channel_join_request(user_id: int, channel_id: int):
return (mcs_pdu_header(UInt8(DomainMCSPDU.CHANNEL_JOIN_REQUEST)),
per.writeInteger16(user_id, Channel.MCS_USERCHANNEL_BASE),
per.writeInteger16(channel_id))
def channel_join_confirm(user_id: int, channel_id: int, data: Stream) -> bool:
"""
"""
opcode = data.read_type(UInt8())
if not check_mcs_pdu_header(opcode.value, DomainMCSPDU.CHANNEL_JOIN_CONFIRM):
raise InvalidExpectedDataException("Invalid MCS PDU : CHANNEL_JOIN_CONFIRM expected")
confirm = per.readEnumerates(data)
if user_id != per.readInteger16(data, Channel.MCS_USERCHANNEL_BASE):
raise InvalidExpectedDataException("Invalid MCS User Id")
if channel_id != per.readInteger16(data):
raise InvalidExpectedDataException("Invalid MCS channel id")
return confirm == 0
class Client:
def __init__(self, x224_layer: x224.X224):
self.x224 = x224_layer
self.channel_ids = {}
async def write_connect_initial(self):
"""
"""
settings = gcc.client_settings()
settings.get_block(gcc.MessageType.CS_CORE).serverSelectedProtocol.value = self.x224.get_selected_protocol()
cc_req = gcc.writeConferenceCreateRequest(settings)
cc_req_stream = Stream()
cc_req_stream.write_type(cc_req)
tmp = (ber.writeOctetstring(b"\x01"), ber.writeOctetstring(b"\x01"), ber.writeBoolean(True),
write_domain_params(34, 2, 0, 0xffff),
write_domain_params(1, 1, 1, 0x420),
write_domain_params(0xffff, 0xfc17, 0xffff, 0xffff),
ber.writeOctetstring(cc_req_stream.getvalue()))
await self.x224.write((ber.writeApplicationTag(Message.MCS_TYPE_CONNECT_INITIAL, sizeof(tmp)), tmp))
async def read_connect_response(self):
payload = await self.x224.read()
ber.readApplicationTag(payload, UInt8(Message.MCS_TYPE_CONNECT_RESPONSE))
ber.readEnumerated(payload)
ber.readInteger(payload)
read_domain_params(payload)
if not ber.readUniversalTag(payload, ber.Tag.BER_TAG_OCTET_STRING, False):
raise InvalidExpectedDataException("invalid expected BER tag")
gccRequestLength = ber.readLength(payload)
if payload.data_len() != gccRequestLength:
raise InvalidSize("bad size of GCC request")
gcc.readConferenceCreateResponse(payload)
async def connect(self):
await self.write_connect_initial()
await self.read_connect_response()
await self.x224.write(erect_domain_request())
await self.x224.write(attach_user_request())
user_id = read_attach_confirm(await self.x224.read())
self.channel_ids["global"] = 1003
self.channel_ids["user"] = user_id
# connect all channels
for channel_id in self.channel_ids.values():
await self.x224.write(channel_join_request(user_id, channel_id))
if not channel_join_confirm(user_id, channel_id, await self.x224.read()):
print("Server refused channel %s"%channel_id)
class MCSLayer(LayerAutomata): class MCSLayer(LayerAutomata):
""" """
@@ -98,11 +239,13 @@ class MCSLayer(LayerAutomata):
the main layer of RDP protocol the main layer of RDP protocol
is why he can do everything and more! is why he can do everything and more!
""" """
class MCSProxySender(Layer, IStreamSender, IGCCConfig): class MCSProxySender(Layer, IStreamSender, IGCCConfig):
""" """
@summary: Proxy use to set as transport layer for upper channel @summary: Proxy use to set as transport layer for upper channel
use to abstract channel id for presentation layer use to abstract channel id for presentation layer
""" """
def __init__(self, presentation, mcs, channelId): def __init__(self, presentation, mcs, channelId):
""" """
@param presentation: {Layer} presentation layer @param presentation: {Layer} presentation layer
@@ -155,7 +298,6 @@ class MCSLayer(LayerAutomata):
""" """
return self._mcs._serverSettings return self._mcs._serverSettings
def __init__(self, presentation, receiveOpcode, sendOpcode, virtualChannels=[]): def __init__(self, presentation, receiveOpcode, sendOpcode, virtualChannels=[]):
""" """
@param presentation: {Layer} presentation layer @param presentation: {Layer} presentation layer
@@ -182,7 +324,7 @@ class MCSLayer(LayerAutomata):
@summary: Send disconnect provider ultimatum @summary: Send disconnect provider ultimatum
""" """
self._transport.send((UInt8(self.writeMCSPDUHeader(DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM, 1)), self._transport.send((UInt8(self.writeMCSPDUHeader(DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM, 1)),
per.writeEnumerates(0x80), String("\x00" * 6))) per.writeEnumerates(0x80), Buffer(b"\x00" * 6)))
self._transport.close() self._transport.close()
def allChannelConnected(self): def allChannelConnected(self):
@@ -216,7 +358,7 @@ class MCSLayer(LayerAutomata):
@param data: {Stream} @param data: {Stream}
""" """
opcode = UInt8() opcode = UInt8()
data.readType(opcode) data.read_type(opcode)
if self.readMCSPDUHeader(opcode.value, DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM): if self.readMCSPDUHeader(opcode.value, DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM):
log.info("MCS DISCONNECT_PROVIDER_ULTIMATUM") log.info("MCS DISCONNECT_PROVIDER_ULTIMATUM")
@@ -294,16 +436,19 @@ class MCSLayer(LayerAutomata):
ber.readInteger(s) ber.readInteger(s)
return (max_channels, max_users, max_tokens, max_pdu_size) return (max_channels, max_users, max_tokens, max_pdu_size)
class Client(MCSLayer):
class ClientOld(MCSLayer):
""" """
@summary: Client automata of multiple channel service layer @summary: Client automata of multiple channel service layer
""" """
def __init__(self, presentation, virtualChannels=[]): def __init__(self, presentation, virtualChannels=[]):
""" """
@param presentation: {Layer} presentation layer @param presentation: {Layer} presentation layer
@param virtualChannels: {Array(Layer)} list additional channels like rdpsnd... [tuple(mcs.ChannelDef, layer)] @param virtualChannels: {Array(Layer)} list additional channels like rdpsnd... [tuple(mcs.ChannelDef, layer)]
""" """
MCSLayer.__init__(self, presentation, DomainMCSPDU.SEND_DATA_INDICATION, DomainMCSPDU.SEND_DATA_REQUEST, virtualChannels) MCSLayer.__init__(self, presentation, DomainMCSPDU.SEND_DATA_INDICATION, DomainMCSPDU.SEND_DATA_REQUEST,
virtualChannels)
# use to know state of static channel # use to know state of static channel
self._isGlobalChannelRequested = False self._isGlobalChannelRequested = False
self._isUserChannelRequested = False self._isUserChannelRequested = False
@@ -344,8 +489,8 @@ class Client(MCSLayer):
return return
# static virtual channel # static virtual channel
if self._nbChannelRequested < self._serverSettings.getBlock(gcc.MessageType.SC_NET).channelCount.value: if self._nbChannelRequested < self._serverSettings.get_block(gcc.MessageType.SC_NET).channelCount.value:
channelId = self._serverSettings.getBlock(gcc.MessageType.SC_NET).channelIdArray[self._nbChannelRequested] channelId = self._serverSettings.get_block(gcc.MessageType.SC_NET).channelIdArray[self._nbChannelRequested]
self._nbChannelRequested += 1 self._nbChannelRequested += 1
self.sendChannelJoinRequest(channelId) self.sendChannelJoinRequest(channelId)
return return
@@ -367,7 +512,7 @@ class Client(MCSLayer):
if not ber.readUniversalTag(data, ber.Tag.BER_TAG_OCTET_STRING, False): if not ber.readUniversalTag(data, ber.Tag.BER_TAG_OCTET_STRING, False):
raise InvalidExpectedDataException("invalid expected BER tag") raise InvalidExpectedDataException("invalid expected BER tag")
gccRequestLength = ber.readLength(data) gccRequestLength = ber.readLength(data)
if data.dataLen() != gccRequestLength: if data.data_len() != gccRequestLength:
raise InvalidSize("bad size of GCC request") raise InvalidSize("bad size of GCC request")
self._serverSettings = gcc.readConferenceCreateResponse(data) self._serverSettings = gcc.readConferenceCreateResponse(data)
@@ -385,7 +530,7 @@ class Client(MCSLayer):
@param data: {Stream} @param data: {Stream}
""" """
opcode = UInt8() opcode = UInt8()
data.readType(opcode) data.read_type(opcode)
if not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.ATTACH_USER_CONFIRM): if not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.ATTACH_USER_CONFIRM):
raise InvalidExpectedDataException("Invalid MCS PDU : ATTACH_USER_CONFIRM expected") raise InvalidExpectedDataException("Invalid MCS PDU : ATTACH_USER_CONFIRM expected")
@@ -404,7 +549,7 @@ class Client(MCSLayer):
@param data: {Stream} @param data: {Stream}
""" """
opcode = UInt8() opcode = UInt8()
data.readType(opcode) data.read_type(opcode)
if not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.CHANNEL_JOIN_CONFIRM): if not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.CHANNEL_JOIN_CONFIRM):
raise InvalidExpectedDataException("Invalid MCS PDU : CHANNEL_JOIN_CONFIRM expected") raise InvalidExpectedDataException("Invalid MCS PDU : CHANNEL_JOIN_CONFIRM expected")
@@ -421,7 +566,7 @@ class Client(MCSLayer):
raise InvalidExpectedDataException("Server must confirm static channel") raise InvalidExpectedDataException("Server must confirm static channel")
if confirm == 0: if confirm == 0:
serverNet = self._serverSettings.getBlock(gcc.MessageType.SC_NET) serverNet = self._serverSettings.get_block(gcc.MessageType.SC_NET)
for i in range(0, serverNet.channelCount.value): for i in range(0, serverNet.channelCount.value):
if channelId == serverNet.channelIdArray[i].value: if channelId == serverNet.channelIdArray[i].value:
self._channels[channelId] = self._virtualChannels[i][1] self._channels[channelId] = self._virtualChannels[i][1]
@@ -435,7 +580,7 @@ class Client(MCSLayer):
""" """
ccReq = gcc.writeConferenceCreateRequest(self._clientSettings) ccReq = gcc.writeConferenceCreateRequest(self._clientSettings)
ccReqStream = Stream() ccReqStream = Stream()
ccReqStream.writeType(ccReq) ccReqStream.write_type(ccReq)
tmp = (ber.writeOctetstring("\x01"), ber.writeOctetstring("\x01"), ber.writeBoolean(True), tmp = (ber.writeOctetstring("\x01"), ber.writeOctetstring("\x01"), ber.writeBoolean(True),
self.writeDomainParams(34, 2, 0, 0xffff), self.writeDomainParams(34, 2, 0, 0xffff),
@@ -468,16 +613,19 @@ class Client(MCSLayer):
per.writeInteger16(self._userId, Channel.MCS_USERCHANNEL_BASE), per.writeInteger16(self._userId, Channel.MCS_USERCHANNEL_BASE),
per.writeInteger16(channelId))) per.writeInteger16(channelId)))
class Server(MCSLayer): class Server(MCSLayer):
""" """
@summary: Server automata of multiple channel service layer @summary: Server automata of multiple channel service layer
""" """
def __init__(self, presentation, virtualChannels=[]): def __init__(self, presentation, virtualChannels=[]):
""" """
@param presentation: {Layer} presentation layer @param presentation: {Layer} presentation layer
@param virtualChannels: {List(Layer)} list additional channels like rdpsnd... [tuple(mcs.ChannelDef, layer)] @param virtualChannels: {List(Layer)} list additional channels like rdpsnd... [tuple(mcs.ChannelDef, layer)]
""" """
MCSLayer.__init__(self, presentation, DomainMCSPDU.SEND_DATA_REQUEST, DomainMCSPDU.SEND_DATA_INDICATION, virtualChannels) MCSLayer.__init__(self, presentation, DomainMCSPDU.SEND_DATA_REQUEST, DomainMCSPDU.SEND_DATA_INDICATION,
virtualChannels)
# nb channel requested # nb channel requested
self._nbChannelConfirmed = 0 self._nbChannelConfirmed = 0
@@ -488,7 +636,6 @@ class Server(MCSLayer):
""" """
# basic rdp security layer # basic rdp security layer
if self._transport._selectedProtocol == 0: if self._transport._selectedProtocol == 0:
self._serverSettings.SC_SECURITY.encryptionMethod.value = gcc.EncryptionMethod.ENCRYPTION_FLAG_128BIT self._serverSettings.SC_SECURITY.encryptionMethod.value = gcc.EncryptionMethod.ENCRYPTION_FLAG_128BIT
self._serverSettings.SC_SECURITY.encryptionLevel.value = gcc.EncryptionLevel.ENCRYPTION_LEVEL_HIGH self._serverSettings.SC_SECURITY.encryptionLevel.value = gcc.EncryptionLevel.ENCRYPTION_LEVEL_HIGH
self._serverSettings.SC_SECURITY.serverRandom.value = rsa.random(256) self._serverSettings.SC_SECURITY.serverRandom.value = rsa.random(256)
@@ -536,7 +683,7 @@ class Server(MCSLayer):
@param data: {Stream} @param data: {Stream}
""" """
opcode = UInt8() opcode = UInt8()
data.readType(opcode) data.read_type(opcode)
if not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.ERECT_DOMAIN_REQUEST): if not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.ERECT_DOMAIN_REQUEST):
raise InvalidExpectedDataException("Invalid MCS PDU : ERECT_DOMAIN_REQUEST expected") raise InvalidExpectedDataException("Invalid MCS PDU : ERECT_DOMAIN_REQUEST expected")
@@ -554,7 +701,7 @@ class Server(MCSLayer):
@param data: {Stream} @param data: {Stream}
""" """
opcode = UInt8() opcode = UInt8()
data.readType(opcode) data.read_type(opcode)
if not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.ATTACH_USER_REQUEST): if not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.ATTACH_USER_REQUEST):
raise InvalidExpectedDataException("Invalid MCS PDU : ATTACH_USER_REQUEST expected") raise InvalidExpectedDataException("Invalid MCS PDU : ATTACH_USER_REQUEST expected")
@@ -570,7 +717,7 @@ class Server(MCSLayer):
""" """
opcode = UInt8() opcode = UInt8()
data.readType(opcode) data.read_type(opcode)
if not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.CHANNEL_JOIN_REQUEST): if not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.CHANNEL_JOIN_REQUEST):
raise InvalidExpectedDataException("Invalid MCS PDU : CHANNEL_JOIN_REQUEST expected") raise InvalidExpectedDataException("Invalid MCS PDU : CHANNEL_JOIN_REQUEST expected")
@@ -584,7 +731,7 @@ class Server(MCSLayer):
confirm = 0 if channelId in self._channels.keys() or channelId == self._userId else 1 confirm = 0 if channelId in self._channels.keys() or channelId == self._userId else 1
self.sendChannelJoinConfirm(channelId, confirm) self.sendChannelJoinConfirm(channelId, confirm)
self._nbChannelConfirmed += 1 self._nbChannelConfirmed += 1
if self._nbChannelConfirmed == self._serverSettings.getBlock(gcc.MessageType.SC_NET).channelCount.value + 2: if self._nbChannelConfirmed == self._serverSettings.get_block(gcc.MessageType.SC_NET).channelCount.value + 2:
self.allChannelConnected() self.allChannelConnected()
def sendConnectResponse(self): def sendConnectResponse(self):
@@ -593,7 +740,7 @@ class Server(MCSLayer):
""" """
ccReq = gcc.writeConferenceCreateResponse(self._serverSettings) ccReq = gcc.writeConferenceCreateResponse(self._serverSettings)
ccReqStream = Stream() ccReqStream = Stream()
ccReqStream.writeType(ccReq) ccReqStream.write_type(ccReq)
tmp = (ber.writeEnumerated(0), ber.writeInteger(0), self.writeDomainParams(22, 3, 0, 0xfff8), tmp = (ber.writeEnumerated(0), ber.writeInteger(0), self.writeDomainParams(22, 3, 0, 0xfff8),
ber.writeOctetstring(ccReqStream.getvalue())) ber.writeOctetstring(ccReqStream.getvalue()))

View File

@@ -21,8 +21,8 @@
Per encoded function Per encoded function
""" """
from rdpy.core.type import UInt8, UInt16Be, UInt32Be, String from rdpy.model.message import UInt8, UInt16Be, UInt32Be, Buffer
from rdpy.core.error import InvalidValue, InvalidExpectedDataException from rdpy.model.error import InvalidValue, InvalidExpectedDataException
def readLength(s): def readLength(s):
""" """
@@ -31,12 +31,12 @@ def readLength(s):
@return: int python @return: int python
""" """
byte = UInt8() byte = UInt8()
s.readType(byte) s.read_type(byte)
size = 0 size = 0
if byte.value & 0x80: if byte.value & 0x80:
byte.value &= ~0x80 byte.value &= ~0x80
size = byte.value << 8 size = byte.value << 8
s.readType(byte) s.read_type(byte)
size += byte.value size += byte.value
else: else:
size = byte.value size = byte.value
@@ -60,7 +60,7 @@ def readChoice(s):
@return: int that represent choice @return: int that represent choice
""" """
choice = UInt8() choice = UInt8()
s.readType(choice) s.read_type(choice)
return choice.value return choice.value
def writeChoice(choice): def writeChoice(choice):
@@ -78,7 +78,7 @@ def readSelection(s):
@return: int that represent selection @return: int that represent selection
""" """
choice = UInt8() choice = UInt8()
s.readType(choice) s.read_type(choice)
return choice.value return choice.value
def writeSelection(selection): def writeSelection(selection):
@@ -96,7 +96,7 @@ def readNumberOfSet(s):
@return: int that represent numberOfSet @return: int that represent numberOfSet
""" """
choice = UInt8() choice = UInt8()
s.readType(choice) s.read_type(choice)
return choice.value return choice.value
def writeNumberOfSet(numberOfSet): def writeNumberOfSet(numberOfSet):
@@ -114,7 +114,7 @@ def readEnumerates(s):
@return: int that represent enumerate @return: int that represent enumerate
""" """
choice = UInt8() choice = UInt8()
s.readType(choice) s.read_type(choice)
return choice.value return choice.value
def writeEnumerates(enumer): def writeEnumerates(enumer):
@@ -142,7 +142,7 @@ def readInteger(s):
result = UInt32Be() result = UInt32Be()
else: else:
raise InvalidValue("invalid integer size %d"%size) raise InvalidValue("invalid integer size %d"%size)
s.readType(result) s.read_type(result)
return result.value return result.value
def writeInteger(value): def writeInteger(value):
@@ -166,7 +166,7 @@ def readInteger16(s, minimum = 0):
@return: int or long python value @return: int or long python value
""" """
result = UInt16Be() result = UInt16Be()
s.readType(result) s.read_type(result)
return result.value + minimum return result.value + minimum
def writeInteger16(value, minimum = 0): def writeInteger16(value, minimum = 0):
@@ -190,16 +190,16 @@ def readObjectIdentifier(s, oid):
raise InvalidValue("size of stream oid is wrong %d != 5"%size) raise InvalidValue("size of stream oid is wrong %d != 5"%size)
a_oid = [0, 0, 0, 0, 0, 0] a_oid = [0, 0, 0, 0, 0, 0]
t12 = UInt8() t12 = UInt8()
s.readType(t12) s.read_type(t12)
a_oid[0] = t12.value >> 4 a_oid[0] = t12.value >> 4
a_oid[1] = t12.value & 0x0f a_oid[1] = t12.value & 0x0f
s.readType(t12) s.read_type(t12)
a_oid[2] = t12.value a_oid[2] = t12.value
s.readType(t12) s.read_type(t12)
a_oid[3] = t12.value a_oid[3] = t12.value
s.readType(t12) s.read_type(t12)
a_oid[4] = t12.value a_oid[4] = t12.value
s.readType(t12) s.read_type(t12)
a_oid[5] = t12.value a_oid[5] = t12.value
if list(oid) != a_oid: if list(oid) != a_oid:
@@ -223,12 +223,9 @@ def readNumericString(s, minValue):
length = (length + minValue + 1) / 2 length = (length + minValue + 1) / 2
s.read(length) s.read(length)
def writeNumericString(nStr, minValue): def writeNumericString(nStr, minValue):
""" """
@summary: write string in per format
@param str: python string to write
@param min: min value
@return: String type that contain str encoded in per format
""" """
length = len(nStr) length = len(nStr)
mlength = minValue mlength = minValue
@@ -238,9 +235,9 @@ def writeNumericString(nStr, minValue):
result = [] result = []
for i in range(0, length, 2): for i in range(0, length, 2):
c1 = ord(nStr[i]) c1 = nStr[i]
if i + 1 < length: if i + 1 < length:
c2 = ord(nStr[i + 1]) c2 = nStr[i + 1]
else: else:
c2 = 0x30 c2 = 0x30
c1 = (c1 - 0x30) % 10 c1 = (c1 - 0x30) % 10
@@ -248,7 +245,7 @@ def writeNumericString(nStr, minValue):
result.append(UInt8((c1 << 4) | c2)) result.append(UInt8((c1 << 4) | c2))
return (writeLength(mlength), tuple(result)) return writeLength(mlength), tuple(result)
def readPadding(s, length): def readPadding(s, length):
""" """
@@ -264,7 +261,7 @@ def writePadding(length):
@param length: length of padding @param length: length of padding
@return: String with \x00 * length @return: String with \x00 * length
""" """
return String("\x00"*length) return Buffer(b"\x00" * length)
def readOctetStream(s, octetStream, minValue = 0): def readOctetStream(s, octetStream, minValue = 0):
""" """
@@ -276,11 +273,11 @@ def readOctetStream(s, octetStream, minValue = 0):
""" """
size = readLength(s) + minValue size = readLength(s) + minValue
if size != len(octetStream): 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): for i in range(0, size):
c = UInt8() c = UInt8()
s.readType(c) s.read_type(c)
if ord(octetStream[i]) != c.value: if octetStream[i] != c.value:
return False return False
return True return True
@@ -300,6 +297,6 @@ def writeOctetStream(oStr, minValue = 0):
result = [] result = []
for i in range(0, length): for i in range(0, length):
result.append(UInt8(ord(oStr[i]))) result.append(UInt8(oStr[i]))
return (writeLength(mlength), tuple(result)) return writeLength(mlength), tuple(result)

179
rdpy/core/tpkt.py Normal file
View File

@@ -0,0 +1,179 @@
#
# Copyright (c) 2014-2015 Sylvain Peyrefitte
#
# This file is part of rdpy.
#
# rdpy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
"""
Transport packet layer implementation
Use to build correct size packet and handle slow path and fast path mode
"""
import asyncio
import ssl
from rdpy.core.nla import cssp, sspi
from rdpy.model.layer import RawLayer
from rdpy.model.message import UInt8, UInt16Be, sizeof, Stream
class Action:
"""
@see: http://msdn.microsoft.com/en-us/library/cc240621.aspx
@see: http://msdn.microsoft.com/en-us/library/cc240589.aspx
"""
FASTPATH_ACTION_FASTPATH = 0x0
FASTPATH_ACTION_X224 = 0x3
class SecFlags:
"""
@see: http://msdn.microsoft.com/en-us/library/cc240621.aspx
"""
FASTPATH_OUTPUT_SECURE_CHECKSUM = 0x1
FASTPATH_OUTPUT_ENCRYPTED = 0x2
class Tpkt:
"""
@summary: TPKT layer in RDP protocol stack
represent the Raw Layer in stack (first layer)
This layer only handle size of packet and determine if is a fast path packet
"""
def __init__(self, reader, writer):
self.reader = reader
self.writer = writer
def readHeader(self, data):
"""
@summary: Read header of TPKT packet
@param data: {Stream} received from twisted layer
"""
#first read packet version
version = UInt8()
data.read_type(version)
#classic packet
if version.value == Action.FASTPATH_ACTION_X224:
#padding
data.read_type(UInt8())
#read end header
self.expect(2, self.readExtendedHeader)
else:
#is fast path packet
self._secFlag = ((version.value >> 6) & 0x3)
data.read_type(self._lastShortLength)
if self._lastShortLength.value & 0x80:
#size is 1 byte more
self.expect(1, self.readExtendedFastPathHeader)
return
self.expect(self._lastShortLength.value - 2, self.readFastPath)
def readExtendedHeader(self, data):
"""
@summary: Header may be on 4 bytes
@param data: {Stream} from twisted layer
"""
#next state is read data
size = UInt16Be()
data.read_type(size)
self.expect(size.value - 4, self.readData)
def readExtendedFastPathHeader(self, data):
"""
@summary: Fast path header may be on 1 byte more
@param data: {Stream} from twisted layer
"""
leftPart = UInt8()
data.read_type(leftPart)
self._lastShortLength.value &= ~0x80
packetSize = (self._lastShortLength.value << 8) + leftPart.value
#next state is fast patn data
self.expect(packetSize - 3, self.readFastPath)
def readFastPath(self, data):
"""
@summary: Fast path data
@param data: {Stream} from twisted layer
"""
self._fastPathListener.recvFastPath(self._secFlag, data)
self.expect(2, self.readHeader)
def readData(self, data):
"""
@summary: Read classic TPKT packet, last state in tpkt automata
@param data: {Stream} with correct size
"""
#next state is pass to
self._presentation.recv(data)
self.expect(2, self.readHeader)
async def write(self, message):
"""
@summary: Send encompassed data
@param message: {network.Type} message to send
"""
s = Stream()
s.write_type((UInt8(Action.FASTPATH_ACTION_X224), UInt8(0), UInt16Be(sizeof(message) + 4), message))
self.writer.write(s.getvalue())
await self.writer.drain()
async def read(self):
"""
Read an entire payload from the reader stream
"""
header = Stream(await self.reader.readexactly(2))
action = UInt8()
header.read_type(action)
if action.value == Action.FASTPATH_ACTION_X224:
# read padding
header.read_type(UInt8())
size = UInt16Be()
Stream(await self.reader.readexactly(2)).read_type(size)
return Stream(await self.reader.readexactly(size.value - 4))
def sendFastPath(self, secFlag, fastPathS):
"""
@param fastPathS: {Type | Tuple} type transform to stream and send as fastpath
@param secFlag: {integer} Security flag for fastpath packet
"""
RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_FASTPATH | ((secFlag & 0x3) << 6)), UInt16Be((sizeof(fastPathS) + 3) | 0x8000), fastPathS))
async def start_tls(self):
"""
Start TLS protocol
"""
ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ssl_ctx.check_hostname = False
ssl_ctx.verify_mode = ssl.VerifyMode.CERT_NONE
reader, writer = await asyncio.open_connection(sock=self.writer.transport._sock, ssl=ssl_ctx, server_hostname="")
return Tpkt(reader, writer)
async def start_nla(self, authentication_protocol: sspi.IAuthenticationProtocol):
"""
use to start NLA (NTLM over SSL) protocol
must be called after startTLS function
:ivar authentication_protocol: Authentication protocol use by CSSP to authenticate user
and transfert credentials
"""
tpkt = await self.start_tls()
await cssp.connect(tpkt.reader, tpkt.writer, authentication_protocol)
return tpkt

View File

@@ -23,13 +23,15 @@ Implement transport PDU layer
This layer have main goal to negociate SSL transport This layer have main goal to negociate SSL transport
RDP basic security is supported only on client side RDP basic security is supported only on client side
""" """
from rdpy.core import log from rdpy.core import tpkt
from rdpy.core.nla import sspi
from rdpy.model import log
from rdpy.core.layer import LayerAutomata, IStreamSender from rdpy.model.message import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof, Buffer, Stream
from rdpy.core.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof, String from rdpy.model.error import InvalidExpectedDataException, RDPSecurityNegoFail
from rdpy.core.error import InvalidExpectedDataException, RDPSecurityNegoFail
class MessageType(object):
class MessageType:
""" """
@summary: Message type @summary: Message type
""" """
@@ -39,7 +41,8 @@ class MessageType(object):
X224_TPDU_DATA = 0xF0 X224_TPDU_DATA = 0xF0
X224_TPDU_ERROR = 0x70 X224_TPDU_ERROR = 0x70
class NegociationType(object):
class NegociationType:
""" """
@summary: Negotiation header @summary: Negotiation header
""" """
@@ -47,7 +50,8 @@ class NegociationType(object):
TYPE_RDP_NEG_RSP = 0x02 TYPE_RDP_NEG_RSP = 0x02
TYPE_RDP_NEG_FAILURE = 0x03 TYPE_RDP_NEG_FAILURE = 0x03
class Protocols(object):
class Protocols:
""" """
@summary: Protocols available for x224 layer @summary: Protocols available for x224 layer
@see: https://msdn.microsoft.com/en-us/library/cc240500.aspx @see: https://msdn.microsoft.com/en-us/library/cc240500.aspx
@@ -57,7 +61,8 @@ class Protocols(object):
PROTOCOL_HYBRID = 0x00000002 PROTOCOL_HYBRID = 0x00000002
PROTOCOL_HYBRID_EX = 0x00000008 PROTOCOL_HYBRID_EX = 0x00000008
class NegotiationFailureCode(object):
class NegotiationFailureCode:
""" """
@summary: Protocol negotiation failure code @summary: Protocol negotiation failure code
""" """
@@ -68,22 +73,24 @@ class NegotiationFailureCode(object):
HYBRID_REQUIRED_BY_SERVER = 0x00000005 HYBRID_REQUIRED_BY_SERVER = 0x00000005
SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006 SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006
class ClientConnectionRequestPDU(CompositeType):
class ConnectionRequestPDU(CompositeType):
""" """
@summary: Connection request Connection Request PDU
client -> server Use to send protocol security level available for the client
@see: http://msdn.microsoft.com/en-us/library/cc240470.aspx :see: http://msdn.microsoft.com/en-us/library/cc240470.aspx
""" """
def __init__(self): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.len = UInt8(lambda:sizeof(self) - 1) self.len = UInt8(lambda:sizeof(self) - 1)
self.code = UInt8(MessageType.X224_TPDU_CONNECTION_REQUEST, constant=True) self.code = UInt8(MessageType.X224_TPDU_CONNECTION_REQUEST, constant=True)
self.padding = (UInt16Be(), UInt16Be(), UInt8()) self.padding = (UInt16Be(), UInt16Be(), UInt8())
self.cookie = String(until = "\x0d\x0a", conditional = lambda:(self.len._is_readed and self.len.value > 14)) self.cookie = Buffer(until=b"\x0d\x0a", conditional=lambda: (self.len._is_readed and self.len.value > 14))
# read if there is enough data # read if there is enough data
self.protocolNeg = Negotiation(optional = True) self.protocolNeg = Negotiation(optional = True)
class ServerConnectionConfirm(CompositeType):
class ConnectionConfirmPDU(CompositeType):
""" """
@summary: Server response @summary: Server response
@see: http://msdn.microsoft.com/en-us/library/cc240506.aspx @see: http://msdn.microsoft.com/en-us/library/cc240506.aspx
@@ -96,6 +103,7 @@ class ServerConnectionConfirm(CompositeType):
#read if there is enough data #read if there is enough data
self.protocolNeg = Negotiation(optional = True) self.protocolNeg = Negotiation(optional = True)
class X224DataHeader(CompositeType): class X224DataHeader(CompositeType):
""" """
@summary: Header send when x224 exchange application data @summary: Header send when x224 exchange application data
@@ -106,6 +114,7 @@ class X224DataHeader(CompositeType):
self.messageType = UInt8(MessageType.X224_TPDU_DATA, constant = True) self.messageType = UInt8(MessageType.X224_TPDU_DATA, constant = True)
self.separator = UInt8(0x80, constant = True) self.separator = UInt8(0x80, constant = True)
class Negotiation(CompositeType): class Negotiation(CompositeType):
""" """
@summary: Negociate request message @summary: Negociate request message
@@ -122,117 +131,68 @@ class Negotiation(CompositeType):
self.selectedProtocol = UInt32Le(conditional = lambda: (self.code.value != NegociationType.TYPE_RDP_NEG_FAILURE)) self.selectedProtocol = UInt32Le(conditional = lambda: (self.code.value != NegociationType.TYPE_RDP_NEG_FAILURE))
self.failureCode = UInt32Le(conditional = lambda: (self.code.value == NegociationType.TYPE_RDP_NEG_FAILURE)) self.failureCode = UInt32Le(conditional = lambda: (self.code.value == NegociationType.TYPE_RDP_NEG_FAILURE))
class X224Layer(LayerAutomata, IStreamSender):
"""
@summary: x224 layer management
there is an connection automata
"""
def __init__(self, presentation):
"""
@param presentation: upper layer, MCS layer in RDP case
"""
LayerAutomata.__init__(self, presentation)
#client requested selectedProtocol
self._requestedProtocol = Protocols.PROTOCOL_SSL | Protocols.PROTOCOL_HYBRID
#server selected selectedProtocol
self._selectedProtocol = Protocols.PROTOCOL_SSL
def recvData(self, data): class X224:
"""
"""
def __init__(self, tpkt: tpkt.Tpkt, selected_protocol: int):
"""
"""
self.tpkt = tpkt
self.selected_protocol = selected_protocol
async def read(self) -> Stream:
""" """
@summary: Read data header from packet
And pass to presentation layer
@param data: Stream
""" """
header = X224DataHeader() header = X224DataHeader()
data.readType(header) payload = await self.tpkt.read()
self._presentation.recv(data) payload.read_type(header)
return payload
def send(self, message): async def write(self, message):
""" """
@summary: Write message packet for TPDU layer
Add TPDU header
@param message: network.Type message
""" """
self._transport.send((X224DataHeader(), message)) await self.tpkt.write((X224DataHeader(), message))
class Client(X224Layer): def get_selected_protocol(self):
""" return self.selected_protocol
@summary: Client automata of TPDU layer
"""
def __init__(self, presentation):
"""
@param presentation: upper layer, MCS layer in RDP case
"""
X224Layer.__init__(self, presentation)
def connect(self):
"""
@summary: Connection request for client send a connection request packet
"""
self.sendConnectionRequest()
def sendConnectionRequest(self): async def connect(tpkt: tpkt.Tpkt, authentication_protocol: sspi.IAuthenticationProtocol) -> X224:
""" """
@summary: Write connection request message Negotiate the security level and generate a X224 configured layer
Next state is recvConnectionConfirm
@see: http://msdn.microsoft.com/en-us/library/cc240500.aspx :ivar tpkt: this is the tpkt layer use to negotiate the security level
:ivar authentication_protocol: Authentication protocol is used by NLA authentication
Actually only NTLMv2 is available
:see: http://msdn.microsoft.com/en-us/library/cc240500.aspx
""" """
message = ClientConnectionRequestPDU() request = ConnectionRequestPDU()
message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_REQ request.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_REQ
message.protocolNeg.selectedProtocol.value = self._requestedProtocol request.protocolNeg.selectedProtocol.value = Protocols.PROTOCOL_HYBRID | Protocols.PROTOCOL_SSL
self._transport.send(message) await tpkt.write(request)
self.setNextState(self.recvConnectionConfirm)
def recvConnectionConfirm(self, data): respond = (await tpkt.read()).read_type(ConnectionConfirmPDU())
""" if respond.protocolNeg.failureCode._is_readed:
@summary: Receive connection confirm message raise RDPSecurityNegoFail("negotiation failure code %x"%respond.protocolNeg.failureCode.value)
Next state is recvData
Call connect on presentation layer if all is good
@param data: Stream that contain connection confirm
@see: response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
@see: failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
"""
message = ServerConnectionConfirm()
data.readType(message)
if message.protocolNeg.failureCode._is_readed: selected_protocol = Protocols.PROTOCOL_RDP
raise RDPSecurityNegoFail("negotiation failure code %x"%message.protocolNeg.failureCode.value) if respond.protocolNeg._is_readed:
selected_protocol = respond.protocolNeg.selectedProtocol.value
#check presence of negotiation response if selected_protocol in [Protocols.PROTOCOL_HYBRID_EX]:
if message.protocolNeg._is_readed:
self._selectedProtocol = message.protocolNeg.selectedProtocol.value
else:
self._selectedProtocol = Protocols.PROTOCOL_RDP
#NLA protocol doesn't support in actual version of RDPY
if self._selectedProtocol in [ Protocols.PROTOCOL_HYBRID_EX ]:
raise InvalidExpectedDataException("RDPY doesn't support PROTOCOL_HYBRID_EX security Layer") raise InvalidExpectedDataException("RDPY doesn't support PROTOCOL_HYBRID_EX security Layer")
#now i'm ready to receive data if selected_protocol == Protocols.PROTOCOL_RDP:
self.setNextState(self.recvData) return X224(tpkt, selected_protocol)
elif selected_protocol == Protocols.PROTOCOL_SSL:
return X224(await tpkt.start_tls(), selected_protocol)
elif selected_protocol == Protocols.PROTOCOL_HYBRID:
return X224(await tpkt.start_nla(authentication_protocol), selected_protocol)
if self._selectedProtocol == Protocols.PROTOCOL_RDP:
log.warning("*" * 43)
log.warning("*" + " " * 10 + "RDP Security selected" + " " * 10 + "*")
log.warning("*" * 43)
#connection is done send to presentation
self._presentation.connect()
elif self._selectedProtocol == Protocols.PROTOCOL_SSL: class Server(X224):
log.info("*" * 43)
log.info("*" + " " * 10 + "SSL Security selected" + " " * 10 + "*")
log.info("*" * 43)
self._transport.startTLS(ClientTLSContext())
#connection is done send to presentation
self._presentation.connect()
elif self._selectedProtocol == Protocols.PROTOCOL_HYBRID:
log.info("*" * 43)
log.info("*" + " " * 10 + "NLA Security selected" + " " * 10 + "*")
log.info("*" * 43)
self._transport.startNLA(ClientTLSContext(), lambda:self._presentation.connect())
class Server(X224Layer):
""" """
@summary: Server automata of X224 layer @summary: Server automata of X224 layer
""" """
@@ -262,8 +222,8 @@ class Server(X224Layer):
@param data: {Stream} @param data: {Stream}
@see : http://msdn.microsoft.com/en-us/library/cc240470.aspx @see : http://msdn.microsoft.com/en-us/library/cc240470.aspx
""" """
message = ClientConnectionRequestPDU() message = ConnectionRequestPDU()
data.readType(message) data.read_type(message)
if not message.protocolNeg._is_readed: if not message.protocolNeg._is_readed:
self._requestedProtocol = Protocols.PROTOCOL_RDP self._requestedProtocol = Protocols.PROTOCOL_RDP
@@ -280,7 +240,7 @@ class Server(X224Layer):
if not self._selectedProtocol & Protocols.PROTOCOL_SSL and self._forceSSL: if not self._selectedProtocol & Protocols.PROTOCOL_SSL and self._forceSSL:
log.warning("server reject client because doesn't support SSL") log.warning("server reject client because doesn't support SSL")
#send error message and quit #send error message and quit
message = ServerConnectionConfirm() message = ConnectionConfirmPDU()
message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_FAILURE message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_FAILURE
message.protocolNeg.failureCode.value = NegotiationFailureCode.SSL_REQUIRED_BY_SERVER message.protocolNeg.failureCode.value = NegotiationFailureCode.SSL_REQUIRED_BY_SERVER
self._transport.send(message) self._transport.send(message)
@@ -296,45 +256,15 @@ class Server(X224Layer):
Next state is recvData Next state is recvData
@see : http://msdn.microsoft.com/en-us/library/cc240501.aspx @see : http://msdn.microsoft.com/en-us/library/cc240501.aspx
""" """
message = ServerConnectionConfirm() message = ConnectionConfirmPDU()
message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_RSP message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_RSP
message.protocolNeg.selectedProtocol.value = self._selectedProtocol message.protocolNeg.selectedProtocol.value = self._selectedProtocol
self._transport.send(message) self._transport.send(message)
if self._selectedProtocol == Protocols.PROTOCOL_SSL: if self._selectedProtocol == Protocols.PROTOCOL_SSL:
log.debug("*" * 10 + " select SSL layer " + "*" * 10) log.debug("*" * 10 + " select SSL layer " + "*" * 10)
#_transport is TPKT and transport is TCP layer of twisted #_transport is TPKT and transport is TCP layer of twisted
self._transport.startTLS(ServerTLSContext(self._serverPrivateKeyFileName, self._serverCertificateFileName)) #self._transport.startTLS(ServerTLSContext(self._serverPrivateKeyFileName, self._serverCertificateFileName))
#connection is done send to presentation #connection is done send to presentation
self.setNextState(self.recvData) self.setNextState(self.recvData)
self._presentation.connect() self._presentation.connect()
#open ssl needed
from twisted.internet import ssl
from OpenSSL import SSL
class ClientTLSContext(ssl.ClientContextFactory):
"""
@summary: client context factory for open ssl
"""
def getContext(self):
context = SSL.Context(SSL.TLSv1_METHOD)
context.set_options(SSL.OP_DONT_INSERT_EMPTY_FRAGMENTS)
context.set_options(SSL.OP_TLS_BLOCK_PADDING_BUG)
return context
class ServerTLSContext(ssl.DefaultOpenSSLContextFactory):
"""
@summary: Server context factory for open ssl
@param privateKeyFileName: Name of a file containing a private key
@param certificateFileName: Name of a file containing a certificate
"""
def __init__(self, privateKeyFileName, certificateFileName):
class TPDUSSLContext(SSL.Context):
def __init__(self, method):
SSL.Context.__init__(self, method)
self.set_options(SSL.OP_DONT_INSERT_EMPTY_FRAGMENTS)
self.set_options(SSL.OP_TLS_BLOCK_PADDING_BUG)
ssl.DefaultOpenSSLContextFactory.__init__(self, privateKeyFileName, certificateFileName, SSL.SSLv23_METHOD, TPDUSSLContext)

View File

@@ -22,8 +22,9 @@ Join RDPY design with twisted design
RDPY use Layer Protocol design (like twisted) RDPY use Layer Protocol design (like twisted)
""" """
import asyncio
from rdpy.model.error import CallPureVirtualFuntion
from rdpy.core.error import CallPureVirtualFuntion
class IStreamListener(object): class IStreamListener(object):
""" """
@@ -36,6 +37,7 @@ class IStreamListener(object):
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener")) raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
class IStreamSender(object): class IStreamSender(object):
""" """
@summary: Interface use to inform stream sender capability @summary: Interface use to inform stream sender capability
@@ -47,6 +49,7 @@ class IStreamSender(object):
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "send", "IStreamSender")) raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "send", "IStreamSender"))
class Layer(object): class Layer(object):
""" """
@summary: A simple double linked list with presentation and transport layer @summary: A simple double linked list with presentation and transport layer
@@ -80,6 +83,7 @@ class Layer(object):
if not self._transport is None: if not self._transport is None:
self._transport.close() self._transport.close()
class LayerAutomata(Layer, IStreamListener): class LayerAutomata(Layer, IStreamListener):
""" """
@summary: Layer with automata callback @summary: Layer with automata callback
@@ -103,13 +107,8 @@ class LayerAutomata(Layer, IStreamListener):
self.recv = callback self.recv = callback
#twisted layer concept
from twisted.internet import protocol
from twisted.internet.abstract import FileDescriptor
#first that handle stream
from type import Stream
class RawLayerClientFactory(protocol.ClientFactory): class RawLayerClientFactory(asyncio.Protocol):
""" """
@summary: Abstract class for Raw layer client factory @summary: Abstract class for Raw layer client factory
""" """
@@ -137,36 +136,37 @@ class RawLayerClientFactory(protocol.ClientFactory):
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "connectionLost", "RawLayerClientFactory")) raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "connectionLost", "RawLayerClientFactory"))
class RawLayerServerFactory(protocol.ServerFactory):
"""
@summary: Abstract class for Raw layer server factory
"""
def buildProtocol(self, addr):
"""
@summary: Function call from twisted
@param addr: destination address
"""
rawLayer = self.buildRawLayer(addr)
rawLayer.setFactory(self)
return rawLayer
def buildRawLayer(self, addr): # class RawLayerServerFactory(protocol.ServerFactory):
""" # """
@summary: Override this function to build raw layer # @summary: Abstract class for Raw layer server factory
@param addr: destination address # """
""" # def buildProtocol(self, addr):
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener")) # """
# @summary: Function call from twisted
def connectionLost(self, rawlayer, reason): # @param addr: destination address
""" # """
@summary: Override this method to handle connection lost # rawLayer = self.buildRawLayer(addr)
@param rawlayer: rawLayer that cause connectionLost event # rawLayer.setFactory(self)
@param reason: twisted reason # return rawLayer
""" #
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener")) # def buildRawLayer(self, addr):
# """
# @summary: Override this function to build raw layer
class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender): # @param addr: destination address
# """
# raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
#
# def connectionLost(self, rawlayer, reason):
# """
# @summary: Override this method to handle connection lost
# @param rawlayer: rawLayer that cause connectionLost event
# @param reason: twisted reason
# """
# raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
#
#
class RawLayer(asyncio.Protocol, LayerAutomata, IStreamSender):
""" """
@summary: Wait event from twisted engine @summary: Wait event from twisted engine
And format correct size packet And format correct size packet
@@ -256,5 +256,5 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
@param message: (tuple | Type) @param message: (tuple | Type)
""" """
s = Stream() s = Stream()
s.writeType(message) s.write_type(message)
self.transport.write(s.getvalue()) self.transport.write(s.getvalue())

View File

@@ -33,13 +33,18 @@ class Level(object):
NONE = 4 NONE = 4
_LOG_LEVEL = Level.DEBUG _LOG_LEVEL = Level.DEBUG
_LOG_FILE = False
def log(message): def log(message):
""" """
@summary: Main log function @summary: Main log function
@param message: string to print @param message: string to print
""" """
print "[*] %s"%message if _LOG_FILE:
f = open(_LOG_FILE, "a+")
f.write("%s\n"%message)
f.close()
print("[*] %s"%message)
def error(message): def error(message):
""" """

View File

@@ -26,9 +26,10 @@ We are in python!
import struct import struct
from copy import deepcopy from copy import deepcopy
from StringIO import StringIO from io import BytesIO
from rdpy.core.error import InvalidExpectedDataException, InvalidSize, CallPureVirtualFuntion, InvalidValue from rdpy.model.error import InvalidExpectedDataException, InvalidSize, CallPureVirtualFuntion, InvalidValue
import rdpy.core.log as log import rdpy.model.log as log
def sizeof(element): def sizeof(element):
""" """
@@ -42,22 +43,18 @@ def sizeof(element):
for i in element: for i in element:
size += sizeof(i) size += sizeof(i)
return size return size
elif isinstance(element, Type) and element._conditional(): elif isinstance(element, Message) and element._conditional():
return element.__sizeof__() return element.__sizeof__()
return 0 return 0
class Type(object):
class Message:
""" """
@summary: Root type object inheritance @summary: Root type object inheritance
Record conditional optional of constant mechanism Record conditional optional of constant mechanism
""" """
def __init__(self, conditional=lambda: True, optional=False, constant=False): def __init__(self, conditional=lambda: True, optional=False, constant=False):
""" """
@param conditional : Callable object
Read and Write operation depend on return of this function
@param optional: If there is no enough byte in current stream
And optional is True, read type is ignored
@param constant: Check if object value doesn't change after read operation
""" """
self._conditional = conditional self._conditional = conditional
self._optional = optional self._optional = optional
@@ -103,7 +100,7 @@ class Type(object):
# check constant value # check constant value
if old != self: if old != self:
# rollback read value # rollback read value
s.pos -= sizeof(self) s.seek(-sizeof(self), 1)
raise InvalidExpectedDataException("%s const value expected %s != %s"%(self.__class__, old.value, self.value)) raise InvalidExpectedDataException("%s const value expected %s != %s"%(self.__class__, old.value, self.value))
def __read__(self, s): def __read__(self, s):
@@ -127,22 +124,23 @@ class Type(object):
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "__sizeof__", "Type")) raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "__sizeof__", "Type"))
class CallableValue(object):
class DynMessage(Message):
""" """
@summary: Expression evaluate when is get or set Expression evaluate when is get or set
Ex: Type contain length of array and array Ex: Type contain length of array and array
To know the size of array you need to read To know the size of array you need to read
length field before. At ctor time no length was read. length field before. At ctor time no length was read.
You need a callable object that will be evaluate when it will be used You need a callable object that will be evaluate when it will be used
""" """
def __init__(self, value): def __init__(self, **kwargs):
""" """
@param value: value will be wrapped (raw python type | lambda | function) @param value: value will be wrapped (raw python type | lambda | function)
""" """
super().__init__(**kwargs)
self._value = None self._value = None
self.value = value
def __getValue__(self): def get_value(self):
""" """
@summary: Call when value is get -> Evaluate inner expression @summary: Call when value is get -> Evaluate inner expression
Can be overwritten to add specific check before Can be overwritten to add specific check before
@@ -151,7 +149,7 @@ class CallableValue(object):
""" """
return self._value() return self._value()
def __setValue__(self, value): def set_value(self, value):
""" """
@summary: Call when value is set @summary: Call when value is set
Can be overwritten to add specific check before Can be overwritten to add specific check before
@@ -164,23 +162,10 @@ class CallableValue(object):
self._value = value_callable self._value = value_callable
@property value = property(get_value, set_value)
def value(self):
"""
@summary: Evaluate callable expression
@return: result of callable value
"""
return self.__getValue__()
@value.setter
def value(self, value):
"""
@summary: Setter of value
@param value: new value encompass in value type object
"""
self.__setValue__(value)
class SimpleType(Type, CallableValue): class SimpleType(DynMessage):
""" """
@summary: Non composite type @summary: Non composite type
leaf in type tree leaf in type tree
@@ -198,46 +183,11 @@ class SimpleType(Type, CallableValue):
And optional is True, read type is ignored And optional is True, read type is ignored
@param constant: Check if object value doesn't change after read operation @param constant: Check if object value doesn't change after read operation
""" """
super().__init__(conditional=conditional, optional=optional, constant=constant)
self._signed = signed self._signed = signed
self._typeSize = typeSize self._typeSize = typeSize
self._structFormat = structFormat self._structFormat = structFormat
Type.__init__(self, conditional = conditional, optional = optional, constant = constant) self.value = value
CallableValue.__init__(self, value)
def __getValue__(self):
"""
@summary: Check value if match range of type
And apply sign
Ex: UInt8 can be > 255
@return: Python value wrap into type
@raise InvalidValue: if value doesn't respect type range
@see: CallableValue.__getValue__
"""
value = CallableValue.__getValue__(self)
#check value now because it can be an callable value
#and evaluate a this time
if not self.isInRange(value):
raise InvalidValue("value is out of range for %s"%self.__class__)
if self._signed:
return value
else:
return value & self.mask()
def __setValue__(self, value):
"""
@summary: Check if new value respect type declaration
Ex: UInt8 can be > 256
@param value: new value (raw python type | lambda | function)
@raise InvalidValue: if value doesn't respect type range
@see: CallableValue.__setValue__
"""
#check static value range
if not callable(value) and not self.isInRange(value):
raise InvalidValue("value is out of range for %s"%self.__class__)
CallableValue.__setValue__(self, value)
def __write__(self, s): def __write__(self, s):
""" """
@@ -256,33 +206,11 @@ class SimpleType(Type, CallableValue):
@param s: Stream that will be read @param s: Stream that will be read
@raise InvalidSize: if there is not enough data in stream @raise InvalidSize: if there is not enough data in stream
""" """
if s.dataLen() < self._typeSize: if s.data_len() < self._typeSize:
raise InvalidSize("Stream is too small to read expected SimpleType") raise InvalidSize("Stream is too small to read expected SimpleType")
self.value = struct.unpack(self._structFormat, s.read(self._typeSize))[0] value = struct.unpack(self._structFormat, s.read(self._typeSize))[0]
def mask(self): self.value = value
"""
@summary: Compute bit mask for type
Because in Python all numbers are Int long or float
Cache result in self._mask field
"""
if not self.__dict__.has_key("_mask"):
mask = 0xff
for _ in range(1, self._typeSize):
mask = mask << 8 | 0xff
self._mask = mask
return self._mask
def isInRange(self, value):
"""
@summary: Check if value is in range represented by mask
@param value: Python value
@return: true if value is in type range
"""
if self._signed:
return not (value < -(self.mask() >> 1) or value > (self.mask() >> 1))
else:
return not (value < 0 or value > self.mask())
def __sizeof__(self): def __sizeof__(self):
""" """
@@ -291,7 +219,7 @@ class SimpleType(Type, CallableValue):
""" """
return self._typeSize return self._typeSize
def __cmp__(self, other): def __eq__(self, other):
""" """
@summary: Compare two simple type @summary: Compare two simple type
Call inner value compare operator Call inner value compare operator
@@ -301,7 +229,19 @@ class SimpleType(Type, CallableValue):
""" """
if not isinstance(other, SimpleType): if not isinstance(other, SimpleType):
other = self.__class__(other) other = self.__class__(other)
return self.value.__cmp__(other.value) return self.value.__eq__(other.value)
def __ne__(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
"""
if not isinstance(other, SimpleType):
other = self.__class__(other)
return self.value.__ne__(other.value)
def __invert__(self): def __invert__(self):
""" """
@@ -412,57 +352,37 @@ class SimpleType(Type, CallableValue):
return bool(self.value) return bool(self.value)
class CompositeType(Type): class CompositeType(Message):
""" """
@summary: Type node in Type tree
Track type field declared in __init__ function
Ex: self.lengthOfPacket = UInt16Le() -> record lengthOfPacket as sub type of node
""" """
def __init__(self, conditional = lambda:True, optional = False, constant = False, readLen = None): def __init__(self, read_len=None, conditional=lambda: True, optional=False, constant=False):
""" """
@param conditional : Callable object
Read and Write operation depend on return of this function
@param optional: If there is no enough byte in current stream
And optional is True, read type is ignored
@param constant: Check if object value doesn't change after read operation
@param readLen: Max length in bytes can be readed from stream
Use to check length information
""" """
Type.__init__(self, conditional = conditional, optional = optional, constant = constant) super().__init__(conditional=conditional, optional=optional, constant=constant)
#list of ordoned type
self._typeName = [] # list of ordorred type
self._readLen = readLen self._type_name = []
self._read_len = read_len
def __setattr__(self, name, value): def __setattr__(self, name, value):
""" """
@summary: Track Type field
For Type field record it in same order as declared
Keep other but bot handle in read or write function
@param name: name of new attribute
@param value: value of new attribute
""" """
if name[0] != '_' and (isinstance(value, Type) or isinstance(value, tuple)) and not name in self._typeName: if name[0] != '_' and (isinstance(value, Message) or isinstance(value, tuple)) and name not in self._type_name:
self._typeName.append(name) self._type_name.append(name)
self.__dict__[name] = value self.__dict__[name] = value
def __read__(self, s): def __read__(self, s):
""" """
@summary: Read composite type
Call read on each ordered sub-type
And check read length parameter
If an error occurred rollback type already read
@param s: Stream
@raise InvalidSize: if stream is greater than readLen parameter
""" """
readLen = 0 read_len = 0
for name in self._typeName: for name in self._type_name:
try: try:
s.readType(self.__dict__[name]) s.read_type(self.__dict__[name])
readLen += sizeof(self.__dict__[name]) read_len += sizeof(self.__dict__[name])
# read is ok but read out of bound # read is ok but read out of bound
if not self._readLen is None and readLen > self._readLen.value: if self._read_len is not None and read_len > self._read_len():
# roll back # roll back
s.pos -= sizeof(self.__dict__[name]) s.seek(-sizeof(self.__dict__[name]), 1)
# and notify if not optional # and notify if not optional
if not self.__dict__[name]._optional: if not self.__dict__[name]._optional:
raise InvalidSize("Impossible to read type %s : read length is too small"%(self.__class__)) raise InvalidSize("Impossible to read type %s : read length is too small"%(self.__class__))
@@ -470,15 +390,15 @@ class CompositeType(Type):
except Exception as e: except Exception as e:
log.error("Error during read %s::%s"%(self.__class__, name)) log.error("Error during read %s::%s"%(self.__class__, name))
# roll back already read # roll back already read
for tmpName in self._typeName: for tmp_name in self._type_name:
if tmpName == name: if tmp_name == name:
break break
s.pos -= sizeof(self.__dict__[tmpName]) s.seek(-sizeof(self.__dict__[tmp_name]), 1)
raise e raise e
if not self._readLen is None and readLen < self._readLen.value: if self._read_len is not None and read_len < self._read_len():
log.debug("Still have correct data in packet %s, read it as padding"%self.__class__) log.debug("Still have correct data in packet %s, read %s bytes as padding"%(self.__class__, self._read_len() - read_len))
s.read(self._readLen.value - readLen) s.read(self._read_len() - read_len)
def __write__(self, s): def __write__(self, s):
""" """
@@ -486,9 +406,9 @@ class CompositeType(Type):
Call write on each ordered sub type Call write on each ordered sub type
@param s: Stream @param s: Stream
""" """
for name in self._typeName: for name in self._type_name:
try: try:
s.writeType(self.__dict__[name]) s.write_type(self.__dict__[name])
except Exception as e: except Exception as e:
log.error("Error during write %s::%s"%(self.__class__, name)) log.error("Error during write %s::%s"%(self.__class__, name))
raise e raise e
@@ -498,11 +418,11 @@ class CompositeType(Type):
@summary: Call sizeof on each sub type @summary: Call sizeof on each sub type
@return: sum of sizeof of each Type attributes @return: sum of sizeof of each Type attributes
""" """
if self._is_readed and not self._readLen is None: if self._is_readed and not self._read_len is None:
return self._readLen.value return self._read_len()
size = 0 size = 0
for name in self._typeName: for name in self._type_name:
size += sizeof(self.__dict__[name]) size += sizeof(self.__dict__[name])
return size return size
@@ -513,9 +433,9 @@ class CompositeType(Type):
@param other: CompositeType @param other: CompositeType
@return: True if each sub-type are equals @return: True if each sub-type are equals
""" """
if self._typeName != other._typeName: if self._type_name != other._typeName:
return False return False
for name in self._typeName: for name in self._type_name:
if self.__dict__[name] != other.__dict__[name]: if self.__dict__[name] != other.__dict__[name]:
return False return False
return True return True
@@ -705,6 +625,7 @@ class UInt24Be(SimpleType):
""" """
self.value = struct.unpack(self._structFormat, '\x00' + s.read(self._typeSize))[0] self.value = struct.unpack(self._structFormat, '\x00' + s.read(self._typeSize))[0]
class UInt24Le(SimpleType): class UInt24Le(SimpleType):
""" """
@summary: unsigned 24 bit integer @summary: unsigned 24 bit integer
@@ -734,90 +655,64 @@ class UInt24Le(SimpleType):
@summary: special read for a special type @summary: special read for a special type
@param s: Stream @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):
class Buffer(DynMessage):
""" """
@summary: String type This a raw binary bytes data
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: bytes = b"", read_len=None, conditional=lambda:True, optional: bool = False, constant: bool = False, until: bytes = None):
""" """
@param value: python string use for inner value
@param readLen: length use to read in stream (SimpleType) if 0 read entire stream
@param conditional : Callable object
Read and Write operation depend on return of this function
@param optional: If there is no enough byte in current stream
And optional is True, read type is ignored
@param constant: Check if object value doesn't change after read operation
@param unicode: Encode and decode value as unicode
@param until: read until sequence is readed or write sequence at the end of string
""" """
Type.__init__(self, conditional = conditional, optional = optional, constant = constant) super().__init__(conditional=conditional, optional=optional, constant=constant)
CallableValue.__init__(self, value)
# type use to know read length # type use to know read length
self._readLen = readLen self._read_len = read_len
self._unicode = unicode
self._until = until self._until = until
self.value = value
def __cmp__(self, other): def __eq__(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) return self.value.__eq__(other.value)
def __ne__(self, other):
"""
"""
return self.value.__ne__(other.value)
def __hash__(self): def __hash__(self):
""" """
@summary: hash function to treat simple type in hash collection
@return: hash of inner value
""" """
return hash(self.value) return hash(self.value)
def __str__(self): def __str__(self):
""" """
@summary: call when str function is call
@return: inner python string
""" """
return self.value return self.value
def __write__(self, s): def __write__(self, s):
""" """
@summary: Write the inner value after evaluation
Append until sequence if present
Encode in unicode format if asked
@param s: Stream
""" """
toWrite = self.value to_write = self.value
if not self._until is None: if not self._until is None:
toWrite += self._until to_write += self._until
s.write(to_write)
if self._unicode:
s.write(encodeUnicode(self.value))
else:
s.write(self.value)
def __read__(self, s): def __read__(self, s):
""" """
@summary: Read readLen bytes as string
If readLen is None read until 'until' sequence match
If until sequence is None read until end of stream
@param s: Stream
""" """
if self._readLen is None: if self._read_len is None:
if self._until is None: if self._until is None:
self.value = s.getvalue()[s.pos:] self.value = s.getvalue()[s.tell():]
else: else:
self.value = "" self.value = ""
while self.value[-len(self._until):] != self._until and s.dataLen() != 0: while self.value[-len(self._until):] != self._until and s.data_len() != 0:
self.value += s.read(1) self.value += s.read(1)
else: else:
self.value = s.read(self._readLen.value) self.value = s.read(self._read_len())
if self._unicode:
self.value = decodeUnicode(self.value)
def __sizeof__(self): def __sizeof__(self):
""" """
@@ -825,11 +720,9 @@ class String(Type, CallableValue):
if string is unicode encode return 2*len(str) + 2 if string is unicode encode return 2*len(str) + 2
@return: length of inner string @return: length of inner string
""" """
if self._unicode:
return 2 * len(self.value) + 2
else:
return len(self.value) return len(self.value)
def encodeUnicode(s): def encodeUnicode(s):
""" """
@summary: Encode string in unicode @summary: Encode string in unicode
@@ -852,35 +745,36 @@ def decodeUnicode(s):
i += 1 i += 1
return r return r
class Stream(StringIO):
class Stream(BytesIO):
""" """
@summary: Stream use to read all types @summary: Stream use to read all types
""" """
def dataLen(self): def data_len(self) -> int:
""" """
@return: not yet read length :returns: not yet read length
""" """
return self.len - self.pos return len(self.getvalue()) - self.tell()
def readLen(self): def read_len(self) -> int:
""" """
@summary: compute already read size Compute already read size
@return: read size of stream :returns: read size of stream
""" """
return self.pos return self.seek()
def readType(self, value): def read_type(self, value: Message):
""" """
@summary: call specific read on type object Call specific read on type object
or iterate over tuple elements or iterate over tuple elements
rollback read if error occurred during read value rollback read if error occurred during read value
@param value: (tuple | Type) object :ivar tuple | Type object
""" """
# read each tuple # read each tuple
if isinstance(value, tuple) or isinstance(value, list): if isinstance(value, tuple) or isinstance(value, list):
for element in value: for element in value:
try: try:
self.readType(element) self.read_type(element)
except Exception as e: except Exception as e:
# rollback already readed elements # rollback already readed elements
for tmpElement in value: for tmpElement in value:
@@ -888,69 +782,61 @@ class Stream(StringIO):
break break
self.pos -= sizeof(tmpElement) self.pos -= sizeof(tmpElement)
raise e raise e
return return value
# optional value not present # optional value not present
if self.dataLen() == 0 and value._optional: if self.data_len() == 0 and value._optional:
return return
value.read(self) value.read(self)
return value
def readNextType(self, t): def readNextType(self, t):
""" """
@summary: read next type but didn't consume it @summary: read next type but didn't consume it
@param t: Type element @param t: Type element
""" """
self.readType(t) self.read_type(t)
self.pos -= sizeof(t) self.pos -= sizeof(t)
def writeType(self, value): def write_type(self, value: Message):
""" """
@summary: Call specific write on type object Call specific write on type object
or iterate over tuple element or iterate over tuple element
@param value: (tuple | Type)
:ivar Type: Type to write
""" """
# write each element of tuple # write each element of tuple
if isinstance(value, tuple) or isinstance(value, list): if isinstance(value, tuple) or isinstance(value, list):
for element in value: for element in value:
self.writeType(element) self.write_type(element)
return return self
value.write(self) value.write(self)
return self
class ArrayType(Type):
class ArrayType(Message):
""" """
@summary: Factory af n element @summary: Factory af n element
""" """
def __init__(self, typeFactory, init = None, readLen = None, conditional = lambda:True, optional = False, constant = False): def __init__(self, type_factory, init=None, read_len=None, conditional=lambda:True, optional=False, constant=False):
""" """
@param typeFactory: class use to init new element on read
@param init: init array
@param readLen: number of element in sequence
@param conditional : Callable object
Read and Write operation depend on return of this function
@param optional: If there is no enough byte in current stream
And optional is True, read type is ignored
@param constant: Check if object value doesn't change after read operation
""" """
Type.__init__(self, conditional, optional, constant) super().__init__(conditional, optional, constant)
self._typeFactory = typeFactory self._type_factory = type_factory
self._readLen = readLen self._read_len = read_len
self._array = [] self._array = init or []
if not init is None:
self._array = init
def __read__(self, s): def __read__(self, s):
""" """
@summary: Create readLen new object and read it
@param s: Stream
""" """
self._array = [] self._array = []
i = 0 i = 0
#self._readLen is None means that array will be read until end of stream # self._read_len is None means that array will be read until end of stream
while self._readLen is None or i < self._readLen.value: while self._read_len is None or i < self._read_len():
element = self._typeFactory() element = self._type_factory()
element._optional = self._readLen is None element._optional = self._read_len is None
s.readType(element) s.read_type(element)
if not element._is_readed: if not element._is_readed:
break break
self._array.append(element) self._array.append(element)
@@ -958,10 +844,8 @@ class ArrayType(Type):
def __write__(self, s): def __write__(self, s):
""" """
@summary: Just write array
@param s: Stream
""" """
s.writeType(self._array) s.write_type(self._array)
def __getitem__(self, item): def __getitem__(self, item):
""" """
@@ -976,7 +860,10 @@ class ArrayType(Type):
""" """
return sizeof(self._array) return sizeof(self._array)
class FactoryType(Type): def __len__(self):
return len(self._array)
class FactoryType(Message):
""" """
@summary: Call a factory callback at read or write time @summary: Call a factory callback at read or write time
Wrapp attribute access to inner type Wrapp attribute access to inner type
@@ -990,7 +877,7 @@ class FactoryType(Type):
And optional is True, read type is ignored And optional is True, read type is ignored
@param constant: Check if object value doesn't change after read operation @param constant: Check if object value doesn't change after read operation
""" """
Type.__init__(self, conditional, optional, constant) Message.__init__(self, conditional, optional, constant)
self._factory = factory self._factory = factory
if not callable(factory): if not callable(factory):
self._factory = lambda:factory self._factory = lambda:factory
@@ -1003,7 +890,7 @@ class FactoryType(Type):
@param s: Stream @param s: Stream
""" """
self._value = self._factory() self._value = self._factory()
s.readType(self._value) s.read_type(self._value)
def __write__(self, s): def __write__(self, s):
""" """
@@ -1011,7 +898,7 @@ class FactoryType(Type):
@param s: Stream @param s: Stream
""" """
self._value = self._factory() self._value = self._factory()
s.writeType(self._value) s.write_type(self._value)
def __getattr__(self, name): def __getattr__(self, name):
""" """

View File

@@ -22,8 +22,8 @@ Remote Session Scenario File format
Private protocol format to save events Private protocol format to save events
""" """
from rdpy.core.type import CompositeType, FactoryType, UInt8, UInt16Le, UInt32Le, String, sizeof, Stream from rdpy.model.type import CompositeType, FactoryType, UInt8, UInt16Le, UInt32Le, Buffer, sizeof, Stream
from rdpy.core import log, error from rdpy.model import log, error
import time import time
class EventType(object): class EventType(object):
@@ -63,7 +63,7 @@ class Event(CompositeType):
return c(readLen = self.length) return c(readLen = self.length)
log.debug("unknown event type : %s"%hex(self.type.value)) log.debug("unknown event type : %s"%hex(self.type.value))
#read entire packet #read entire packet
return String(readLen = self.length) return Buffer(readLen = self.length)
if event is None: if event is None:
event = FactoryType(EventFactory) event = FactoryType(EventFactory)
@@ -88,7 +88,7 @@ class UpdateEvent(CompositeType):
self.bpp = UInt8() self.bpp = UInt8()
self.format = UInt8() self.format = UInt8()
self.length = UInt32Le(lambda:sizeof(self.data)) self.length = UInt32Le(lambda:sizeof(self.data))
self.data = String(readLen = self.length) self.data = Buffer(readLen = self.length)
class InfoEvent(CompositeType): class InfoEvent(CompositeType):
""" """
@@ -98,13 +98,13 @@ class InfoEvent(CompositeType):
def __init__(self, readLen = None): def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen) CompositeType.__init__(self, readLen = readLen)
self.lenUsername = UInt16Le(lambda:sizeof(self.username)) self.lenUsername = UInt16Le(lambda:sizeof(self.username))
self.username = String(readLen = self.lenUsername) self.username = Buffer(readLen = self.lenUsername)
self.lenPassword = UInt16Le(lambda:sizeof(self.password)) self.lenPassword = UInt16Le(lambda:sizeof(self.password))
self.password = String(readLen = self.lenPassword) self.password = Buffer(readLen = self.lenPassword)
self.lenDomain = UInt16Le(lambda:sizeof(self.domain)) self.lenDomain = UInt16Le(lambda:sizeof(self.domain))
self.domain = String(readLen = self.lenDomain) self.domain = Buffer(readLen = self.lenDomain)
self.lenHostname = UInt16Le(lambda:sizeof(self.hostname)) self.lenHostname = UInt16Le(lambda:sizeof(self.hostname))
self.hostname = String(readLen = self.lenHostname) self.hostname = Buffer(readLen = self.lenHostname)
class ScreenEvent(CompositeType): class ScreenEvent(CompositeType):
""" """
@@ -177,7 +177,7 @@ class FileRecorder(object):
self._lastEventTimer = now self._lastEventTimer = now
s = Stream() s = Stream()
s.writeType(e) s.write_type(e)
self._file.write(s.getvalue()) self._file.write(s.getvalue())
@@ -276,10 +276,10 @@ class FileReader(object):
""" """
@summary: read next event and return it @summary: read next event and return it
""" """
if self._s.dataLen() == 0: if self._s.data_len() == 0:
return None return None
e = Event() e = Event()
self._s.readType(e) self._s.read_type(e)
return e return e
def createRecorder(path): def createRecorder(path):

View File

@@ -1,291 +0,0 @@
#
# Copyright (c) 2014-2015 Sylvain Peyrefitte
#
# This file is part of rdpy.
#
# rdpy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
"""
@summary: Credential Security Support Provider
@see: https://msdn.microsoft.com/en-us/library/cc226764.aspx
"""
from pyasn1.type import namedtype, univ, tag
import pyasn1.codec.der.encoder as der_encoder
import pyasn1.codec.der.decoder as der_decoder
import pyasn1.codec.ber.encoder as ber_encoder
from rdpy.core.type import Stream
from twisted.internet import protocol
from OpenSSL import crypto
from rdpy.security import x509
from rdpy.core import error
class NegoToken(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('negoToken', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
)
class NegoData(univ.SequenceOf):
"""
@summary: contain spnego ntlm of kerberos data
@see: https://msdn.microsoft.com/en-us/library/cc226781.aspx
"""
componentType = NegoToken()
class TSRequest(univ.Sequence):
"""
@summary: main structure
@see: https://msdn.microsoft.com/en-us/library/cc226780.aspx
"""
componentType = namedtype.NamedTypes(
namedtype.NamedType('version', univ.Integer().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.OptionalNamedType('negoTokens', NegoData().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
namedtype.OptionalNamedType('authInfo', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))),
namedtype.OptionalNamedType('pubKeyAuth', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))),
namedtype.OptionalNamedType('errorCode', univ.Integer().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4)))
)
class TSCredentials(univ.Sequence):
"""
@summary: contain user information
@see: https://msdn.microsoft.com/en-us/library/cc226782.aspx
"""
componentType = namedtype.NamedTypes(
namedtype.NamedType('credType', univ.Integer().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.NamedType('credentials', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
)
class TSPasswordCreds(univ.Sequence):
"""
@summary: contain username and password
@see: https://msdn.microsoft.com/en-us/library/cc226783.aspx
"""
componentType = namedtype.NamedTypes(
namedtype.NamedType('domainName', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.NamedType('userName', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
namedtype.NamedType('password', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)))
)
class TSCspDataDetail(univ.Sequence):
"""
@summary: smart card credentials
@see: https://msdn.microsoft.com/en-us/library/cc226785.aspx
"""
componentType = namedtype.NamedTypes(
namedtype.NamedType('keySpec', univ.Integer().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.OptionalNamedType('cardName', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
namedtype.OptionalNamedType('readerName', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))),
namedtype.OptionalNamedType('containerName', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))),
namedtype.OptionalNamedType('cspName', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4)))
)
class TSSmartCardCreds(univ.Sequence):
"""
@summary: smart card credentials
@see: https://msdn.microsoft.com/en-us/library/cc226784.aspx
"""
componentType = namedtype.NamedTypes(
namedtype.NamedType('pin', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
namedtype.NamedType('cspData', TSCspDataDetail().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
namedtype.OptionalNamedType('userHint', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))),
namedtype.OptionalNamedType('domainHint', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3)))
)
class OpenSSLRSAPublicKey(univ.Sequence):
"""
@summary: asn1 public rsa key
@see: https://tools.ietf.org/html/rfc3447
"""
componentType = namedtype.NamedTypes(
namedtype.NamedType('unknow', univ.Integer()),
namedtype.NamedType('modulus', univ.Integer()),
namedtype.NamedType('publicExponent', univ.Integer()),
)
def encodeDERTRequest(negoTypes = [], authInfo = None, pubKeyAuth = None):
"""
@summary: create TSRequest from list of Type
@param negoTypes: {list(Type)}
@param authInfo: {str} authentication info TSCredentials encrypted with authentication protocol
@param pubKeyAuth: {str} public key encrypted with authentication protocol
@return: {str} TRequest der encoded
"""
negoData = NegoData().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))
#fill nego data tokens
i = 0
for negoType in negoTypes:
s = Stream()
s.writeType(negoType)
negoToken = NegoToken()
negoToken.setComponentByPosition(0, s.getvalue())
negoData.setComponentByPosition(i, negoToken)
i += 1
request = TSRequest()
request.setComponentByName("version", univ.Integer(2).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
if i > 0:
request.setComponentByName("negoTokens", negoData)
if not authInfo is None:
request.setComponentByName("authInfo", univ.OctetString(authInfo).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)))
if not pubKeyAuth is None:
request.setComponentByName("pubKeyAuth", univ.OctetString(pubKeyAuth).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3)))
return der_encoder.encode(request)
def decodeDERTRequest(s):
"""
@summary: Decode the stream as
@param s: {str}
"""
return der_decoder.decode(s, asn1Spec=TSRequest())[0]
def getNegoTokens(tRequest):
negoData = tRequest.getComponentByName("negoTokens")
return [Stream(negoData.getComponentByPosition(i).getComponentByPosition(0).asOctets()) for i in range(len(negoData))]
def getPubKeyAuth(tRequest):
return tRequest.getComponentByName("pubKeyAuth").asOctets()
def encodeDERTCredentials(domain, username, password):
passwordCred = TSPasswordCreds()
passwordCred.setComponentByName("domainName", univ.OctetString(domain).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
passwordCred.setComponentByName("userName", univ.OctetString(username).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
passwordCred.setComponentByName("password", univ.OctetString(password).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)))
credentials = TSCredentials()
credentials.setComponentByName("credType", univ.Integer(1).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
credentials.setComponentByName("credentials", univ.OctetString(der_encoder.encode(passwordCred)).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
return der_encoder.encode(credentials)
class CSSP(protocol.Protocol):
"""
@summary: Handle CSSP connection
Proxy class for authentication
"""
def __init__(self, layer, authenticationProtocol):
"""
@param layer: {type.Layer.RawLayer}
@param authenticationProtocol: {sspi.IAuthenticationProtocol}
"""
self._layer = layer
self._authenticationProtocol = authenticationProtocol
#IGenericSecurityService
self._interface = None
#function call at the end of nego
self._callback = None
def setFactory(self, factory):
"""
@summary: Call by RawLayer Factory
@param param: RawLayerClientFactory or RawLayerFactory
"""
self._layer.setFactory(factory)
def dataReceived(self, data):
"""
@summary: Inherit from twisted.protocol class
main event of received data
@param data: string data receive from twisted
"""
self._layer.dataReceived(data)
def connectionLost(self, reason):
"""
@summary: Call from twisted engine when protocol is closed
@param reason: str represent reason of close connection
"""
self._layer._factory.connectionLost(self, reason)
def connectionMade(self):
"""
@summary: install proxy
"""
self._layer.transport = self
self._layer.getDescriptor = lambda:self.transport
self._layer.connectionMade()
def write(self, data):
"""
@summary: write data on transport layer
@param data: {str}
"""
self.transport.write(data)
def startTLS(self, sslContext):
"""
@summary: start TLS protocol
@param sslContext: {ssl.ClientContextFactory | ssl.DefaultOpenSSLContextFactory} context use for TLS protocol
"""
self.transport.startTLS(sslContext)
def startNLA(self, sslContext, callback = None):
"""
@summary: start NLA authentication
@param sslContext: {ssl.ClientContextFactory | ssl.DefaultOpenSSLContextFactory} context use for TLS protocol
@param callback: {function} function call when cssp layer is read
"""
self._callback = callback
self.startTLS(sslContext)
#send negotiate message
self.transport.write(encodeDERTRequest( negoTypes = [ self._authenticationProtocol.getNegotiateMessage() ] ))
#next state is receive a challenge
self.dataReceived = self.recvChallenge
def recvChallenge(self, data):
"""
@summary: second state in cssp automata
@param data : {str} all data available on buffer
"""
request = decodeDERTRequest(data)
message, self._interface = self._authenticationProtocol.getAuthenticateMessage(getNegoTokens(request)[0])
#get back public key
#convert from der to ber...
pubKeyDer = crypto.dump_privatekey(crypto.FILETYPE_ASN1, self.transport.protocol._tlsConnection.get_peer_certificate().get_pubkey())
pubKey = der_decoder.decode(pubKeyDer, asn1Spec=OpenSSLRSAPublicKey())[0]
rsa = x509.RSAPublicKey()
rsa.setComponentByName("modulus", univ.Integer(pubKey.getComponentByName('modulus')._value))
rsa.setComponentByName("publicExponent", univ.Integer(pubKey.getComponentByName('publicExponent')._value))
self._pubKeyBer = ber_encoder.encode(rsa)
#send authenticate message with public key encoded
self.transport.write(encodeDERTRequest( negoTypes = [ message ], pubKeyAuth = self._interface.GSS_WrapEx(self._pubKeyBer)))
#next step is received public key incremented by one
self.dataReceived = self.recvPubKeyInc
def recvPubKeyInc(self, data):
"""
@summary: the server send the pubKeyBer + 1
@param data : {str} all data available on buffer
"""
request = decodeDERTRequest(data)
pubKeyInc = self._interface.GSS_UnWrapEx(getPubKeyAuth(request))
#check pubKeyInc = self._pubKeyBer + 1
if not (self._pubKeyBer[1:] == pubKeyInc[1:] and ord(self._pubKeyBer[0]) + 1 == ord(pubKeyInc[0])):
raise error.InvalidExpectedDataException("CSSP : Invalid public key increment")
domain, user, password = self._authenticationProtocol.getEncodedCredentials()
#send credentials
self.transport.write(encodeDERTRequest( authInfo = self._interface.GSS_WrapEx(encodeDERTCredentials(domain, user, password))))
#reset state back to normal state
self.dataReceived = lambda x: self.__class__.dataReceived(self, x)
if not self._callback is None:
self._callback()

View File

@@ -1,224 +0,0 @@
#
# Copyright (c) 2014-2015 Sylvain Peyrefitte
#
# This file is part of rdpy.
#
# rdpy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
"""
Transport packet layer implementation
Use to build correct size packet and handle slow path and fast path mode
"""
from rdpy.core.layer import RawLayer
from rdpy.core.type import UInt8, UInt16Be, sizeof
from rdpy.core.error import CallPureVirtualFuntion
class Action(object):
"""
@see: http://msdn.microsoft.com/en-us/library/cc240621.aspx
@see: http://msdn.microsoft.com/en-us/library/cc240589.aspx
"""
FASTPATH_ACTION_FASTPATH = 0x0
FASTPATH_ACTION_X224 = 0x3
class SecFlags(object):
"""
@see: http://msdn.microsoft.com/en-us/library/cc240621.aspx
"""
#hihi 'secure' checksum but private key is public !!!
FASTPATH_OUTPUT_SECURE_CHECKSUM = 0x1
FASTPATH_OUTPUT_ENCRYPTED = 0x2
class IFastPathListener(object):
"""
@summary: Fast path packet listener
Usually X224 layer
"""
def recvFastPath(self, secFlag, fastPathS):
"""
@summary: Call when fast path packet is received
@param secFlag: {SecFlags}
@param fastPathS: {Stream}
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recvFastPath", "IFastPathListener"))
def initFastPath(self, fastPathSender):
"""
@summary: initialize stack
@param fastPathSender: {IFastPathSender}
"""
self.setFastPathSender(fastPathSender)
fastPathSender.setFastPathListener(self)
def setFastPathSender(self, fastPathSender):
"""
@param fastPathSender : {IFastPathSender}
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "setFastPathSender", "IFastPathListener"))
class IFastPathSender(object):
"""
@summary: Fast path send capability
"""
def sendFastPath(self, secFlag, fastPathS):
"""
@summary: Send fastPathS Type as fast path packet
@param secFlag: {integer} Security flag for fastpath packet
@param fastPathS: {Type | Tuple} type transform to stream and send as fastpath
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendFastPath", "IFastPathSender"))
def initFastPath(self, fastPathListener):
"""
@summary: initialize stack
@param fastPathListener: {IFastPathListener}
"""
self.setFastPathListener(fastPathListener)
fastPathListener.setFastPathSender(self)
def setFastPathListener(self, fastPathListener):
"""
@param fastPathListener: {IFastPathListener}
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "setFastPathListener", "IFastPathSender"))
class TPKT(RawLayer, IFastPathSender):
"""
@summary: TPKT layer in RDP protocol stack
represent the Raw Layer in stack (first layer)
This layer only handle size of packet and determine if is a fast path packet
"""
def __init__(self, presentation):
"""
@param presentation: {Layer} presentation layer, in RDP case is x224 layer
"""
RawLayer.__init__(self, presentation)
#length may be coded on more than 1 bytes
self._lastShortLength = UInt8()
#fast path listener
self._fastPathListener = None
#last secure flag
self._secFlag = 0
def setFastPathListener(self, fastPathListener):
"""
@param fastPathListener : {IFastPathListener}
@note: implement IFastPathSender
"""
self._fastPathListener = fastPathListener
def connect(self):
"""
@summary: Call when transport layer connection
is made (inherit from RawLayer)
"""
#header is on two bytes
self.expect(2, self.readHeader)
#no connection automata on this layer
if not self._presentation is None:
self._presentation.connect()
def readHeader(self, data):
"""
@summary: Read header of TPKT packet
@param data: {Stream} received from twisted layer
"""
#first read packet version
version = UInt8()
data.readType(version)
#classic packet
if version.value == Action.FASTPATH_ACTION_X224:
#padding
data.readType(UInt8())
#read end header
self.expect(2, self.readExtendedHeader)
else:
#is fast path packet
self._secFlag = ((version.value >> 6) & 0x3)
data.readType(self._lastShortLength)
if self._lastShortLength.value & 0x80:
#size is 1 byte more
self.expect(1, self.readExtendedFastPathHeader)
return
self.expect(self._lastShortLength.value - 2, self.readFastPath)
def readExtendedHeader(self, data):
"""
@summary: Header may be on 4 bytes
@param data: {Stream} from twisted layer
"""
#next state is read data
size = UInt16Be()
data.readType(size)
self.expect(size.value - 4, self.readData)
def readExtendedFastPathHeader(self, data):
"""
@summary: Fast path header may be on 1 byte more
@param data: {Stream} from twisted layer
"""
leftPart = UInt8()
data.readType(leftPart)
self._lastShortLength.value &= ~0x80
packetSize = (self._lastShortLength.value << 8) + leftPart.value
#next state is fast patn data
self.expect(packetSize - 3, self.readFastPath)
def readFastPath(self, data):
"""
@summary: Fast path data
@param data: {Stream} from twisted layer
"""
self._fastPathListener.recvFastPath(self._secFlag, data)
self.expect(2, self.readHeader)
def readData(self, data):
"""
@summary: Read classic TPKT packet, last state in tpkt automata
@param data: {Stream} with correct size
"""
#next state is pass to
self._presentation.recv(data)
self.expect(2, self.readHeader)
def send(self, message):
"""
@summary: Send encompassed data
@param message: {network.Type} message to send
"""
RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_X224), UInt8(0), UInt16Be(sizeof(message) + 4), message))
def sendFastPath(self, secFlag, fastPathS):
"""
@param fastPathS: {Type | Tuple} type transform to stream and send as fastpath
@param secFlag: {integer} Security flag for fastpath packet
"""
RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_FASTPATH | ((secFlag & 0x3) << 6)), UInt16Be((sizeof(fastPathS) + 3) | 0x8000), fastPathS))
def startTLS(self, sslContext):
"""
@summary: start TLS protocol
@param sslContext: {ssl.ClientContextFactory | ssl.DefaultOpenSSLContextFactory} context use for TLS protocol
"""
self.transport.startTLS(sslContext)
def startNLA(self, sslContext, callback):
"""
@summary: use to start NLA (NTLM over SSL) protocol
must be called after startTLS function
"""
self.transport.startNLA(sslContext, callback)

View File

@@ -1,765 +0,0 @@
#
# Copyright (c) 2014-2015 Sylvain Peyrefitte
#
# This file is part of rdpy.
#
# rdpy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
"""
Implement Remote FrameBuffer protocol use in VNC client and server
@see: http://www.realvnc.com/docs/rfbproto.pdf
@todo: server side of protocol
@todo: more encoding rectangle
"""
from rdpy.core.layer import RawLayer, RawLayerClientFactory
from rdpy.core.type import UInt8, UInt16Be, UInt32Be, SInt32Be, String, CompositeType
from rdpy.core.error import InvalidValue, CallPureVirtualFuntion
from rdpy.security.pyDes import des
import rdpy.core.log as log
class ProtocolVersion(object):
"""
@summary: Different protocol version
"""
UNKNOWN = ""
RFB003003 = "RFB 003.003\n"
RFB003007 = "RFB 003.007\n"
RFB003008 = "RFB 003.008\n"
class SecurityType(object):
"""
@summary: Security type supported
"""
INVALID = 0
NONE = 1
VNC = 2
class Pointer(object):
"""
@summary: Mouse event code (which button)
actually in RFB specification only
three buttons are supported
"""
BUTTON1 = 0x1
BUTTON2 = 0x2
BUTTON3 = 0x4
class Encoding(object):
"""
@summary: Encoding types of FrameBuffer update
"""
RAW = 0
class ClientToServerMessages(object):
"""
@summary: Client to server messages types
"""
PIXEL_FORMAT = 0
ENCODING = 2
FRAME_BUFFER_UPDATE_REQUEST = 3
KEY_EVENT = 4
POINTER_EVENT = 5
CUT_TEXT = 6
class PixelFormat(CompositeType):
"""
@summary: Pixel format structure
"""
def __init__(self):
CompositeType.__init__(self)
self.BitsPerPixel = UInt8(32)
self.Depth = UInt8(24)
self.BigEndianFlag = UInt8(False)
self.TrueColorFlag = UInt8(True)
self.RedMax = UInt16Be(255)
self.GreenMax = UInt16Be(255)
self.BlueMax = UInt16Be(255)
self.RedShift = UInt8(16)
self.GreenShift = UInt8(8)
self.BlueShift = UInt8(0)
self.padding = (UInt16Be(), UInt8())
class ServerInit(CompositeType):
"""
@summary: Server init structure
FrameBuffer configuration
"""
def __init__(self):
CompositeType.__init__(self)
self.width = UInt16Be()
self.height = UInt16Be()
self.pixelFormat = PixelFormat()
class FrameBufferUpdateRequest(CompositeType):
"""
@summary: FrameBuffer update request send from client to server
Incremental means that server send update with a specific
order, and client must draw orders in same order
"""
def __init__(self, incremental = False, x = 0, y = 0, width = 0, height = 0):
CompositeType.__init__(self)
self.incremental = UInt8(incremental)
self.x = UInt16Be(x)
self.y = UInt16Be(y)
self.width = UInt16Be(width)
self.height = UInt16Be(height)
class Rectangle(CompositeType):
"""
@summary: Header message of update rectangle
"""
def __init__(self):
CompositeType.__init__(self)
self.x = UInt16Be()
self.y = UInt16Be()
self.width = UInt16Be()
self.height = UInt16Be()
self.encoding = SInt32Be()
class KeyEvent(CompositeType):
"""
@summary: Key event structure message
Use to send a keyboard event
"""
def __init__(self):
CompositeType.__init__(self)
self.downFlag = UInt8(False)
self.padding = UInt16Be()
self.key = UInt32Be()
class PointerEvent(CompositeType):
"""
@summary: Pointer event structure message
Use to send mouse event
"""
def __init__(self):
CompositeType.__init__(self)
self.mask = UInt8()
self.x = UInt16Be()
self.y = UInt16Be()
class ClientCutText(CompositeType):
"""
@summary: Client cut text message message
Use to simulate copy paste (ctrl-c ctrl-v) only for text
"""
def __init__(self, text = ""):
CompositeType.__init__(self)
self.padding = (UInt16Be(), UInt8())
self.size = UInt32Be(len(text))
self.message = String(text)
class ServerCutTextHeader(CompositeType):
"""
@summary: Cut text header send from server to client
"""
def __init__(self):
CompositeType.__init__(self)
self.padding = (UInt16Be(), UInt8())
self.size = UInt32Be()
class RFB(RawLayer):
"""
@summary: Implement RFB protocol
"""
def __init__(self, listener):
"""
@param listener: listener use to inform new orders
"""
RawLayer.__init__(self)
#set client listener
self._clientListener = listener
#useful for RFB protocol
self._callbackBody = None
#protocol version negotiated
self._version = String(ProtocolVersion.RFB003008)
#number security launch by server
self._securityLevel = UInt8(SecurityType.INVALID)
#shared FrameBuffer client init message
self._sharedFlag = UInt8(False)
#server init message
#which contain FrameBuffer dim and pixel format
self._serverInit = ServerInit()
#client pixel format
self._pixelFormat = PixelFormat()
#server name
self._serverName = String()
#nb rectangle
self._nbRect = 0
#current rectangle header
self._currentRect = Rectangle()
#for vnc security type
self._password = '\0' * 8
def expectWithHeader(self, expectedHeaderLen, callbackBody):
"""
2nd level of waiting event
read expectedHeaderLen that contain body size
@param expectedHeaderLen: contains the number of bytes, which body length needs to be encoded
@param callbackBody: next state use when expected date from expectedHeaderLen
are received
"""
self._callbackBody = callbackBody
self.expect(expectedHeaderLen, self.expectedBody)
def expectedBody(self, data):
"""
Read header and wait header value to call next state
@param data: Stream that length are to header length (1|2|4 bytes)
set next state to callBack body when length read from header
are received
"""
bodyLen = None
if data.len == 1:
bodyLen = UInt8()
elif data.len == 2:
bodyLen = UInt16Be()
elif data.len == 4:
bodyLen = UInt32Be()
else:
log.error("invalid header length")
return
data.readType(bodyLen)
self.expect(bodyLen.value, self._callbackBody)
def connect(self):
"""
Call when transport layer connection is made
in Client mode -> wait protocol version
"""
self.expect(12, self.recvProtocolVersion)
def readProtocolVersion(self, data):
"""
Read protocol version
@param data: Stream may contain protocol version string (ProtocolVersion)
"""
data.readType(self._version)
if not self._version.value in [ProtocolVersion.RFB003003, ProtocolVersion.RFB003007, ProtocolVersion.RFB003008]:
self._version.value = ProtocolVersion.UNKNOWN
def recvProtocolVersion(self, data):
"""
Read handshake packet
If protocol receive from client is unknown
try best version of protocol version (ProtocolVersion.RFB003008)
@param data: Stream
"""
self.readProtocolVersion(data)
if self._version.value == ProtocolVersion.UNKNOWN:
log.info("Unknown protocol version %s send 003.008"%data.getvalue())
#protocol version is unknown try best version we can handle
self._version.value = ProtocolVersion.RFB003008
#send same version of
self.send(self._version)
#next state read security
if self._version.value == ProtocolVersion.RFB003003:
self.expect(4, self.recvSecurityServer)
else:
self.expectWithHeader(1, self.recvSecurityList)
def recvSecurityServer(self, data):
"""
Security handshake for 33 RFB version
Server imposed security level
@param data: well formed packet
"""
#TODO!!!
pass
def recvSecurityList(self, data):
"""
Read security list packet send from server to client
@param data: Stream that contains well formed packet
"""
securityList = []
while data.dataLen() > 0:
securityElement = UInt8()
data.readType(securityElement)
securityList.append(securityElement)
#select high security level
for s in securityList:
if s.value in [SecurityType.NONE, SecurityType.VNC] and s > self._securityLevel:
self._securityLevel = s
break
#send back security level choosen
self.send(self._securityLevel)
if self._securityLevel.value == SecurityType.VNC:
self.expect(16, self.recvVNCChallenge)
else:
self.expect(4, self.recvSecurityResult)
def recvVNCChallenge(self, data):
"""
@summary: receive challenge in VNC authentication case
@param data: Stream that contain well formed packet
"""
key = (self._password + '\0' * 8)[:8]
newkey = []
for ki in range(len(key)):
bsrc = ord(key[ki])
btgt = 0
for i in range(8):
if bsrc & (1 << i):
btgt = btgt | (1 << 7-i)
newkey.append(chr(btgt))
algo = des(newkey)
self.send(String(algo.encrypt(data.getvalue())))
self.expect(4, self.recvSecurityResult)
def recvSecurityResult(self, data):
"""
Read security result packet
Use by server to inform connection status of client
@param data: Stream that contain well formed packet
"""
result = UInt32Be()
data.readType(result)
if result == UInt32Be(1):
log.info("Authentification failed")
if self._version.value == ProtocolVersion.RFB003008:
self.expectWithHeader(4, self.recvSecurityFailed)
else:
log.debug("Authentification OK")
self.sendClientInit()
def recvSecurityFailed(self, data):
"""
Send by server to inform reason of why it's refused client
@param data: Stream that contains well formed packet
"""
log.info("Security failed cause to %s"%data.getvalue())
def recvServerInit(self, data):
"""
Read server init packet
@param data: Stream that contains well formed packet
"""
data.readType(self._serverInit)
self.expectWithHeader(4, self.recvServerName)
def recvServerName(self, data):
"""
@summary: Read server name
@param data: Stream that contains well formed packet
"""
data.readType(self._serverName)
log.info("Server name %s"%str(self._serverName))
#end of handshake
#send pixel format
self.sendPixelFormat(self._pixelFormat)
#write encoding
self.sendSetEncoding()
#request entire zone
self.sendFramebufferUpdateRequest(False, 0, 0, self._serverInit.width.value, self._serverInit.height.value)
#now i'm ready to send event
self._clientListener.onReady()
self.expect(1, self.recvServerOrder)
def recvServerOrder(self, data):
"""
@summary: Read order receive from server
Main function for bitmap update from server to client
@param data: Stream that contains well formed packet
"""
packetType = UInt8()
data.readType(packetType)
if packetType.value == 0:
self.expect(3, self.recvFrameBufferUpdateHeader)
elif packetType.value == 2:
self._clientListener.onBell()
elif packetType.value == 3:
self.expect(7, self.recvServerCutTextHeader)
else:
log.error("Unknown message type %s"%packetType.value)
def recvFrameBufferUpdateHeader(self, data):
"""
@summary: Read frame buffer update packet header
@param data: Stream that contains well formed packet
"""
#padding
nbRect = UInt16Be()
self._nbRect = data.readType((UInt8(), nbRect))
self._nbRect = nbRect.value
self.expect(12, self.recvRectHeader)
def recvRectHeader(self, data):
"""
@summary: Read rectangle header
@param data: Stream that contains well formed packet
"""
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)
def recvRectBody(self, data):
"""
@summary: Read body of rectangle update
@param data: Stream that contains well formed packet
"""
self._clientListener.recvRectangle(self._currentRect, self._pixelFormat, data.getvalue())
self._nbRect -= 1
#if there is another rect to read
if self._nbRect == 0:
#job is finish send a request
self.sendFramebufferUpdateRequest(True, 0, 0, self._serverInit.width.value, self._serverInit.height.value)
self.expect(1, self.recvServerOrder)
else:
self.expect(12, self.recvRectHeader)
def recvServerCutTextHeader(self, data):
"""
@summary: callback when expect server cut text message
@param data: Stream that contains well formed packet
"""
header = ServerCutTextHeader()
data.readType(header)
self.expect(header.size.value, self.recvServerCutTextBody)
def recvServerCutTextBody(self, data):
"""
@summary: Receive server cut text body
@param data: Stream that contains well formed packet
"""
self._clientListener.onCutText(data.getvalue())
self.expect(1, self.recvServerOrder)
def sendClientInit(self):
"""
@summary: Send client init packet
"""
self.send(self._sharedFlag)
self.expect(20, self.recvServerInit)
def sendPixelFormat(self, pixelFormat):
"""
@summary: Send pixel format structure
Very important packet that inform the image struct supported by the client
@param pixelFormat: PixelFormat struct
"""
self.send((UInt8(ClientToServerMessages.PIXEL_FORMAT), UInt16Be(), UInt8(), pixelFormat))
def sendSetEncoding(self):
"""
@summary: Send set encoding packet
Actually only RAW bitmap encoding are used
"""
self.send((UInt8(ClientToServerMessages.ENCODING), UInt8(), UInt16Be(1), SInt32Be(Encoding.RAW)))
def sendFramebufferUpdateRequest(self, incremental, x, y, width, height):
"""
@summary: Request server the specified zone
incremental means request only change before last update
"""
self.send((UInt8(ClientToServerMessages.FRAME_BUFFER_UPDATE_REQUEST), FrameBufferUpdateRequest(incremental, x, y, width, height)))
def sendKeyEvent(self, keyEvent):
"""
@summary: Write key event packet
@param keyEvent: KeyEvent struct to send
"""
self.send((UInt8(ClientToServerMessages.KEY_EVENT), keyEvent))
def sendPointerEvent(self, pointerEvent):
"""
@summary: Write pointer event packet
@param pointerEvent: PointerEvent struct use
"""
self.send((UInt8(ClientToServerMessages.POINTER_EVENT), pointerEvent))
def sendClientCutText(self, text):
"""
@summary: write client cut text event packet
"""
self.send((UInt8(ClientToServerMessages.CUT_TEXT), ClientCutText(text)))
class RFBClientListener(object):
"""
@summary: Interface use to expose event receive from RFB layer
"""
def recvRectangle(self, rectangle, pixelFormat, data):
"""
@summary: Receive rectangle order
Main update order type
@param rectangle: Rectangle type header of packet
@param pixelFormat: pixelFormat struct of current session
@param data: image data
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recvRectangle", "RFBClientListener"))
def onBell(self):
"""
@summary: receive bip from server
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onBell", "RFBClientListener"))
def onCutText(self, text):
"""
@summary: Receive cut text from server
@param text: text inner cut text event
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onCutText", "RFBClientListener"))
class RFBClientController(RFBClientListener):
"""
@summary: Class use to manage RFB order and dispatch throw observers for client side
"""
def __init__(self):
self._clientObservers = []
#rfb layer to send client orders
self._rfbLayer = RFB(self)
self._isReady = False
def getProtocol(self):
"""
@return: RFB layer build by controller
"""
return self._rfbLayer
def addClientObserver(self, observer):
"""
@summary: Add new observer for this protocol
@param observer: new observer
"""
self._clientObservers.append(observer)
observer._clientListener = self
def getWidth(self):
"""
@return: width of framebuffer
"""
return self._rfbLayer._serverInit.width.value
def getHeight(self):
"""
@return: height of framebuffer
"""
return self._rfbLayer._serverInit.height.value
def getScreen(self):
"""
@return: (width, height) of screen
"""
return (self.getWidth(), self.getHeight())
def setPassword(self, password):
"""
@summary: set password for vnc authentication type
@param password: password for session
"""
self._rfbLayer._password = password
def onReady(self):
"""
@summary: rfb stack is reday to send or receive event
"""
self._isReady = True
for observer in self._clientObservers:
observer.onReady()
def recvRectangle(self, rectangle, pixelFormat, data):
"""
@summary: Receive rectangle order
Main update order type
@param rectangle: Rectangle type header of packet
@param pixelFormat: pixelFormat struct of current session
@param data: image data
"""
for observer in self._clientObservers:
observer.onUpdate(rectangle.width.value, rectangle.height.value, rectangle.x.value, rectangle.y.value, pixelFormat, rectangle.encoding, data)
def onBell(self):
"""
@summary: biiiip event
"""
for observer in self._clientObservers:
observer.onBell()
def onCutText(self, text):
"""
@summary: receive cut text event
@param text: text in cut text event
"""
for observer in self._clientObservers:
observer.onCutText(text)
def onClose(self):
"""
@summary: handle on close events
"""
if not self._isReady:
log.debug("Close on non ready layer means authentication error")
return
for observer in self._clientObservers:
observer.onClose()
def sendKeyEvent(self, isDown, key):
"""
@summary: Send a key event throw RFB protocol
@param isDown: boolean notify if key is pressed or not (True if key is pressed)
@param key: ASCII code of key
"""
if not self._isReady:
log.info("Try to send key event on non ready layer")
return
try:
event = KeyEvent()
event.downFlag.value = isDown
event.key.value = key
self._rfbLayer.sendKeyEvent(event)
except InvalidValue:
log.debug("Try to send an invalid key event")
def sendPointerEvent(self, mask, x, y):
"""
@summary: Send a pointer event throw RFB protocol
@param mask: mask of button if button 1 and 3 are pressed then mask is 00000101
@param x: x coordinate of mouse pointer
@param y: y pointer of mouse pointer
"""
if not self._isReady:
log.info("Try to send pointer event on non ready layer")
return
try:
event = PointerEvent()
event.mask.value = mask
event.x.value = x
event.y.value = y
self._rfbLayer.sendPointerEvent(event)
except InvalidValue:
log.debug("Try to send an invalid pointer event")
def close(self):
"""
@summary: close rfb stack
"""
self._rfbLayer.close()
class ClientFactory(RawLayerClientFactory):
"""
@summary: Twisted Factory of RFB protocol
"""
def buildRawLayer(self, addr):
"""
@summary: Function call by twisted on connection
@param addr: address where client try to connect
"""
controller = RFBClientController()
self.buildObserver(controller, addr)
return controller.getProtocol()
def connectionLost(self, rfblayer, reason):
"""
@summary: Override this method to handle connection lost
@param rfblayer: rfblayer that cause connectionLost event
@param reason: twisted reason
"""
#call controller
rfblayer._clientListener.onClose()
def buildObserver(self, controller, addr):
"""
@summary: Build an RFB observer object
@param controller: controller use for rfb session
@param addr: destination
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ClientFactory"))
class RFBClientObserver(object):
"""
@summary: RFB client protocol observer
"""
def __init__(self, controller):
self._controller = controller
self._controller.addClientObserver(self)
def getController(self):
"""
@return: RFB controller use by observer
"""
return self._controller
def keyEvent(self, isPressed, key):
"""
@summary: Send a key event
@param isPressed: state of key
@param key: ASCII code of key
"""
self._controller.sendKeyEvent(isPressed, key)
def mouseEvent(self, button, x, y):
"""
@summary: Send a mouse event to RFB Layer
@param button: button number which is pressed (0,1,2,3,4,5,6,7)
@param x: x coordinate of mouse pointer
@param y: y coordinate of mouse pointer
"""
mask = 0
if button == 1:
mask = 1
elif button > 1:
mask = 1 << button - 1
self._controller.sendPointerEvent(mask, x, y)
def onReady(self):
"""
@summary: Event when network stack is ready to receive or send event
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RFBClientObserver"))
def onClose(self):
"""
@summary: On close event
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onClose", "RFBClientObserver"))
def onUpdate(self, width, height, x, y, pixelFormat, encoding, data):
"""
@summary: Receive FrameBuffer update
@param width : width of image
@param height : height of image
@param x : x position
@param y : y position
@param pixelFormat : pixel format struct from rfb.types
@param encoding : encoding struct from rfb.types
@param data : in respect of dataFormat and pixelFormat
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onUpdate", "RFBClientObserver"))
def onCutText(self, text):
"""
@summary: event when server send cut text event
@param text: text received
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onCutText", "RFBClientObserver"))
def onBell(self):
"""
@summary: event when server send biiip
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onBell", "RFBClientObserver"))

View File

@@ -24,7 +24,7 @@
def KSA(key): def KSA(key):
keylength = len(key) keylength = len(key)
S = range(256) S = list(range(256))
j = 0 j = 0
for i in range(256): for i in range(256):
@@ -50,8 +50,10 @@ def RC4(key):
S = KSA(key) S = KSA(key)
return PRGA(S) return PRGA(S)
def RC4Key(key):
return RC4([ord(c) for c in key])
def crypt(keystream, plaintext): def RC4Key(key):
return "".join([chr(ord(c) ^ keystream.next()) for c in plaintext]) return RC4(key)
def crypt(keystream, plaintext: bytes) -> bytes:
return bytes([c ^ next(keystream) for c in plaintext])

View File

@@ -23,13 +23,12 @@ Qt specific code
QRemoteDesktop is a widget use for render in rdpy QRemoteDesktop is a widget use for render in rdpy
""" """
from PyQt4 import QtGui, QtCore from PyQt5 import QtWidgets
from rdpy.protocol.rfb.rfb import RFBClientObserver from rdpy.core.rdp import RDPClientObserver
from rdpy.protocol.rdp.rdp import RDPClientObserver from rdpy.model.error import CallPureVirtualFuntion
from rdpy.core.error import CallPureVirtualFuntion
import sys import sys
import rdpy.core.log as log import rdpy.model.log as log
import rle import rle
class QAdaptor(object): class QAdaptor(object):
@@ -72,112 +71,10 @@ def qtImageFormatFromRFBPixelFormat(pixelFormat):
@summary: convert RFB pixel format to QtGui.QImage format @summary: convert RFB pixel format to QtGui.QImage format
""" """
if pixelFormat.BitsPerPixel.value == 32: if pixelFormat.BitsPerPixel.value == 32:
return QtGui.QImage.Format_RGB32 return QtWidgets.QImage.Format_RGB32
elif pixelFormat.BitsPerPixel.value == 16: elif pixelFormat.BitsPerPixel.value == 16:
return QtGui.QImage.Format_RGB16 return QtWidgets.QImage.Format_RGB16
class RFBClientQt(RFBClientObserver, QAdaptor):
"""
@summary: QAdaptor for specific RFB protocol stack
is to an RFB observer
"""
def __init__(self, controller):
"""
@param controller: controller for observer
@param width: width of widget
@param height: height of widget
"""
RFBClientObserver.__init__(self, controller)
self._widget = QRemoteDesktop(1024, 800, self)
def getWidget(self):
"""
@return: widget use for render
"""
return self._widget
def onUpdate(self, width, height, x, y, pixelFormat, encoding, data):
"""
@summary: Implement RFBClientObserver interface
@param width: width of new image
@param height: height of new image
@param x: x position of new image
@param y: y position of new image
@param pixelFormat: pixefFormat structure in rfb.message.PixelFormat
@param encoding: encoding type rfb.message.Encoding
@param data: image data in accordance with pixel format and encoding
"""
imageFormat = qtImageFormatFromRFBPixelFormat(pixelFormat)
if imageFormat is None:
log.error("Receive image in bad format")
return
image = QtGui.QImage(data, width, height, imageFormat)
self._widget.notifyImage(x, y, image, width, height)
def onCutText(self, text):
"""
@summary: event when server send cut text event
@param text: text received
"""
def onBell(self):
"""
@summary: event when server send biiip
"""
def onReady(self):
"""
@summary: Event when network stack is ready to receive or send event
"""
(width, height) = self._controller.getScreen()
self._widget.resize(width, height)
def sendMouseEvent(self, e, isPressed):
"""
@summary: Convert Qt mouse event to RFB mouse event
@param e: qMouseEvent
@param isPressed: event come from press or release action
"""
button = e.button()
buttonNumber = 0
if button == QtCore.Qt.LeftButton:
buttonNumber = 1
elif button == QtCore.Qt.MidButton:
buttonNumber = 2
elif button == QtCore.Qt.RightButton:
buttonNumber = 3
self.mouseEvent(buttonNumber, e.pos().x(), e.pos().y())
def sendKeyEvent(self, e, isPressed):
"""
@summary: Convert Qt key press event to RFB press event
@param e: qKeyEvent
@param isPressed: event come from press or release action
"""
self.keyEvent(isPressed, e.nativeVirtualKey())
def sendWheelEvent(self, e):
"""
@summary: Convert Qt wheel event to RFB Wheel event
@param e: QKeyEvent
@param isPressed: event come from press or release action
"""
pass
def closeEvent(self, e):
"""
@summary: Call when you want to close connection
@param: QCloseEvent
"""
self._controller.close()
def onClose(self):
"""
@summary: Call when stack is close
"""
#do something maybe a message
pass
def RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data): def RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data):
""" """
@@ -195,36 +92,36 @@ def RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data):
if isCompress: if isCompress:
buf = bytearray(width * height * 2) buf = bytearray(width * height * 2)
rle.bitmap_decompress(buf, width, height, data, 2) rle.bitmap_decompress(buf, width, height, data, 2)
image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB555) image = QtWidgets.QImage(buf, width, height, QtWidgets.QImage.Format_RGB555)
else: 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 = QtWidgets.QImage(data, width, height, QtWidgets.QImage.Format_RGB555).transformed(QtWidgets.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
elif bitsPerPixel == 16: elif bitsPerPixel == 16:
if isCompress: if isCompress:
buf = bytearray(width * height * 2) buf = bytearray(width * height * 2)
rle.bitmap_decompress(buf, width, height, data, 2) rle.bitmap_decompress(buf, width, height, data, 2)
image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB16) image = QtWidgets.QImage(buf, width, height, QtWidgets.QImage.Format_RGB16)
else: 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 = QtWidgets.QImage(data, width, height, QtWidgets.QImage.Format_RGB16).transformed(QtWidgets.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
elif bitsPerPixel == 24: elif bitsPerPixel == 24:
if isCompress: if isCompress:
buf = bytearray(width * height * 3) buf = bytearray(width * height * 3)
rle.bitmap_decompress(buf, width, height, data, 3) rle.bitmap_decompress(buf, width, height, data, 3)
image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB888) image = QtWidgets.QImage(buf, width, height, QtWidgets.QImage.Format_RGB888)
else: 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 = QtWidgets.QImage(data, width, height, QtWidgets.QImage.Format_RGB888).transformed(QtWidgets.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
elif bitsPerPixel == 32: elif bitsPerPixel == 32:
if isCompress: if isCompress:
buf = bytearray(width * height * 4) buf = bytearray(width * height * 4)
rle.bitmap_decompress(buf, width, height, data, 4) rle.bitmap_decompress(buf, width, height, data, 4)
image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB32) image = QtWidgets.QImage(buf, width, height, QtWidgets.QImage.Format_RGB32)
else: 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 = QtWidgets.QImage(data, width, height, QtWidgets.QImage.Format_RGB32).transformed(QtWidgets.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
else: else:
log.error("Receive image in bad format") log.error("Receive image in bad format")
image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32) image = QtWidgets.QImage(width, height, QtWidgets.QImage.Format_RGB32)
return image return image
class RDPClientQt(RDPClientObserver, QAdaptor): class RDPClientQt(RDPClientObserver, QAdaptor):
@@ -303,7 +200,7 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
@param isCompress: {bool} use RLE compression @param isCompress: {bool} use RLE compression
@param data: {str} bitmap data @param data: {str} bitmap data
""" """
image = RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data); image = RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data)
#if image need to be cut #if image need to be cut
#For bit alignement server may send more than image pixel #For bit alignement server may send more than image pixel
self._widget.notifyImage(destLeft, destTop, image, destRight - destLeft + 1, destBottom - destTop + 1) self._widget.notifyImage(destLeft, destTop, image, destRight - destLeft + 1, destBottom - destTop + 1)
@@ -311,17 +208,26 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
def onReady(self): def onReady(self):
""" """
@summary: Call when stack is ready @summary: Call when stack is ready
@see: rdp.RDPClientObserver.onReady
""" """
#do something maybe a loader #do something maybe a loader
def onSessionReady(self):
"""
@summary: Windows session is ready
@see: rdp.RDPClientObserver.onSessionReady
"""
pass
def onClose(self): def onClose(self):
""" """
@summary: Call when stack is close @summary: Call when stack is close
@see: rdp.RDPClientObserver.onClose
""" """
#do something maybe a message #do something maybe a message
class QRemoteDesktop(QtGui.QWidget): class QRemoteDesktop(QtWidgets.QWidget):
""" """
@summary: Qt display widget @summary: Qt display widget
""" """
@@ -336,16 +242,10 @@ class QRemoteDesktop(QtGui.QWidget):
self._adaptor = adaptor self._adaptor = adaptor
#set correct size #set correct size
self.resize(width, height) self.resize(width, height)
#refresh stack of image
#because we can update image only in paint
#event function. When protocol receive image
#we will stock into refresh list
#and in paint event paint list of all refresh images
self._refresh = []
#bind mouse event #bind mouse event
self.setMouseTracking(True) self.setMouseTracking(True)
#buffer image #buffer image
self._buffer = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32) self._buffer = QtWidgets.QImage(width, height, QtWidgets.QImage.Format_RGB32)
def notifyImage(self, x, y, qimage, width, height): def notifyImage(self, x, y, qimage, width, height):
""" """
@@ -354,8 +254,9 @@ class QRemoteDesktop(QtGui.QWidget):
@param y: y position of new image @param y: y position of new image
@param qimage: new QImage @param qimage: new QImage
""" """
#save in refresh list (order is important) #fill buffer image
self._refresh.append((x, y, qimage, width, height)) with QtWidgets.QPainter(self._buffer) as qp:
qp.drawImage(x, y, qimage, 0, 0, width, height)
#force update #force update
self.update() self.update()
@@ -365,25 +266,18 @@ class QRemoteDesktop(QtGui.QWidget):
@param width: {int} width of widget @param width: {int} width of widget
@param height: {int} height of widget @param height: {int} height of widget
""" """
self._buffer = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32) self._buffer = QtWidgets.QImage(width, height, QtWidgets.QImage.Format_RGB32)
QtGui.QWidget.resize(self, width, height) QtWidgets.QWidget.resize(self, width, height)
def paintEvent(self, e): def paintEvent(self, e):
""" """
@summary: Call when Qt renderer engine estimate that is needed @summary: Call when Qt renderer engine estimate that is needed
@param e: QEvent @param e: QEvent
""" """
#fill buffer image
with QtGui.QPainter(self._buffer) as qp:
#draw image
for (x, y, image, width, height) in self._refresh:
qp.drawImage(x, y, image, 0, 0, width, height)
#draw in widget #draw in widget
with QtGui.QPainter(self) as qp: with QtWidgets.QPainter(self) as qp:
qp.drawImage(0, 0, self._buffer) qp.drawImage(0, 0, self._buffer)
self._refresh = []
def mouseMoveEvent(self, event): def mouseMoveEvent(self, event):
""" """
@summary: Call when mouse move @summary: Call when mouse move

View File

@@ -4,7 +4,7 @@ import setuptools
from distutils.core import setup, Extension from distutils.core import setup, Extension
setup(name='rdpy', setup(name='rdpy',
version='1.3.1', version='2.0.0',
description='Remote Desktop Protocol in Python', description='Remote Desktop Protocol in Python',
long_description=""" 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. 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.
@@ -16,14 +16,11 @@ setup(name='rdpy',
url='https://github.com/citronneur/rdpy', url='https://github.com/citronneur/rdpy',
packages=[ packages=[
'rdpy', 'rdpy',
'rdpy.core', 'rdpy.model',
'rdpy.security', 'rdpy.security',
'rdpy.protocol', 'rdpy.core.pdu',
'rdpy.protocol.rdp', 'rdpy.core.nla',
'rdpy.protocol.rdp.pdu', 'rdpy.core.t125',
'rdpy.protocol.rdp.nla',
'rdpy.protocol.rdp.t125',
'rdpy.protocol.rfb',
'rdpy.ui' 'rdpy.ui'
], ],
ext_modules=[Extension('rle', ['ext/rle.c'])], ext_modules=[Extension('rle', ['ext/rle.c'])],
@@ -37,11 +34,10 @@ setup(name='rdpy',
'bin/rdpy-vncscreenshot.py' 'bin/rdpy-vncscreenshot.py'
], ],
install_requires=[ install_requires=[
'twisted', 'PyQt5',
'pyopenssl', 'PyQt5-sip',
'service_identity', 'service_identity',
'qt4reactor',
'rsa', 'rsa',
'pyasn1', 'pyasn1'
], ],
) )

View File

@@ -56,7 +56,7 @@ class LayerTest(unittest.TestCase):
""" """
class TestAutomata(rdpy.core.layer.RawLayer): class TestAutomata(rdpy.core.layer.RawLayer):
def expectedCallBack(self, data): def expectedCallBack(self, data):
if data.dataLen() == 4: if data.data_len() == 4:
raise LayerTest.LayerCaseException() raise LayerTest.LayerCaseException()
t = TestAutomata() t = TestAutomata()
@@ -69,7 +69,7 @@ class LayerTest(unittest.TestCase):
""" """
class TestAutomata(rdpy.core.layer.RawLayer): class TestAutomata(rdpy.core.layer.RawLayer):
def expectedCallBack(self, data): def expectedCallBack(self, data):
if data.dataLen() == 4: if data.data_len() == 4:
raise LayerTest.LayerCaseException() raise LayerTest.LayerCaseException()
t = TestAutomata() t = TestAutomata()

View File

@@ -56,7 +56,7 @@ class TypeTest(unittest.TestCase):
def __write__(self, s): def __write__(self, s):
raise Exception() raise Exception()
s = rdpy.core.type.Stream() s = rdpy.core.type.Stream()
self.assertRaises(Exception, s.writeType, TestType(conditional = lambda:True)) self.assertRaises(Exception, s.write_type, TestType(conditional = lambda:True))
@unittest.expectedFailure @unittest.expectedFailure
def test_type_write_conditional_false(self): def test_type_write_conditional_false(self):
@@ -67,7 +67,7 @@ class TypeTest(unittest.TestCase):
def __write__(self, s): def __write__(self, s):
raise Exception() raise Exception()
s = rdpy.core.type.Stream() s = rdpy.core.type.Stream()
self.assertRaises(Exception, s.writeType, TestType(conditional = lambda:False)) self.assertRaises(Exception, s.write_type, TestType(conditional = lambda:False))
def test_type_read_conditional_true(self): def test_type_read_conditional_true(self):
""" """
@@ -77,7 +77,7 @@ class TypeTest(unittest.TestCase):
def __read__(self, s): def __read__(self, s):
raise Exception() raise Exception()
s = rdpy.core.type.Stream() s = rdpy.core.type.Stream()
self.assertRaises(Exception, s.readType, TestType(conditional = lambda:True)) self.assertRaises(Exception, s.read_type, TestType(conditional = lambda:True))
@unittest.expectedFailure @unittest.expectedFailure
def test_type_read_conditional_false(self): def test_type_read_conditional_false(self):
@@ -88,7 +88,7 @@ class TypeTest(unittest.TestCase):
def __read__(self, s): def __read__(self, s):
raise Exception() raise Exception()
s = rdpy.core.type.Stream() s = rdpy.core.type.Stream()
self.assertRaises(Exception, s.readType, TestType(conditional = lambda:False)) self.assertRaises(Exception, s.read_type, TestType(conditional = lambda:False))
def test_sizeof_conditional_true(self): def test_sizeof_conditional_true(self):
@@ -138,7 +138,7 @@ class TypeTest(unittest.TestCase):
@summary: test write uint8 in stream @summary: test write uint8 in stream
""" """
s = rdpy.core.type.Stream() s = rdpy.core.type.Stream()
s.writeType(rdpy.core.type.UInt8(1)) s.write_type(rdpy.core.type.UInt8(1))
self.assertEqual(''.join(s.buflist), '\x01', "invalid stream write") self.assertEqual(''.join(s.buflist), '\x01', "invalid stream write")
def test_stream_write_uint16Le_type(self): def test_stream_write_uint16Le_type(self):
@@ -146,7 +146,7 @@ class TypeTest(unittest.TestCase):
@summary: test write UInt16Le in stream @summary: test write UInt16Le in stream
""" """
s = rdpy.core.type.Stream() s = rdpy.core.type.Stream()
s.writeType(rdpy.core.type.UInt16Le(1)) s.write_type(rdpy.core.type.UInt16Le(1))
self.assertEqual(''.join(s.buflist), '\x01\x00', "invalid stream write") self.assertEqual(''.join(s.buflist), '\x01\x00', "invalid stream write")
def test_stream_write_uint16Be_type(self): def test_stream_write_uint16Be_type(self):
@@ -154,7 +154,7 @@ class TypeTest(unittest.TestCase):
@summary: test write UInt16Be in stream @summary: test write UInt16Be in stream
""" """
s = rdpy.core.type.Stream() s = rdpy.core.type.Stream()
s.writeType(rdpy.core.type.UInt16Be(1)) s.write_type(rdpy.core.type.UInt16Be(1))
self.assertEqual(''.join(s.buflist), '\x00\x01', "invalid stream write") self.assertEqual(''.join(s.buflist), '\x00\x01', "invalid stream write")
def test_stream_write_uint24Le_type(self): def test_stream_write_uint24Le_type(self):
@@ -162,7 +162,7 @@ class TypeTest(unittest.TestCase):
@summary: test write UInt24Le in stream @summary: test write UInt24Le in stream
""" """
s = rdpy.core.type.Stream() s = rdpy.core.type.Stream()
s.writeType(rdpy.core.type.UInt24Le(1)) s.write_type(rdpy.core.type.UInt24Le(1))
self.assertEqual(''.join(s.buflist), '\x01\x00\x00', "invalid stream write") self.assertEqual(''.join(s.buflist), '\x01\x00\x00', "invalid stream write")
def test_stream_write_uint24Be_type(self): def test_stream_write_uint24Be_type(self):
@@ -170,7 +170,7 @@ class TypeTest(unittest.TestCase):
@summary: test write uint24Be in stream @summary: test write uint24Be in stream
""" """
s = rdpy.core.type.Stream() s = rdpy.core.type.Stream()
s.writeType(rdpy.core.type.UInt24Be(1)) s.write_type(rdpy.core.type.UInt24Be(1))
self.assertEqual(''.join(s.buflist), '\x00\x00\x01', "invalid stream write") self.assertEqual(''.join(s.buflist), '\x00\x00\x01', "invalid stream write")
def test_stream_write_uint32Le_type(self): def test_stream_write_uint32Le_type(self):
@@ -178,7 +178,7 @@ class TypeTest(unittest.TestCase):
@summary: test write UInt32Le in stream @summary: test write UInt32Le in stream
""" """
s = rdpy.core.type.Stream() s = rdpy.core.type.Stream()
s.writeType(rdpy.core.type.UInt32Le(1)) s.write_type(rdpy.core.type.UInt32Le(1))
self.assertEqual(''.join(s.buflist), '\x01\x00\x00\x00', "invalid stream write") self.assertEqual(''.join(s.buflist), '\x01\x00\x00\x00', "invalid stream write")
def test_stream_write_uint32Be_type(self): def test_stream_write_uint32Be_type(self):
@@ -186,7 +186,7 @@ class TypeTest(unittest.TestCase):
@summary: test write UInt32Be in stream @summary: test write UInt32Be in stream
""" """
s = rdpy.core.type.Stream() s = rdpy.core.type.Stream()
s.writeType(rdpy.core.type.UInt32Be(1)) s.write_type(rdpy.core.type.UInt32Be(1))
self.assertEqual(''.join(s.buflist), '\x00\x00\x00\x01', "invalid stream write") self.assertEqual(''.join(s.buflist), '\x00\x00\x00\x01', "invalid stream write")
def test_stream_read_uint8_type(self): def test_stream_read_uint8_type(self):
@@ -195,9 +195,9 @@ class TypeTest(unittest.TestCase):
""" """
s = rdpy.core.type.Stream('\x01') s = rdpy.core.type.Stream('\x01')
t = rdpy.core.type.UInt8() t = rdpy.core.type.UInt8()
s.readType(t) s.read_type(t)
self.assertEqual(t.value, 1, "invalid stream read value") self.assertEqual(t.value, 1, "invalid stream read value")
self.assertEqual(s.dataLen(), 0, "not read all stream") self.assertEqual(s.data_len(), 0, "not read all stream")
def test_stream_read_uint16Le_type(self): def test_stream_read_uint16Le_type(self):
""" """
@@ -205,9 +205,9 @@ class TypeTest(unittest.TestCase):
""" """
s = rdpy.core.type.Stream('\x01\x00') s = rdpy.core.type.Stream('\x01\x00')
t = rdpy.core.type.UInt16Le() t = rdpy.core.type.UInt16Le()
s.readType(t) s.read_type(t)
self.assertEqual(t.value, 1, "invalid stream read value") self.assertEqual(t.value, 1, "invalid stream read value")
self.assertEqual(s.dataLen(), 0, "not read all stream") self.assertEqual(s.data_len(), 0, "not read all stream")
def test_stream_read_uint16Be_type(self): def test_stream_read_uint16Be_type(self):
""" """
@@ -215,9 +215,9 @@ class TypeTest(unittest.TestCase):
""" """
s = rdpy.core.type.Stream('\x00\x01') s = rdpy.core.type.Stream('\x00\x01')
t = rdpy.core.type.UInt16Be() t = rdpy.core.type.UInt16Be()
s.readType(t) s.read_type(t)
self.assertEqual(t.value, 1, "invalid stream read value") self.assertEqual(t.value, 1, "invalid stream read value")
self.assertEqual(s.dataLen(), 0, "not read all stream") self.assertEqual(s.data_len(), 0, "not read all stream")
def test_stream_read_uint24Le_type(self): def test_stream_read_uint24Le_type(self):
""" """
@@ -225,9 +225,9 @@ class TypeTest(unittest.TestCase):
""" """
s = rdpy.core.type.Stream('\x01\x00\x00') s = rdpy.core.type.Stream('\x01\x00\x00')
t = rdpy.core.type.UInt24Le() t = rdpy.core.type.UInt24Le()
s.readType(t) s.read_type(t)
self.assertEqual(t.value, 1, "invalid stream read value") self.assertEqual(t.value, 1, "invalid stream read value")
self.assertEqual(s.dataLen(), 0, "not read all stream") self.assertEqual(s.data_len(), 0, "not read all stream")
def test_stream_read_uint24Be_type(self): def test_stream_read_uint24Be_type(self):
""" """
@@ -235,9 +235,9 @@ class TypeTest(unittest.TestCase):
""" """
s = rdpy.core.type.Stream('\x00\x00\x01') s = rdpy.core.type.Stream('\x00\x00\x01')
t = rdpy.core.type.UInt24Be() t = rdpy.core.type.UInt24Be()
s.readType(t) s.read_type(t)
self.assertEqual(t.value, 1, "invalid stream read") self.assertEqual(t.value, 1, "invalid stream read")
self.assertEqual(s.dataLen(), 0, "not read all stream") self.assertEqual(s.data_len(), 0, "not read all stream")
def test_stream_read_uint32Le_type(self): def test_stream_read_uint32Le_type(self):
""" """
@@ -245,9 +245,9 @@ class TypeTest(unittest.TestCase):
""" """
s = rdpy.core.type.Stream('\x01\x00\x00\x00') s = rdpy.core.type.Stream('\x01\x00\x00\x00')
t = rdpy.core.type.UInt32Le() t = rdpy.core.type.UInt32Le()
s.readType(t) s.read_type(t)
self.assertEqual(t.value, 1, "invalid stream read value") self.assertEqual(t.value, 1, "invalid stream read value")
self.assertEqual(s.dataLen(), 0, "not read all stream") self.assertEqual(s.data_len(), 0, "not read all stream")
def test_stream_read_uint32Be_type(self): def test_stream_read_uint32Be_type(self):
""" """
@@ -255,9 +255,9 @@ class TypeTest(unittest.TestCase):
""" """
s = rdpy.core.type.Stream('\x00\x00\x00\x01') s = rdpy.core.type.Stream('\x00\x00\x00\x01')
t = rdpy.core.type.UInt32Be() t = rdpy.core.type.UInt32Be()
s.readType(t) s.read_type(t)
self.assertEqual(t.value, 1, "invalid stream read") self.assertEqual(t.value, 1, "invalid stream read")
self.assertEqual(s.dataLen(), 0, "not read all stream") self.assertEqual(s.data_len(), 0, "not read all stream")
def test_stream_read_optional_singletype(self): def test_stream_read_optional_singletype(self):
""" """
@@ -267,7 +267,7 @@ class TypeTest(unittest.TestCase):
t = rdpy.core.type.SimpleType("I", 4, False, 0, optional = True) t = rdpy.core.type.SimpleType("I", 4, False, 0, optional = True)
#empty stream #empty stream
s1 = rdpy.core.type.Stream() s1 = rdpy.core.type.Stream()
s1.readType(t) s1.read_type(t)
self.assertEqual(t.value, 0, "invalid stream read optional value") self.assertEqual(t.value, 0, "invalid stream read optional value")
def test_stream_read_conditional_singletype_false(self): def test_stream_read_conditional_singletype_false(self):
@@ -277,7 +277,7 @@ class TypeTest(unittest.TestCase):
#unsigned int case #unsigned int case
t = rdpy.core.type.SimpleType("I", 4, False, 0, conditional = lambda:False) 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("\x01\x00\x00\x00")
s1.readType(t) s1.read_type(t)
self.assertEqual(t.value, 0, "invalid stream read conditional value") self.assertEqual(t.value, 0, "invalid stream read conditional value")
def test_stream_read_conditional_singletype_true(self): def test_stream_read_conditional_singletype_true(self):
@@ -287,7 +287,7 @@ class TypeTest(unittest.TestCase):
#unsigned int case #unsigned int case
t = rdpy.core.type.SimpleType("I", 4, False, 0, conditional = lambda:True) 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("\x01\x00\x00\x00")
s1.readType(t) s1.read_type(t)
self.assertEqual(t.value, 1, "invalid stream read conditional value") self.assertEqual(t.value, 1, "invalid stream read conditional value")
def test_stream_read_rollback_constant_constraint(self): def test_stream_read_rollback_constant_constraint(self):
@@ -302,9 +302,9 @@ class TypeTest(unittest.TestCase):
s = rdpy.core.type.Stream("\x00\x00\x00\x00\x00\x00\x00\x00") s = rdpy.core.type.Stream("\x00\x00\x00\x00\x00\x00\x00\x00")
try: try:
s.readType(TestComposite()) s.read_type(TestComposite())
except Exception: except Exception:
self.assertEqual(s.readLen(), 0, "invalid stream roll back operation") self.assertEqual(s.read_len(), 0, "invalid stream roll back operation")
return return
self.assertTrue(False, "Constant constraint fail") self.assertTrue(False, "Constant constraint fail")
@@ -327,9 +327,9 @@ class TypeTest(unittest.TestCase):
s = rdpy.core.type.Stream("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") s = rdpy.core.type.Stream("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
try: try:
s.readType(TestComposite()) s.read_type(TestComposite())
except Exception: except Exception:
self.assertEqual(s.readLen(), 0, "invalid stream roll back operation") self.assertEqual(s.read_len(), 0, "invalid stream roll back operation")
return return
self.assertTrue(False, "Constant constraint fail") self.assertTrue(False, "Constant constraint fail")
@@ -352,9 +352,9 @@ class TypeTest(unittest.TestCase):
s = rdpy.core.type.Stream("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") s = rdpy.core.type.Stream("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
try: try:
s.readType(TestComposite()) s.read_type(TestComposite())
except Exception: except Exception:
self.assertEqual(s.readLen(), 0, "invalid stream roll back operation") self.assertEqual(s.read_len(), 0, "invalid stream roll back operation")
return return
self.assertTrue(False, "Constant constraint fail") self.assertTrue(False, "Constant constraint fail")
@@ -369,8 +369,8 @@ class TypeTest(unittest.TestCase):
rdpy.core.type.CompositeType.__init__(self, readLen = readLen) rdpy.core.type.CompositeType.__init__(self, readLen = readLen)
self.padding = rdpy.core.type.UInt32Le(0) self.padding = rdpy.core.type.UInt32Le(0)
s = rdpy.core.type.Stream("\x00" * 10) s = rdpy.core.type.Stream("\x00" * 10)
s.readType(TestReadLength(rdpy.core.type.UInt8(10))) s.read_type(TestReadLength(rdpy.core.type.UInt8(10)))
self.assertEqual(s.dataLen(), 0, "invalid stream read trash data as padding") self.assertEqual(s.data_len(), 0, "invalid stream read trash data as padding")
def test_stream_read_with_static_length_inferior(self): def test_stream_read_with_static_length_inferior(self):
""" """
@@ -383,7 +383,7 @@ class TypeTest(unittest.TestCase):
rdpy.core.type.CompositeType.__init__(self, readLen = readLen) rdpy.core.type.CompositeType.__init__(self, readLen = readLen)
self.padding = rdpy.core.type.UInt32Le(0) self.padding = rdpy.core.type.UInt32Le(0)
s = rdpy.core.type.Stream("\x00" * 10) s = rdpy.core.type.Stream("\x00" * 10)
self.assertRaises(InvalidSize, s.readType, TestReadLength(rdpy.core.type.UInt8(2))) self.assertRaises(InvalidSize, s.read_type, TestReadLength(rdpy.core.type.UInt8(2)))
def test_stream_read_string(self): def test_stream_read_string(self):
""" """

View File

@@ -26,9 +26,9 @@ import os, sys
sys.path.insert(1, os.path.join(sys.path[0], '..')) sys.path.insert(1, os.path.join(sys.path[0], '..'))
import unittest import unittest
import rdpy.protocol.rdp.t125.ber as ber import rdpy.core.t125.ber as ber
import rdpy.core.type as type import rdpy.core.type as type
import rdpy.core.error as error
class BERTest(unittest.TestCase): class BERTest(unittest.TestCase):
""" """
@@ -40,7 +40,7 @@ class BERTest(unittest.TestCase):
@summary: test readLength function in ber module @summary: test readLength function in ber module
""" """
s1 = type.Stream() s1 = type.Stream()
s1.writeType(type.UInt8(0x1a)) s1.write_type(type.UInt8(0x1a))
s1.pos = 0 s1.pos = 0
l1 = ber.readLength(s1) l1 = ber.readLength(s1)
@@ -48,7 +48,7 @@ class BERTest(unittest.TestCase):
self.assertTrue(l1 == 0x1a, "readLength fail in small format") self.assertTrue(l1 == 0x1a, "readLength fail in small format")
s2 = type.Stream() s2 = type.Stream()
s2.writeType((type.UInt8(0x81),type.UInt8(0xab))) s2.write_type((type.UInt8(0x81), type.UInt8(0xab)))
s2.pos = 0 s2.pos = 0
l2 = ber.readLength(s2) l2 = ber.readLength(s2)
@@ -56,7 +56,7 @@ class BERTest(unittest.TestCase):
self.assertTrue(l2 == 0xab, "readLength fail in big format of size 1") self.assertTrue(l2 == 0xab, "readLength fail in big format of size 1")
s3 = type.Stream() s3 = type.Stream()
s3.writeType((type.UInt8(0x82),type.UInt16Be(0xabab))) s3.write_type((type.UInt8(0x82), type.UInt16Be(0xabab)))
s3.pos = 0 s3.pos = 0
l3 = ber.readLength(s3) l3 = ber.readLength(s3)

View File

@@ -25,7 +25,7 @@ import os, sys
# Change path so we find rdpy # Change path so we find rdpy
sys.path.insert(1, os.path.join(sys.path[0], '..')) sys.path.insert(1, os.path.join(sys.path[0], '..'))
from rdpy.protocol.rdp.nla import cssp, ntlm from rdpy.core.nla import ntlm, cssp
from rdpy.security import rc4 from rdpy.security import rc4
pubKeyHex = """ pubKeyHex = """
@@ -73,25 +73,25 @@ class TestCsspNtlm(unittest.TestCase):
@summary: test generate ntlmv2 over cssp authentication protocol @summary: test generate ntlmv2 over cssp authentication protocol
""" """
def testCSSPNTLMAuthentication(self): def testCSSPNTLMAuthentication(self):
negotiate_data_request = cssp.decodeDERTRequest(peer0_0.decode('base64')) negotiate_data_request = cssp.decode_der_trequest(peer0_0.decode('base64'))
challenge_data_request = cssp.decodeDERTRequest(peer1_0.decode('base64')) challenge_data_request = cssp.decode_der_trequest(peer1_0.decode('base64'))
authenticate_data_request = cssp.decodeDERTRequest(peer0_1.decode('base64')) authenticate_data_request = cssp.decode_der_trequest(peer0_1.decode('base64'))
negotiate_data = cssp.getNegoTokens(negotiate_data_request)[0] negotiate_data = cssp.getNegoTokens(negotiate_data_request)[0]
challenge_data = cssp.getNegoTokens(challenge_data_request)[0] challenge_data = cssp.getNegoTokens(challenge_data_request)[0]
authenticate_data = cssp.getNegoTokens(authenticate_data_request)[0] authenticate_data = cssp.getNegoTokens(authenticate_data_request)[0]
negotiate = ntlm.NegotiateMessage() negotiate = ntlm.NegotiateMessage()
negotiate_data.readType(negotiate) negotiate_data.read_type(negotiate)
challenge = ntlm.ChallengeMessage() challenge = ntlm.ChallengeMessage()
challenge_data.readType(challenge) challenge_data.read_type(challenge)
ServerChallenge = challenge.ServerChallenge.value ServerChallenge = challenge.ServerChallenge.value
ServerName = challenge.getTargetInfo() ServerName = challenge.getTargetInfo()
authenticate = ntlm.AuthenticateMessage() authenticate = ntlm.AuthenticateMessage()
authenticate_data.readType(authenticate) authenticate_data.read_type(authenticate)
NtChallengeResponseTemp = authenticate.getNtChallengeResponse() NtChallengeResponseTemp = authenticate.getNtChallengeResponse()
NTProofStr = NtChallengeResponseTemp[:16] NTProofStr = NtChallengeResponseTemp[:16]

View File

@@ -26,7 +26,7 @@ import os, sys
sys.path.insert(1, os.path.join(sys.path[0], '..')) sys.path.insert(1, os.path.join(sys.path[0], '..'))
import unittest import unittest
from rdpy.protocol.rdp import lic, sec from rdpy.core import lic, sec
import rdpy.core.type as type import rdpy.core.type as type
#dump of server request #dump of server request
@@ -91,7 +91,7 @@ class TestLic(unittest.TestCase):
def test_valid_client_licensing_error_message(self): def test_valid_client_licensing_error_message(self):
l = lic.LicenseManager(None) l = lic.LicenseManager(None)
s = type.Stream() s = type.Stream()
s.writeType(lic.createValidClientLicensingErrorMessage()) s.write_type(lic.createValidClientLicensingErrorMessage())
#reinit position #reinit position
s.pos = 0 s.pos = 0
@@ -105,9 +105,9 @@ class TestLic(unittest.TestCase):
if flag != sec.SecurityFlag.SEC_LICENSE_PKT: if flag != sec.SecurityFlag.SEC_LICENSE_PKT:
return return
s = type.Stream() s = type.Stream()
s.writeType(message) s.write_type(message)
s.pos = 0 s.pos = 0
s.readType(lic.LicPacket(lic.ClientNewLicenseRequest())) s.read_type(lic.LicPacket(lic.ClientNewLicenseRequest()))
self._state = True self._state = True
def getGCCServerSettings(self): def getGCCServerSettings(self):
class A: class A:

View File

@@ -26,7 +26,7 @@ import os, sys
sys.path.insert(1, os.path.join(sys.path[0], '..')) sys.path.insert(1, os.path.join(sys.path[0], '..'))
import unittest import unittest
import rdpy.protocol.rdp.t125.per as per import rdpy.core.t125.per as per
import rdpy.core.type as type import rdpy.core.type as type
import rdpy.core.error as error import rdpy.core.error as error
@@ -40,7 +40,7 @@ class PERTest(unittest.TestCase):
@summary: test readLength function in per module @summary: test readLength function in per module
""" """
s1 = type.Stream() s1 = type.Stream()
s1.writeType(type.UInt8(0x1a)) s1.write_type(type.UInt8(0x1a))
s1.pos = 0 s1.pos = 0
l1 = per.readLength(s1) l1 = per.readLength(s1)
@@ -48,7 +48,7 @@ class PERTest(unittest.TestCase):
self.assertTrue(l1 == 0x1a, "readLength fail in small format") self.assertTrue(l1 == 0x1a, "readLength fail in small format")
s2 = type.Stream() s2 = type.Stream()
s2.writeType(type.UInt16Be(0x1abc | 0x8000)) s2.write_type(type.UInt16Be(0x1abc | 0x8000))
s2.pos = 0 s2.pos = 0
l2 = per.readLength(s2) l2 = per.readLength(s2)
@@ -78,7 +78,7 @@ class PERTest(unittest.TestCase):
for t in [type.UInt8, type.UInt16Be, type.UInt32Be]: for t in [type.UInt8, type.UInt16Be, type.UInt32Be]:
v = t(3) v = t(3)
s = type.Stream() s = type.Stream()
s.writeType((per.writeLength(type.sizeof(v)), v)) s.write_type((per.writeLength(type.sizeof(v)), v))
s.pos = 0 s.pos = 0
self.assertTrue(per.readInteger(s) == 3, "invalid readLength for type %s" % t) self.assertTrue(per.readInteger(s) == 3, "invalid readLength for type %s" % t)
@@ -86,7 +86,7 @@ class PERTest(unittest.TestCase):
#error case #error case
for l in [0, 3, 5]: for l in [0, 3, 5]:
s = type.Stream() s = type.Stream()
s.writeType(per.writeLength(l)) s.write_type(per.writeLength(l))
s.pos = 0 s.pos = 0
self.assertRaises(error.InvalidValue, per.readInteger, s) self.assertRaises(error.InvalidValue, per.readInteger, s)

View File

@@ -26,9 +26,9 @@ import os, sys
sys.path.insert(1, os.path.join(sys.path[0], '..')) sys.path.insert(1, os.path.join(sys.path[0], '..'))
import unittest import unittest
import rdpy.protocol.rdp.tpkt as tpkt import rdpy.core.tpkt as tpkt
import rdpy.core.type as type import rdpy.core.type as type
import rdpy.core.error as error
class TPKTTest(unittest.TestCase): class TPKTTest(unittest.TestCase):
""" """
@@ -60,13 +60,13 @@ class TPKTTest(unittest.TestCase):
def connect(self): def connect(self):
pass pass
def recv(self, data): def recv(self, data):
data.readType(type.String("test_tpkt_layer_recv", constant = True)) data.read_type(type.String("test_tpkt_layer_recv", constant = True))
raise TPKTTest.TPKT_PASS() raise TPKTTest.TPKT_PASS()
message = type.String("test_tpkt_layer_recv") message = type.String("test_tpkt_layer_recv")
s = type.Stream() s = type.Stream()
s.writeType((type.UInt8(tpkt.Action.FASTPATH_ACTION_X224), type.UInt8(), type.UInt16Be(type.sizeof(message) + 4), message)) s.write_type((type.UInt8(tpkt.Action.FASTPATH_ACTION_X224), type.UInt8(), type.UInt16Be(type.sizeof(message) + 4), message))
layer = tpkt.TPKT(Presentation()) layer = tpkt.TPKT(Presentation())
layer.connect() layer.connect()
@@ -80,13 +80,13 @@ class TPKTTest(unittest.TestCase):
def setFastPathSender(self, fastPathSender): def setFastPathSender(self, fastPathSender):
pass pass
def recvFastPath(self, secFlag, fastPathS): def recvFastPath(self, secFlag, fastPathS):
fastPathS.readType(type.String("test_tpkt_layer_recv_fastpath", constant = True)) fastPathS.read_type(type.String("test_tpkt_layer_recv_fastpath", constant = True))
raise TPKTTest.TPKT_PASS() raise TPKTTest.TPKT_PASS()
message = type.String("test_tpkt_layer_recv_fastpath") message = type.String("test_tpkt_layer_recv_fastpath")
s = type.Stream() s = type.Stream()
s.writeType((type.UInt8(tpkt.Action.FASTPATH_ACTION_FASTPATH), type.UInt8(type.sizeof(message) + 2), message)) s.write_type((type.UInt8(tpkt.Action.FASTPATH_ACTION_FASTPATH), type.UInt8(type.sizeof(message) + 2), message))
layer = tpkt.TPKT(None) layer = tpkt.TPKT(None)
layer.initFastPath(FastPathLayer()) layer.initFastPath(FastPathLayer())
@@ -101,13 +101,13 @@ class TPKTTest(unittest.TestCase):
def setFastPathSender(self, fastPathSender): def setFastPathSender(self, fastPathSender):
pass pass
def recvFastPath(self, secflag, fastPathS): def recvFastPath(self, secflag, fastPathS):
fastPathS.readType(type.String("test_tpkt_layer_recv_fastpath_ext_length", constant = True)) fastPathS.read_type(type.String("test_tpkt_layer_recv_fastpath_ext_length", constant = True))
raise TPKTTest.TPKT_PASS() raise TPKTTest.TPKT_PASS()
message = type.String("test_tpkt_layer_recv_fastpath_ext_length") message = type.String("test_tpkt_layer_recv_fastpath_ext_length")
s = type.Stream() s = type.Stream()
s.writeType((type.UInt8(tpkt.Action.FASTPATH_ACTION_FASTPATH), type.UInt16Be((type.sizeof(message) + 3) | 0x8000), message)) s.write_type((type.UInt8(tpkt.Action.FASTPATH_ACTION_FASTPATH), type.UInt16Be((type.sizeof(message) + 3) | 0x8000), message))
layer = tpkt.TPKT(None) layer = tpkt.TPKT(None)
layer.initFastPath(FastPathLayer()) layer.initFastPath(FastPathLayer())

View File

@@ -26,7 +26,7 @@ import os, sys
sys.path.insert(1, os.path.join(sys.path[0], '..')) sys.path.insert(1, os.path.join(sys.path[0], '..'))
import unittest import unittest
import rdpy.protocol.rdp.x224 as x224 import rdpy.core.x224 as x224
import rdpy.core.type as type import rdpy.core.type as type
import rdpy.core.error as error import rdpy.core.error as error
@@ -53,12 +53,12 @@ class X224Test(unittest.TestCase):
""" """
class Presentation(object): class Presentation(object):
def recv(self, data): def recv(self, data):
data.readType(type.String('test_x224_layer_recvData', constant = True)) data.read_type(type.String('test_x224_layer_recvData', constant = True))
raise X224Test.X224_PASS() raise X224Test.X224_PASS()
layer = x224.X224Layer(Presentation()) layer = x224.X224Layer(Presentation())
s = type.Stream() s = type.Stream()
s.writeType((x224.X224DataHeader(), type.String('test_x224_layer_recvData'))) s.write_type((x224.X224DataHeader(), type.String('test_x224_layer_recvData')))
#reinit position #reinit position
s.pos = 0 s.pos = 0
@@ -71,10 +71,10 @@ class X224Test(unittest.TestCase):
class Transport(object): class Transport(object):
def send(self, data): def send(self, data):
s = type.Stream() s = type.Stream()
s.writeType(data) s.write_type(data)
s.pos = 0 s.pos = 0
s.readType(x224.X224DataHeader()) s.read_type(x224.X224DataHeader())
s.readType(type.String('test_x224_layer_send', constant = True)) s.read_type(type.String('test_x224_layer_send', constant = True))
raise X224Test.X224_PASS() raise X224Test.X224_PASS()
layer = x224.X224Layer(None) layer = x224.X224Layer(None)
@@ -89,10 +89,10 @@ class X224Test(unittest.TestCase):
class Transport(object): class Transport(object):
def send(self, data): def send(self, data):
s = type.Stream() s = type.Stream()
s.writeType(data) s.write_type(data)
s.pos = 0 s.pos = 0
t = x224.ClientConnectionRequestPDU() t = x224.ConnectionRequestPDU()
s.readType(t) s.read_type(t)
if t.protocolNeg.code != x224.NegociationType.TYPE_RDP_NEG_REQ: if t.protocolNeg.code != x224.NegociationType.TYPE_RDP_NEG_REQ:
raise X224Test.X224_FAIL() raise X224Test.X224_FAIL()
@@ -112,10 +112,10 @@ class X224Test(unittest.TestCase):
@summary: unit test for X224Client.recvConnectionConfirm and sendConnectionRequest function @summary: unit test for X224Client.recvConnectionConfirm and sendConnectionRequest function
check negotiation failure check negotiation failure
""" """
message = x224.ServerConnectionConfirm() message = x224.ConnectionConfirmPDU()
message.protocolNeg.code.value = x224.NegociationType.TYPE_RDP_NEG_FAILURE message.protocolNeg.code.value = x224.NegociationType.TYPE_RDP_NEG_FAILURE
s = type.Stream() s = type.Stream()
s.writeType(message) s.write_type(message)
s.pos = 0 s.pos = 0
layer = x224.Client(None) layer = x224.Client(None)
self.assertRaises(error.RDPSecurityNegoFail, layer.recvConnectionConfirm, s) self.assertRaises(error.RDPSecurityNegoFail, layer.recvConnectionConfirm, s)
@@ -141,11 +141,11 @@ class X224Test(unittest.TestCase):
def recvData(data): def recvData(data):
raise X224Test.X224_PASS() raise X224Test.X224_PASS()
message = x224.ServerConnectionConfirm() message = x224.ConnectionConfirmPDU()
message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_SSL message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_SSL
s = type.Stream() s = type.Stream()
s.writeType(message) s.write_type(message)
s.pos = 0 s.pos = 0
layer = x224.Client(Presentation()) layer = x224.Client(Presentation())
layer._transport = Transport() layer._transport = Transport()
@@ -165,17 +165,17 @@ class X224Test(unittest.TestCase):
class Transport(object): class Transport(object):
def send(self, data): def send(self, data):
if not isinstance(data, x224.ServerConnectionConfirm): if not isinstance(data, x224.ConnectionConfirmPDU):
raise X224Test.X224_FAIL() raise X224Test.X224_FAIL()
if data.protocolNeg.code.value != x224.NegociationType.TYPE_RDP_NEG_FAILURE or data.protocolNeg.failureCode.value != x224.NegotiationFailureCode.SSL_REQUIRED_BY_SERVER: if data.protocolNeg.code.value != x224.NegociationType.TYPE_RDP_NEG_FAILURE or data.protocolNeg.failureCode.value != x224.NegotiationFailureCode.SSL_REQUIRED_BY_SERVER:
raise X224Test.X224_FAIL() raise X224Test.X224_FAIL()
def close(self): def close(self):
raise X224Test.X224_PASS() raise X224Test.X224_PASS()
message = x224.ClientConnectionRequestPDU() message = x224.ConnectionRequestPDU()
message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_HYBRID message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_HYBRID
s = type.Stream() s = type.Stream()
s.writeType(message) s.write_type(message)
s.pos = 0 s.pos = 0
layer = x224.Server(None, "key", "cert", True) layer = x224.Server(None, "key", "cert", True)
@@ -204,7 +204,7 @@ class X224Test(unittest.TestCase):
tls = True tls = True
def send(self, data): def send(self, data):
if not isinstance(data, x224.ServerConnectionConfirm): if not isinstance(data, x224.ConnectionConfirmPDU):
raise X224Test.X224_FAIL() raise X224Test.X224_FAIL()
if data.protocolNeg.code.value != x224.NegociationType.TYPE_RDP_NEG_RSP or data.protocolNeg.selectedProtocol.value != x224.Protocols.PROTOCOL_SSL: if data.protocolNeg.code.value != x224.NegociationType.TYPE_RDP_NEG_RSP or data.protocolNeg.selectedProtocol.value != x224.Protocols.PROTOCOL_SSL:
raise X224Test.X224_FAIL() raise X224Test.X224_FAIL()
@@ -214,10 +214,10 @@ class X224Test(unittest.TestCase):
global connect_event global connect_event
connect_event = True connect_event = True
message = x224.ClientConnectionRequestPDU() message = x224.ConnectionRequestPDU()
message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_SSL | x224.Protocols.PROTOCOL_RDP message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_SSL | x224.Protocols.PROTOCOL_RDP
s = type.Stream() s = type.Stream()
s.writeType(message) s.write_type(message)
s.pos = 0 s.pos = 0
layer = x224.Server(Presentation(), "key", "cert") layer = x224.Server(Presentation(), "key", "cert")