finish honeypot tools

This commit is contained in:
speyrefitte
2015-01-14 15:49:00 +01:00
parent e9fd801237
commit 9dcac862ff
7 changed files with 174 additions and 62 deletions

View File

@@ -61,9 +61,11 @@ RDPY comes with some very useful binaries; These binaries are linux and windows
rdpy-rdpclient is a simple RDP Qt4 client . rdpy-rdpclient is a simple RDP Qt4 client .
``` ```
$ rdpy-rdpclient.py [-u username] [-p password] [-d domain] [...] XXX.XXX.XXX.XXX[:3389] $ rdpy-rdpclient.py [-u username] [-p password] [-d domain] [-r rss_ouput_file] [...] XXX.XXX.XXX.XXX[:3389]
``` ```
You can use rdpy-rdpclient as Recorder Session Scenarion, use in rdpy-rdphoneypot.
### rdpy-vncclient ### rdpy-vncclient
rdpy-vncclient is a simple VNC Qt4 client . rdpy-vncclient is a simple VNC Qt4 client .

View File

@@ -27,15 +27,71 @@ from PyQt4 import QtGui, QtCore
from rdpy.ui.qt4 import RDPClientQt from rdpy.ui.qt4 import RDPClientQt
from rdpy.protocol.rdp import rdp from rdpy.protocol.rdp import rdp
from rdpy.core.error import RDPSecurityNegoFail from rdpy.core.error import RDPSecurityNegoFail
from rdpy.core import rss
import rdpy.core.log as log import rdpy.core.log as log
log._LOG_LEVEL = log.Level.INFO 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): class RDPClientQtFactory(rdp.ClientFactory):
""" """
@summary: Factory create a RDP GUI client @summary: Factory create a RDP GUI client
""" """
def __init__(self, width, height, username, password, domain, fullscreen, keyboardLayout, optimized, security): def __init__(self, width, height, username, password, domain, fullscreen, keyboardLayout, optimized, security, recodedPath):
""" """
@param width: {integer} width of client @param width: {integer} width of client
@param heigth: {integer} heigth of client @param heigth: {integer} heigth of client
@@ -46,6 +102,7 @@ class RDPClientQtFactory(rdp.ClientFactory):
@param keyboardLayout: {str} (fr|en) keyboard layout @param keyboardLayout: {str} (fr|en) keyboard layout
@param optimized: {bool} enable optimized session orders @param optimized: {bool} enable optimized session orders
@param security: {str} (ssl | rdp | nego) @param security: {str} (ssl | rdp | nego)
@param recodedPath: {str | None} Rss file Path
""" """
self._width = width self._width = width
self._height = height self._height = height
@@ -56,6 +113,7 @@ class RDPClientQtFactory(rdp.ClientFactory):
self._keyboardLayout = keyboardLayout self._keyboardLayout = keyboardLayout
self._optimized = optimized self._optimized = optimized
self._nego = security == "nego" self._nego = security == "nego"
self._recodedPath = recodedPath
if self._nego: if self._nego:
self._security = "ssl" self._security = "ssl"
else: else:
@@ -71,7 +129,10 @@ class RDPClientQtFactory(rdp.ClientFactory):
@return: RDPClientQt @return: RDPClientQt
""" """
#create client observer #create client observer
self._client = RDPClientQt(controller, self._width, self._height) 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 #create qt widget
self._w = self._client.getWidget() self._w = self._client.getWidget()
self._w.setWindowTitle('rdpy-rdpclient') self._w.setWindowTitle('rdpy-rdpclient')
@@ -146,15 +207,18 @@ def autoDetectKeyboardLayout():
return "en" return "en"
def help(): def help():
print "Usage: rdpy-rdpclient [options] ip[:port]" print """
print "\t-u: user name" Usage: rdpy-rdpclient [options] ip[:port]"
print "\t-p: password" \t-u: user name
print "\t-d: domain" \t-p: password
print "\t-w: width of screen [default : 1024]" \t-d: domain
print "\t-l: height of screen [default : 800]" \t-w: width of screen [default : 1024]
print "\t-f: enable full screen mode [default : False]" \t-l: height of screen [default : 800]
print "\t-k: keyboard layout [en|fr] [default : en]" \t-f: enable full screen mode [default : False]
print "\t-o: optimized session (disable costly effect) [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__':
@@ -166,10 +230,11 @@ if __name__ == '__main__':
height = 800 height = 800
fullscreen = False fullscreen = False
optimized = False optimized = False
recodedPath = None
keyboardLayout = autoDetectKeyboardLayout() keyboardLayout = autoDetectKeyboardLayout()
try: try:
opts, args = getopt.getopt(sys.argv[1:], "hfou:p:d:w:l:k:") opts, args = getopt.getopt(sys.argv[1:], "hfou:p:d:w:l:k:r:")
except getopt.GetoptError: except getopt.GetoptError:
help() help()
for opt, arg in opts: for opt, arg in opts:
@@ -192,6 +257,8 @@ if __name__ == '__main__':
optimized = True optimized = True
elif opt == "-k": elif opt == "-k":
keyboardLayout = arg keyboardLayout = arg
elif opt == "-r":
recodedPath = arg
if ':' in args[0]: if ':' in args[0]:
ip, port = args[0].split(':') ip, port = args[0].split(':')
@@ -212,6 +279,6 @@ if __name__ == '__main__':
log.info("keyboard layout set to %s"%keyboardLayout) log.info("keyboard layout set to %s"%keyboardLayout)
from twisted.internet import reactor from twisted.internet import reactor
reactor.connectTCP(ip, int(port), RDPClientQtFactory(width, height, username, password, domain, fullscreen, keyboardLayout, optimized, "nego")) reactor.connectTCP(ip, int(port), RDPClientQtFactory(width, height, username, password, domain, fullscreen, keyboardLayout, optimized, "nego", recodedPath))
reactor.runReturn() reactor.runReturn()
app.exec_() app.exec_()

View File

@@ -37,6 +37,7 @@ class HoneyPotServer(rdp.RDPServerObserver):
""" """
rdp.RDPServerObserver.__init__(self, controller) rdp.RDPServerObserver.__init__(self, controller)
self._rssFile = rssFile self._rssFile = rssFile
self._dx, self._dy = 0, 0
def onReady(self): def onReady(self):
""" """
@@ -46,7 +47,15 @@ class HoneyPotServer(rdp.RDPServerObserver):
restart a connection sequence restart a connection sequence
@see: rdp.RDPServerObserver.onReady @see: rdp.RDPServerObserver.onReady
""" """
self.loopScenario() domain, username, password = self._controller.getCredentials()
hostname = self._controller.getHostname()
log.info("""Credentials:
\tdomain : %s
\tusername : %s
\tpassword : %s
\thostname : %s
"""%(domain, username, password, hostname));
self.start()
def onClose(self): def onClose(self):
""" HoneyPot """ """ HoneyPot """
@@ -60,22 +69,32 @@ class HoneyPotServer(rdp.RDPServerObserver):
def onPointerEvent(self, x, y, button, isPressed): def onPointerEvent(self, x, y, button, isPressed):
""" HoneyPot """ """ HoneyPot """
def loopScenario(self): def start(self):
self.loopScenario(self._rssFile.nextEvent())
def loopScenario(self, nextEvent):
""" """
@summary: main loop event @summary: main loop event
""" """
e = self._rssFile.nextEvent() if nextEvent.type.value == rss.EventType.UPDATE:
if e is None: self._controller.sendUpdate(nextEvent.event.destLeft.value + self._dx, nextEvent.event.destTop.value + self._dy, nextEvent.event.destRight.value + self._dx, nextEvent.event.destBottom.value + self._dy, nextEvent.event.width.value, nextEvent.event.height.value, nextEvent.event.bpp.value, nextEvent.event.format.value == rss.UpdateFormat.BMP, nextEvent.event.data.value)
elif nextEvent.type.value == rss.EventType.CLOSE:
self._controller.close() self._controller.close()
return return
if e.type.value == rss.EventType.UPDATE: elif nextEvent.type.value == rss.EventType.SCREEN:
self._controller.sendUpdate(e.event.destLeft.value, e.event.destTop.value, e.event.destRight.value, e.event.destBottom.value, e.event.width.value, e.event.height.value, e.event.bpp.value, e.event.format.value == rss.UpdateFormat.BMP, e.event.data.value) self._controller.setColorDepth(nextEvent.event.colorDepth.value)
elif e.type.value == rss.EventType.SCREEN: #compute centering because we cannot resize client
self._controller.setColorDepth(e.event.colorDepth.value) clientSize = nextEvent.event.width.value, nextEvent.event.height.value
serverSize = self._controller.getScreen()
self._dx, self._dy = (serverSize[0] - clientSize[0]) / 2, (serverSize[1] - clientSize[1]) / 2
#restart connection sequence #restart connection sequence
return return
reactor.callLater(float(e.timestamp.value) / 1000.0, self.loopScenario)
e = self._rssFile.nextEvent()
reactor.callLater(float(e.timestamp.value) / 1000.0, lambda:self.loopScenario(e))
class HoneyPotServerFactory(rdp.ServerFactory): class HoneyPotServerFactory(rdp.ServerFactory):
""" """
@@ -96,6 +115,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))
return HoneyPotServer(controller, rss.createReader(self._rssFilePath)) return HoneyPotServer(controller, rss.createReader(self._rssFilePath))
def help(): def help():

View File

@@ -35,7 +35,7 @@ from rdpy.core import log, error, rss
from rdpy.protocol.rdp import rdp from rdpy.protocol.rdp import rdp
from twisted.internet import reactor from twisted.internet import reactor
log._LOG_LEVEL = log.Level.INFO log._LOG_LEVEL = log.Level.DEBUG
class ProxyServer(rdp.RDPServerObserver): class ProxyServer(rdp.RDPServerObserver):
""" """
@@ -71,10 +71,10 @@ 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.recInfo(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.recScreen(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))
@@ -84,6 +84,10 @@ class ProxyServer(rdp.RDPServerObserver):
@summary: Call when human client close connection @summary: Call when human client close connection
@see: rdp.RDPServerObserver.onClose @see: rdp.RDPServerObserver.onClose
""" """
#end scenario
self._rss.close()
#close network stack
if self._client is None: if self._client is None:
return return
self._client._controller.close() self._client._controller.close()
@@ -177,6 +181,8 @@ class ProxyClient(rdp.RDPClientObserver):
@summary: Event inform that stack is close @summary: Event inform that stack is close
@see: rdp.RDPClientObserver.onClose @see: rdp.RDPClientObserver.onClose
""" """
#end scenario
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):
@@ -193,7 +199,7 @@ 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.recUpdate(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, 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):

View File

@@ -51,29 +51,33 @@ class RssPlayerWidget(QRemoteDesktop):
def help(): def help():
print "Usage: rdpy-rssplayer [-h] rss_filepath" print "Usage: rdpy-rssplayer [-h] rss_filepath"
def loop(widget, rssFile): def start(widget, rssFile):
loop(widget, rssFile, rssFile.nextEvent())
def loop(widget, rssFile, nextEvent):
""" """
@summary: timer function @summary: timer function
@param widget: {QRemoteDesktop} @param widget: {QRemoteDesktop}
@param rssFile: {rss.FileReader} @param rssFile: {rss.FileReader}
""" """
e = rssFile.nextEvent()
if e is None: if nextEvent.type.value == rss.EventType.UPDATE:
image = RDPBitmapToQtImage(nextEvent.event.width.value, nextEvent.event.height.value, nextEvent.event.bpp.value, nextEvent.event.format.value == rss.UpdateFormat.BMP, nextEvent.event.data.value);
widget.notifyImage(nextEvent.event.destLeft.value, nextEvent.event.destTop.value, image, nextEvent.event.destRight.value - nextEvent.event.destLeft.value + 1, nextEvent.event.destBottom.value - nextEvent.event.destTop.value + 1)
elif nextEvent.type.value == rss.EventType.SCREEN:
widget.resize(nextEvent.event.width.value, nextEvent.event.height.value)
elif nextEvent.type.value == rss.EventType.INFO:
widget.drawInfos(nextEvent.event.domain.value, nextEvent.event.username.value, nextEvent.event.password.value, nextEvent.event.hostname.value)
elif nextEvent.type.value == rss.EventType.CLOSE:
widget.close() widget.close()
return return
if e.type.value == rss.EventType.UPDATE: e = rssFile.nextEvent()
image = RDPBitmapToQtImage(e.event.width.value, e.event.height.value, e.event.bpp.value, e.event.format.value == rss.UpdateFormat.BMP, e.event.data.value); QtCore.QTimer.singleShot(e.timestamp.value,lambda:loop(widget, rssFile, e))
widget.notifyImage(e.event.destLeft.value, e.event.destTop.value, image, e.event.destRight.value - e.event.destLeft.value + 1, e.event.destBottom.value - e.event.destTop.value + 1)
elif e.type.value == rss.EventType.SCREEN:
widget.resize(e.event.width.value, e.event.height.value)
elif e.type.value == rss.EventType.INFO:
widget.drawInfos(e.event.domain.value, e.event.username.value, e.event.password.value, e.event.hostname.value)
QtCore.QTimer.singleShot(e.timestamp.value,lambda:loop(widget, rssFile))
if __name__ == '__main__': if __name__ == '__main__':
try: try:
@@ -91,5 +95,5 @@ if __name__ == '__main__':
widget = RssPlayerWidget(800, 600) widget = RssPlayerWidget(800, 600)
widget.show() widget.show()
rssFile = rss.createReader(filepath) rssFile = rss.createReader(filepath)
loop(widget, rssFile) start(widget, rssFile)
sys.exit(app.exec_()) sys.exit(app.exec_())

View File

@@ -33,6 +33,7 @@ class EventType(object):
UPDATE = 0x0001 UPDATE = 0x0001
SCREEN = 0x0002 SCREEN = 0x0002
INFO = 0x0003 INFO = 0x0003
CLOSE = 0x0004
class UpdateFormat(object): class UpdateFormat(object):
""" """
@@ -55,7 +56,7 @@ class Event(CompositeType):
""" """
@summary: Closure for event factory @summary: Closure for event factory
""" """
for c in [UpdateEvent, ScreenEvent, InfoEvent]: for c in [UpdateEvent, ScreenEvent, InfoEvent, CloseEvent]:
if self.type.value == c._TYPE_: if self.type.value == c._TYPE_:
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))
@@ -114,6 +115,14 @@ class ScreenEvent(CompositeType):
self.height = UInt16Le() self.height = UInt16Le()
self.colorDepth = UInt8() self.colorDepth = UInt8()
class CloseEvent(CompositeType):
"""
@summary: end of session event
"""
_TYPE_ = EventType.CLOSE
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
def timeMs(): def timeMs():
""" """
@return: {int} time stamp in milliseconds @return: {int} time stamp in milliseconds
@@ -150,7 +159,7 @@ class FileRecorder(object):
self._file.write(s.getvalue()) self._file.write(s.getvalue())
def recUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bpp, upateFormat, data): def update(self, destLeft, destTop, destRight, destBottom, width, height, bpp, upateFormat, data):
""" """
@summary: record update event @summary: record update event
@param destLeft: {int} xmin position @param destLeft: {int} xmin position
@@ -175,7 +184,7 @@ class FileRecorder(object):
updateEvent.data.value = data updateEvent.data.value = data
self.rec(updateEvent) self.rec(updateEvent)
def recScreen(self, width, height, colorDepth): def screen(self, width, height, colorDepth):
""" """
@summary: record resize event of screen (maybe first event) @summary: record resize event of screen (maybe first event)
@param width: {int} width of screen @param width: {int} width of screen
@@ -188,7 +197,7 @@ class FileRecorder(object):
screenEvent.colorDepth.value = colorDepth screenEvent.colorDepth.value = colorDepth
self.rec(screenEvent) self.rec(screenEvent)
def recInfo(self, username, password, domain = "", hostname = ""): def credentials(self, username, password, domain = "", hostname = ""):
""" """
@summary: Record informations event @summary: Record informations event
@param username: {str} username of session @param username: {str} username of session
@@ -202,6 +211,12 @@ class FileRecorder(object):
infoEvent.domain.value = domain infoEvent.domain.value = domain
infoEvent.hostname.value = hostname infoEvent.hostname.value = hostname
self.rec(infoEvent) self.rec(infoEvent)
def close(self):
"""
@summary: end of scenario
"""
self.rec(CloseEvent())
class FileReader(object): class FileReader(object):
""" """

View File

@@ -233,9 +233,9 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
""" """
def __init__(self, controller, width, height): def __init__(self, controller, width, height):
""" """
@param controller: RDP controller @param controller: {RDPClientController} RDP controller
@param width: width of widget @param width: {int} width of widget
@param height: height of widget @param height: {int} height of widget
""" """
RDPClientObserver.__init__(self, controller) RDPClientObserver.__init__(self, controller)
self._widget = QRemoteDesktop(width, height, self) self._widget = QRemoteDesktop(width, height, self)
@@ -293,15 +293,15 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
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: Notify bitmap update @summary: Notify bitmap update
@param destLeft: xmin position @param destLeft: {int} xmin position
@param destTop: ymin position @param destTop: {int} ymin position
@param destRight: xmax position because RDP can send bitmap with padding @param destRight: {int} xmax position because RDP can send bitmap with padding
@param destBottom: ymax position because RDP can send bitmap with padding @param destBottom: {int} ymax position because RDP can send bitmap with padding
@param width: width of bitmap @param width: {int} width of bitmap
@param height: height of bitmap @param height: {int} height of bitmap
@param bitsPerPixel: number of bit per pixel @param bitsPerPixel: {int} number of bit per pixel
@param isCompress: use RLE compression @param isCompress: {bool} use RLE compression
@param data: 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
@@ -313,14 +313,12 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
@summary: Call when stack is ready @summary: Call when stack is ready
""" """
#do something maybe a loader #do something maybe a loader
pass
def onClose(self): def onClose(self):
""" """
@summary: Call when stack is close @summary: Call when stack is close
""" """
#do something maybe a message #do something maybe a message
pass
class QRemoteDesktop(QtGui.QWidget): class QRemoteDesktop(QtGui.QWidget):