3 Commits

Author SHA1 Message Date
speyrefitte
1e2cf2ef88 add missing links 2015-06-09 18:11:36 +02:00
speyrefitte
040ac6185d Merge branch 'dev' of https://github.com/citronneur/rdpy into dev 2015-06-01 18:16:39 +02:00
speyrefitte
0f30de7d20 synthax 2015-06-01 18:15:57 +02:00
10 changed files with 158 additions and 221 deletions

View File

@@ -236,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, 3, 4 or 5 button @param button: 1, 2 or 3 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

@@ -22,7 +22,7 @@
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, datetime import sys, os, getopt, time
from rdpy.core import log, error, rss from rdpy.core import log, error, rss
from rdpy.protocol.rdp import rdp from rdpy.protocol.rdp import rdp
@@ -54,12 +54,17 @@ 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("%s --- select file (%s, %s) -> %s"%(datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'),width, height, rssFilePath)) log.info("select file (%s, %s) -> %s"%(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("""%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)); log.info("""Credentials:
\tdomain : %s
\tusername : %s
\tpassword : %s
\thostname : %s
"""%(domain, username, password, hostname));
self.start() self.start()
def onClose(self): def onClose(self):
@@ -120,7 +125,7 @@ class HoneyPotServerFactory(rdp.ServerFactory):
@param addr: destination address @param addr: destination address
@see: rdp.ServerFactory.buildObserver @see: rdp.ServerFactory.buildObserver
""" """
log.info("%s --- Connection from %s:%s"%(datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'), addr.host, addr.port)) log.info("Connection from %s:%s"%(addr.host, addr.port))
return HoneyPotServer(controller, self._rssFileSizeList) return HoneyPotServer(controller, self._rssFileSizeList)
def readSize(filePath): def readSize(filePath):
@@ -141,12 +146,10 @@ def help():
@summary: Print help in console @summary: Print help in console
""" """
print """ print """
Usage: rdpy-rdphoneypot.py Usage: rdpy-rdphoneypot.py rss_filepath(1..n)
[-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__':
@@ -156,15 +159,13 @@ if __name__ == '__main__':
rssFileSizeList = [] rssFileSizeList = []
try: try:
opts, args = getopt.getopt(sys.argv[1:], "hl:k:c:L:") opts, args = getopt.getopt(sys.argv[1:], "hl:k:c:")
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":
@@ -173,12 +174,11 @@ if __name__ == '__main__':
certificateFilePath = arg certificateFilePath = arg
#build size map #build size map
log.info("%s --- Start rdphoneypot"%datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ')) log.info("Build size map")
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) -> %s"%(datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'), size[0], size[1], arg)) log.info("(%s, %s) -> %s"%(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,10 +29,7 @@ Client RDP -> | ProxyServer | ProxyClient | -> Server RDP
----------------- -----------------
""" """
import sys import sys, os, getopt, time
import os
import argparse
import time
from rdpy.core import log, error, rss from rdpy.core import log, error, rss
from rdpy.protocol.rdp import rdp from rdpy.protocol.rdp import rdp
@@ -40,12 +37,10 @@ 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}
@@ -57,14 +52,14 @@ class ProxyServer(rdp.RDPServerObserver):
self._client = None self._client = None
self._rss = rssRecorder self._rss = rssRecorder
self._clientSecurityLevel = clientSecurityLevel self._clientSecurityLevel = clientSecurityLevel
def setClient(self, client): def setClient(self, client):
""" """
@summary: Event throw by client when it's ready @summary: Event throw by client when it's ready
@param client: {ProxyClient} @param client: {ProxyClient}
""" """
self._client = client self._client = client
def onReady(self): def onReady(self):
""" """
@summary: Event use to inform state of server stack @summary: Event use to inform state of server stack
@@ -74,30 +69,29 @@ class ProxyServer(rdp.RDPServerObserver):
@see: rdp.RDPServerObserver.onReady @see: rdp.RDPServerObserver.onReady
""" """
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, self._rss.credentials(username, password, domain, self._controller.getHostname())
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())
reactor.connectTCP(self._target[0], int(self._target[1]), ProxyClientFactory(self, width, height, reactor.connectTCP(self._target[0], int(self._target[1]), ProxyClientFactory(self, width, height,
domain, username, password, self._clientSecurityLevel)) domain, username, password,self._clientSecurityLevel))
def onClose(self): def onClose(self):
""" """
@summary: Call when human client close connection @summary: Call when human client close connection
@see: rdp.RDPServerObserver.onClose @see: rdp.RDPServerObserver.onClose
""" """
# end scenario #end scenario
self._rss.close() self._rss.close()
# close network stack #close network stack
if self._client is None: if self._client is None:
return return
self._client._controller.close() self._client._controller.close()
def onKeyEventScancode(self, code, isPressed, isExtended): 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
@@ -108,10 +102,9 @@ class ProxyServer(rdp.RDPServerObserver):
""" """
if self._client is None: if self._client is None:
return return
self._client._controller.sendKeyEventScancode( self._client._controller.sendKeyEventScancode(code, isPressed, isExtended)
code, isPressed, isExtended)
self._rss.keyScancode(code, isPressed) self._rss.keyScancode(code, isPressed)
def onKeyEventUnicode(self, code, isPressed): def onKeyEventUnicode(self, code, isPressed):
""" """
@summary: Event call when a keyboard event is catch in unicode format @summary: Event call when a keyboard event is catch in unicode format
@@ -123,26 +116,24 @@ class ProxyServer(rdp.RDPServerObserver):
return return
self._client._controller.sendKeyEventUnicode(code, isPressed) self._client._controller.sendKeyEventUnicode(code, isPressed)
self._rss.keyUnicode(code, isPressed) self._rss.keyUnicode(code, isPressed)
def onPointerEvent(self, x, y, button, isPressed): def onPointerEvent(self, x, y, button, isPressed):
""" """
@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, 3, 4 or 5 button @param button: {int} 1, 2 or 3 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
""" """
if self._client is None: if self._client is None:
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)}
@@ -150,14 +141,13 @@ 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__( rdp.ServerFactory.__init__(self, 16, privateKeyFilePath, certificateFilePath)
self, 16, privateKeyFilePath, certificateFilePath)
self._target = target self._target = target
self._ouputDir = ouputDir self._ouputDir = ouputDir
self._clientSecurity = clientSecurity self._clientSecurity = clientSecurity
# use produce unique file by connection #use produce unique file by connection
self._uniqueId = 0 self._uniqueId = 0
def buildObserver(self, controller, addr): def buildObserver(self, controller, addr):
""" """
@param controller: {rdp.RDPServerController} @param controller: {rdp.RDPServerController}
@@ -165,14 +155,12 @@ class ProxyServerFactory(rdp.ServerFactory):
@see: rdp.ServerFactory.buildObserver @see: rdp.ServerFactory.buildObserver
""" """
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}
@@ -180,7 +168,7 @@ class ProxyClient(rdp.RDPClientObserver):
""" """
rdp.RDPClientObserver.__init__(self, controller) rdp.RDPClientObserver.__init__(self, controller)
self._server = server self._server = server
def onReady(self): def onReady(self):
""" """
@summary: Event use to signal that RDP stack is ready @summary: Event use to signal that RDP stack is ready
@@ -188,26 +176,25 @@ class ProxyClient(rdp.RDPClientObserver):
@see: rdp.RDPClientObserver.onReady @see: rdp.RDPClientObserver.onReady
""" """
self._server.setClient(self) self._server.setClient(self)
# maybe color depth change #maybe color depth change
self._server._controller.setColorDepth( self._server._controller.setColorDepth(self._controller.getColorDepth())
self._controller.getColorDepth())
def onSessionReady(self): def onSessionReady(self):
""" """
@summary: Windows session is ready @summary: Windows session is ready
@see: rdp.RDPClientObserver.onSessionReady @see: rdp.RDPClientObserver.onSessionReady
""" """
pass pass
def onClose(self): def onClose(self):
""" """
@summary: Event inform that stack is close @summary: Event inform that stack is close
@see: rdp.RDPClientObserver.onClose @see: rdp.RDPClientObserver.onClose
""" """
# end scenario #end scenario
self._server._rss.close() self._server._rss.close()
self._server._controller.close() self._server._controller.close()
def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data): def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
""" """
@summary: Event use to inform bitmap update @summary: Event use to inform bitmap update
@@ -222,17 +209,13 @@ 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, self._server._rss.update(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, rss.UpdateFormat.BMP if isCompress else rss.UpdateFormat.RAW, 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)
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}
@@ -250,7 +233,7 @@ class ProxyClientFactory(rdp.ClientFactory):
self._username = username self._username = username
self._password = password self._password = password
self._security = security self._security = security
def buildObserver(self, controller, addr): def buildObserver(self, controller, addr):
""" """
@summary: Build observer @summary: Build observer
@@ -259,65 +242,69 @@ class ProxyClientFactory(rdp.ClientFactory):
@see: rdp.ClientFactory.buildObserver @see: rdp.ClientFactory.buildObserver
@return: ProxyClient @return: ProxyClient
""" """
# set screen resolution #set screen resolution
controller.setScreen(self._width, self._height) controller.setScreen(self._width, self._height)
# set credential #set credential
controller.setDomain(self._domain) controller.setDomain(self._domain)
controller.setUsername(self._username) controller.setUsername(self._username)
controller.setPassword(self._password) controller.setPassword(self._password)
controller.setSecurityLevel(self._security) controller.setSecurityLevel(self._security)
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:
s = interface.split(':') return interface.split(':')
return s[0], int(s[1])
else: else:
return interface, int(defaultPort) return interface, 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__':
p = argparse.ArgumentParser( listen = "3389"
formatter_class=argparse.ArgumentDefaultsHelpFormatter) privateKeyFilePath = None
certificateFilePath = None
p.add_argument('-l', '--listen', type=parseIpPort, default="0.0.0.0:3389", ouputDirectory = None
help="<addr>[:<port>] to bind the server") #for anonymous authentication
p.add_argument('-t', '--target', type=parseIpPort, required=True, clientSecurity = rdp.SecurityLevel.RDP_LEVEL_SSL
help="<addr>[:<port>] of the target you want to connect to via proxy")
p.add_argument('-o', '--output', type=isDirectory, try:
help="output directory", required=True) opts, args = getopt.getopt(sys.argv[1:], "hl:k:c:o:rn")
p.add_argument('-s', '--sec', choices=["rdp", "tls", "nla"], except getopt.GetoptError:
default="rdp", help="set protocol security layer") help()
ssl = p.add_argument_group() for opt, arg in opts:
ssl.add_argument('-c', '--certificate', help="certificate for TLS connections") if opt == "-h":
ssl.add_argument('-k', '--key', help="private key of the given certificate for TLS connections") help()
sys.exit()
args = p.parse_args() elif opt == "-l":
listen = arg
if args.certificate and args.key and not args.sec == "nla": elif opt == "-k":
args.sec = "tls" privateKeyFilePath = arg
elif opt == "-c":
log.info("running server on {addr}, using {sec} security layer, proxying to {target}".format( certificateFilePath = arg
addr=args.listen, sec=args.sec.upper(), target=args.target)) elif opt == "-o":
reactor.listenTCP(args.listen[1], ProxyServerFactory( ouputDirectory = arg
args.target, args.output, args.key, args.certificate, mapSecurityLayer(args.sec)), elif opt == "-r":
interface=args.listen[0]) clientSecurity = rdp.SecurityLevel.RDP_LEVEL_RDP
elif opt == "-n":
reactor.run() clientSecurity = rdp.SecurityLevel.RDP_LEVEL_NLA
if ouputDirectory is None or not os.path.dirname(ouputDirectory):
log.error("%s is an invalid output directory"%ouputDirectory)
help()
sys.exit()
reactor.listenTCP(int(listen), ProxyServerFactory(parseIpPort(args[0]), ouputDirectory, privateKeyFilePath, certificateFilePath, clientSecurity))
reactor.run()

View File

@@ -23,9 +23,7 @@ example of use rdpy
take screenshot of login page take screenshot of login page
""" """
import getopt import sys, os, getopt
import os
import sys
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from rdpy.protocol.rdp import rdp from rdpy.protocol.rdp import rdp
@@ -34,17 +32,15 @@ import rdpy.core.log as log
from rdpy.core.error import RDPSecurityNegoFail from rdpy.core.error import RDPSecurityNegoFail
from twisted.internet import task 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
@@ -62,7 +58,7 @@ class RDPScreenShotFactory(rdp.ClientFactory):
self._timeout = timeout self._timeout = timeout
#NLA server can't be screenshooting #NLA server can't be screenshooting
self._security = rdp.SecurityLevel.RDP_LEVEL_SSL self._security = rdp.SecurityLevel.RDP_LEVEL_SSL
def clientConnectionLost(self, connector, reason): def clientConnectionLost(self, connector, reason):
""" """
@summary: Connection lost event @summary: Connection lost event
@@ -74,14 +70,14 @@ class RDPScreenShotFactory(rdp.ClientFactory):
self._security = rdp.SecurityLevel.RDP_LEVEL_RDP self._security = rdp.SecurityLevel.RDP_LEVEL_RDP
connector.connect() connector.connect()
return return
log.info("connection lost : %s" % reason) log.info("connection lost : %s"%reason)
RDPScreenShotFactory.__STATE__.append((connector.host, connector.port, reason)) RDPScreenShotFactory.__STATE__.append((connector.host, connector.port, reason))
RDPScreenShotFactory.__INSTANCE__ -= 1 RDPScreenShotFactory.__INSTANCE__ -= 1
if(RDPScreenShotFactory.__INSTANCE__ == 0): if(RDPScreenShotFactory.__INSTANCE__ == 0):
self._reactor.stop() self._reactor.stop()
self._app.exit() self._app.exit()
def clientConnectionFailed(self, connector, reason): def clientConnectionFailed(self, connector, reason):
""" """
@summary: Connection failed event @summary: Connection failed event
@@ -94,7 +90,8 @@ class RDPScreenShotFactory(rdp.ClientFactory):
if(RDPScreenShotFactory.__INSTANCE__ == 0): if(RDPScreenShotFactory.__INSTANCE__ == 0):
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
@@ -120,46 +117,46 @@ class RDPScreenShotFactory(rdp.ClientFactory):
self._timeout = timeout self._timeout = timeout
self._startTimeout = False self._startTimeout = False
self._reactor = reactor self._reactor = reactor
def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data): def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
""" """
@summary: callback use when bitmap is received @summary: callback use when bitmap is received
""" """
image = RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data); image = RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data);
with QtGui.QPainter(self._buffer) as qp: with QtGui.QPainter(self._buffer) as qp:
# draw image #draw image
qp.drawImage(destLeft, destTop, image, 0, 0, destRight - destLeft + 1, destBottom - destTop + 1) qp.drawImage(destLeft, destTop, image, 0, 0, destRight - destLeft + 1, destBottom - destTop + 1)
if not self._startTimeout: if not self._startTimeout:
self._startTimeout = False self._startTimeout = False
self._reactor.callLater(self._timeout, self.checkUpdate) self._reactor.callLater(self._timeout, self.checkUpdate)
def onReady(self): def onReady(self):
""" """
@summary: callback use when RDP stack is connected (just before received bitmap) @summary: callback use when RDP stack is connected (just before received bitmap)
""" """
log.info("connected %s" % addr) log.info("connected %s"%addr)
def onSessionReady(self): def onSessionReady(self):
""" """
@summary: Windows session is ready @summary: Windows session is ready
@see: rdp.RDPClientObserver.onSessionReady @see: rdp.RDPClientObserver.onSessionReady
""" """
pass pass
def onClose(self): def onClose(self):
""" """
@summary: callback use when RDP stack is closed @summary: callback use when RDP stack is closed
""" """
log.info("save screenshot into %s" % self._path) log.info("save screenshot into %s"%self._path)
self._buffer.save(self._path) self._buffer.save(self._path)
def checkUpdate(self): def checkUpdate(self):
self._controller.close(); self._controller.close();
controller.setScreen(self._width, self._height); controller.setScreen(width, 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)
def main(width, height, path, timeout, hosts): def main(width, height, path, timeout, hosts):
""" """
@summary: main algorithm @summary: main algorithm
@@ -171,40 +168,39 @@ def main(width, height, path, timeout, hosts):
""" """
#create application #create application
app = QtGui.QApplication(sys.argv) app = QtGui.QApplication(sys.argv)
#add qt4 reactor #add qt4 reactor
import qt4reactor import qt4reactor
qt4reactor.install() qt4reactor.install()
from twisted.internet import reactor from twisted.internet import reactor
for host in hosts: for host in hosts:
if ':' in host: if ':' in host:
ip, port = host.split(':') ip, port = host.split(':')
else: else:
ip, port = host, "3389" ip, port = host, "3389"
reactor.connectTCP(ip, int(port), RDPScreenShotFactory(reactor, app, width, height, path + "%s.jpg" % ip, timeout)) reactor.connectTCP(ip, int(port), RDPScreenShotFactory(reactor, app, width, height, path + "%s.jpg"%ip, timeout))
reactor.runReturn() reactor.runReturn()
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"
print "\t-l: height of screen default value is 800" print "\t-l: height of screen default value is 800"
print "\t-o: file path of screenshot default(/tmp/rdpy-rdpscreenshot.jpg)" print "\t-o: file path of screenshot default(/tmp/rdpy-rdpscreenshot.jpg)"
print "\t-t: timeout of connection without any updating order (default is 2s)" print "\t-t: timeout of connection without any updating order (default is 2s)"
if __name__ == '__main__': if __name__ == '__main__':
# default script argument #default script argument
width = 1024 width = 1024
height = 800 height = 800
path = "/tmp/" path = "/tmp/"
timeout = 5.0 timeout = 5.0
try: try:
opts, args = getopt.getopt(sys.argv[1:], "hw:l:o:t:") opts, args = getopt.getopt(sys.argv[1:], "hw:l:o:t:")
except getopt.GetoptError: except getopt.GetoptError:
@@ -221,5 +217,5 @@ if __name__ == '__main__':
path = arg path = arg
elif opt == "-t": elif opt == "-t":
timeout = float(arg) timeout = float(arg)
main(width, height, path, timeout, args) main(width, height, path, timeout, args)

View File

@@ -33,17 +33,12 @@ 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
""" """
if _LOG_FILE:
f = open(_LOG_FILE, "a+")
f.write("%s\n"%message)
f.close()
print "[*] %s"%message print "[*] %s"%message
def error(message): def error(message):
@@ -80,4 +75,4 @@ def debug(message):
""" """
if _LOG_LEVEL > Level.DEBUG: if _LOG_LEVEL > Level.DEBUG:
return return
log("DEBUG:\t%s"%message) log("DEBUG:\t%s"%message)

View File

@@ -160,16 +160,7 @@ class PointerFlag(object):
PTRFLAGS_BUTTON1 = 0x1000 PTRFLAGS_BUTTON1 = 0x1000
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
@@ -928,7 +919,7 @@ 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, PointerExEvent, ScancodeKeyEvent, UnicodeKeyEvent, SynchronizeEvent]: for c in [PointerEvent, ScancodeKeyEvent, UnicodeKeyEvent, SynchronizeEvent]:
if self.messageType.value == c._INPUT_MESSAGE_TYPE_: if self.messageType.value == c._INPUT_MESSAGE_TYPE_:
return c() return c()
raise InvalidExpectedDataException("unknown slow path input : %s"%hex(self.messageType.value)) raise InvalidExpectedDataException("unknown slow path input : %s"%hex(self.messageType.value))
@@ -965,19 +956,6 @@ 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

@@ -228,35 +228,24 @@ class RDPClientController(pdu.layer.PDUClientListener):
return return
try: try:
if button == 4 or button == 5: event = pdu.data.PointerEvent()
event = pdu.data.PointerExEvent() if isPressed:
if isPressed: event.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_DOWN
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()
if isPressed:
event.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_DOWN
if button == 1:
event.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON1
elif button == 2:
event.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON2
elif button == 3:
event.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON3
else:
event.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_MOVE
# position if button == 1:
event.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON1
elif button == 2:
event.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON2
elif button == 3:
event.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON3
else:
event.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_MOVE
#position
event.xPos.value = x event.xPos.value = x
event.yPos.value = y event.yPos.value = y
# send proper event #send proper event
self._pduLayer.sendInputEvents([event]) self._pduLayer.sendInputEvents([event])
except InvalidValue: except InvalidValue:
@@ -511,7 +500,7 @@ class RDPServerController(pdu.layer.PDUServerListener):
#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 events #mouse event
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
@@ -522,15 +511,6 @@ 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):
""" """
@@ -718,7 +698,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, 3, 4 or 5 button @param button: 1, 2 or 3 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

@@ -24,7 +24,7 @@ RDP Standard security layer
import sha, md5 import sha, md5
import lic, tpkt import lic, tpkt
from t125 import gcc, mcs from t125 import gcc, mcs
from rdpy.core.type import CompositeType, CallableValue, Stream, UInt32Le, UInt16Le, String, sizeof, UInt8 from rdpy.core.type import CompositeType, CallableValue, Stream, UInt32Le, UInt16Le, String, sizeof
from rdpy.core.layer import LayerAutomata, IStreamSender from rdpy.core.layer import LayerAutomata, IStreamSender
from rdpy.core.error import InvalidExpectedDataException from rdpy.core.error import InvalidExpectedDataException
from rdpy.core import log from rdpy.core import log
@@ -56,6 +56,7 @@ class SecurityFlag(object):
class InfoFlag(object): class InfoFlag(object):
""" """
Client capabilities informations Client capabilities informations
@see: https://msdn.microsoft.com/en-us/library/cc240475.aspx
""" """
INFO_MOUSE = 0x00000001 INFO_MOUSE = 0x00000001
INFO_DISABLECTRLALTDEL = 0x00000002 INFO_DISABLECTRLALTDEL = 0x00000002
@@ -80,6 +81,7 @@ class InfoFlag(object):
class PerfFlag(object): class PerfFlag(object):
""" """
Network performances flag Network performances flag
@see: https://msdn.microsoft.com/en-us/library/cc240476.aspx
""" """
PERF_DISABLE_WALLPAPER = 0x00000001 PERF_DISABLE_WALLPAPER = 0x00000001
PERF_DISABLE_FULLWINDOWDRAG = 0x00000002 PERF_DISABLE_FULLWINDOWDRAG = 0x00000002

View File

@@ -27,7 +27,6 @@ It exist channel for file system order, audio channel, clipboard etc...
from rdpy.core.layer import LayerAutomata, IStreamSender, Layer from rdpy.core.layer import LayerAutomata, IStreamSender, Layer
from rdpy.core.type import sizeof, Stream, UInt8, UInt16Le, String from rdpy.core.type import sizeof, Stream, UInt8, UInt16Le, String
from rdpy.core.error import InvalidExpectedDataException, InvalidValue, InvalidSize, CallPureVirtualFuntion from rdpy.core.error import InvalidExpectedDataException, InvalidValue, InvalidSize, CallPureVirtualFuntion
from ber import writeLength
import rdpy.core.log as log import rdpy.core.log as log
import ber, gcc, per import ber, gcc, per
@@ -255,7 +254,7 @@ class MCSLayer(LayerAutomata):
domainParam = (ber.writeInteger(maxChannels), ber.writeInteger(maxUsers), ber.writeInteger(maxTokens), domainParam = (ber.writeInteger(maxChannels), ber.writeInteger(maxUsers), ber.writeInteger(maxTokens),
ber.writeInteger(1), ber.writeInteger(0), ber.writeInteger(1), ber.writeInteger(1), ber.writeInteger(0), ber.writeInteger(1),
ber.writeInteger(maxPduSize), ber.writeInteger(2)) ber.writeInteger(maxPduSize), ber.writeInteger(2))
return (ber.writeUniversalTag(ber.Tag.BER_TAG_SEQUENCE, True), writeLength(sizeof(domainParam)), domainParam) return (ber.writeUniversalTag(ber.Tag.BER_TAG_SEQUENCE, True), ber.writeLength(sizeof(domainParam)), domainParam)
def writeMCSPDUHeader(self, mcsPdu, options = 0): def writeMCSPDUHeader(self, mcsPdu, options = 0):
""" """

View File

@@ -42,6 +42,6 @@ setup(name='rdpy',
'service_identity', 'service_identity',
'qt4reactor', 'qt4reactor',
'rsa', 'rsa',
'pyasn1' 'pyasn1',
], ],
) )