def __init__(self, layer: Layer, recorder: Recorder, logger: Logger, **kwargs): Observer.__init__(self, **kwargs) self.clipboardParser = ClipboardParser() self.peer = None self.layer = layer self.recorder = recorder self.forwardNextDataResponse = True self.mitm_log = getLoggerPassFilters(f"{logger.name}.clipboard") self.clipboard_log = getLoggerPassFilters(f"{self.mitm_log.name}.data")
def onClipboardData(self, pdu: PlayerPDU): parser = ClipboardParser() pdu = parser.parse(pdu.payload) if not isinstance(pdu, FormatDataResponsePDU): return clipboardData = decodeUTF16LE(pdu.requestedFormatData) self.writeSeparator() self.writeText(f"CLIPBOARD DATA: {clipboardData}") self.writeSeparator()
def __init__(self, viewer, text): super().__init__() self.viewer = viewer self.text = text self.writeInCaps = False self.inputParser = BasicFastPathParser(ParserMode.SERVER) self.outputParser = BasicFastPathParser(ParserMode.CLIENT) self.clientInfoParser = ClientInfoParser() self.dataParser = SlowPathParser() self.clipboardParser = ClipboardParser() self.outputEventParser = FastPathOutputParser() self.clientConnectionParser = ClientConnectionParser() self.buffer = b""
class PassiveClipboardStealer(Observer): """ MITM observer that passively intercepts clipboard data from the clipboard virtual channel as they get transferred. """ def __init__(self, layer: Layer, recorder: Recorder, logger: Logger, **kwargs): Observer.__init__(self, **kwargs) self.clipboardParser = ClipboardParser() self.peer = None self.layer = layer self.recorder = recorder self.forwardNextDataResponse = True self.mitm_log = getLoggerPassFilters(f"{logger.name}.clipboard") self.clipboard_log = getLoggerPassFilters(f"{self.mitm_log.name}.data") def onPDUReceived(self, pdu: ClipboardPDU): """ Called when a PDU on the observed layer is received. :param pdu: the PDU that was received. """ self.mitm_log.debug("PDU received: %(arg1)s", {"arg1": str(pdu.msgType)}) if self.peer: self.peer.sendPDU(pdu) def sendPDU(self, pdu: ClipboardPDU): """ Log and record every FormatDataResponsePDU (clipboard data). Transfer only the FormatDataResponsePDU if it didn't originate from the Active clipboard stealer. For the other PDUs, just transfer it. """ if not isinstance(pdu, FormatDataResponsePDU): self.layer.send(self.clipboardParser.write(pdu)) else: if self.forwardNextDataResponse: self.layer.send(self.clipboardParser.write(pdu)) if isinstance(pdu, FormatDataResponsePDU): self.clipboard_log.info("%(clipboardData)s", { "clipboardData": hexlify(pdu.requestedFormatData).decode() }) self.recorder.record(pdu, PlayerMessageType.CLIPBOARD_DATA) self.forwardNextDataResponse = True
def onClipboardData(self, pdu: PlayerPDU): parser = ClipboardParser() pdu = parser.parse(pdu.payload) if not isinstance(pdu, FormatDataResponsePDU): # TODO: Handle file PDUs. return data = decodeUTF16LE(pdu.requestedFormatData) self.json[JSON_KEY_EVENTS].append({ "timestamp": self.timestamp, "type": "clipboard", "data": { "mime": "text/plain", "content": data }, })
def __init__(self, transports: List[LayerChainItem]): self.parsers: Dict[PlayerPDUType, Parser] = { PlayerPDUType.FAST_PATH_INPUT: BasicFastPathParser(ParserMode.CLIENT), PlayerPDUType.FAST_PATH_OUTPUT: BasicFastPathParser(ParserMode.SERVER), PlayerPDUType.CLIENT_INFO: ClientInfoParser(), PlayerPDUType.SLOW_PATH_PDU: SlowPathParser(), PlayerPDUType.CLIPBOARD_DATA: ClipboardParser(), PlayerPDUType.CLIENT_DATA: ClientConnectionParser(), } self.topLayers = [] self.recordFilename = None for transport in transports: self.addTransport(transport)
def __init__(self, transportLayers: List[Layer]): self.parsers: Dict[PlayerMessageType, Parser] = { PlayerMessageType.FAST_PATH_INPUT: BasicFastPathParser(ParserMode.CLIENT), PlayerMessageType.FAST_PATH_OUTPUT: BasicFastPathParser(ParserMode.SERVER), PlayerMessageType.CLIENT_INFO: ClientInfoParser(), PlayerMessageType.SLOW_PATH_PDU: SlowPathParser(), PlayerMessageType.CLIPBOARD_DATA: ClipboardParser(), PlayerMessageType.CLIENT_DATA: ClientConnectionParser(), } self.topLayers = [] for transportLayer in transportLayers: self.addTransportLayer(transportLayer)
def __init__(self, output: TextIOBase = stdout): super().__init__() self.output = output self.shiftPressed = False self.capsLockOn = False self.buffer = b"" # Instantiate parsers. self.slowpath = SlowPathParser() # self.fastpath = FastPathOutputParser() self.clipboard = ClipboardParser() self.handlers = { PlayerPDUType.CLIENT_DATA: self.onClientData, PlayerPDUType.CLIENT_INFO: self.onClientInfo, PlayerPDUType.CONNECTION_CLOSE: self.onConnectionClose, PlayerPDUType.CLIPBOARD_DATA: self.onClipboardData, PlayerPDUType.SLOW_PATH_PDU: self.onSlowPathPDU, PlayerPDUType.FAST_PATH_INPUT: self.onFastPathInput, PlayerPDUType.DEVICE_MAPPING: self.onDeviceMapping, }
def __init__(self, parser=ClipboardParser()): super().__init__(parser)
class PlayerMessageHandler(PlayerMessageObserver): """ Class to manage the display of the RDP player when reading events. """ def __init__(self, viewer, text): super().__init__() self.viewer = viewer self.text = text self.writeInCaps = False self.inputParser = BasicFastPathParser(ParserMode.SERVER) self.outputParser = BasicFastPathParser(ParserMode.CLIENT) self.clientInfoParser = ClientInfoParser() self.dataParser = SlowPathParser() self.clipboardParser = ClipboardParser() self.outputEventParser = FastPathOutputParser() self.clientConnectionParser = ClientConnectionParser() self.buffer = b"" def onConnectionClose(self, pdu: PlayerMessagePDU): self.text.moveCursor(QTextCursor.End) self.text.insertPlainText("\n<Connection closed>") def onOutput(self, pdu: PlayerMessagePDU): pdu = self.outputParser.parse(pdu.payload) for event in pdu.events: reassembledEvent = self.reassembleEvent(event) if reassembledEvent is not None: if isinstance(reassembledEvent, FastPathOrdersEvent): log.debug("Not handling orders event, not coded :)") elif isinstance(reassembledEvent, FastPathBitmapEvent): log.debug("Handling bitmap event %(arg1)s", {"arg1": type(reassembledEvent)}) self.onBitmap(reassembledEvent) else: log.debug("Can't handle output event: %(arg1)s", {"arg1": type(reassembledEvent)}) else: log.debug("Reassembling output event...") def onInput(self, pdu: PlayerMessagePDU): pdu = self.inputParser.parse(pdu.payload) for event in pdu.events: if isinstance(event, FastPathScanCodeEvent): log.debug("handling %(arg1)s", {"arg1": event}) self.onScanCode(event.scancode, not event.isReleased) elif isinstance(event, FastPathMouseEvent): self.onMousePosition(event.mouseX, event.mouseY) else: log.debug("Can't handle input event: %(arg1)s", {"arg1": event}) def onScanCode(self, code: int, isPressed: bool): """ Handle scan code. """ log.debug("Reading scancode %(arg1)s", {"arg1": code}) if code in [0x2A, 0x36]: self.text.moveCursor(QTextCursor.End) self.text.insertPlainText( "\n<LSHIFT PRESSED>" if isPressed else "\n<LSHIFT RELEASED>") self.writeInCaps = not self.writeInCaps elif code == 0x3A and isPressed: self.text.moveCursor(QTextCursor.End) self.text.insertPlainText("\n<CAPSLOCK>") self.writeInCaps = not self.writeInCaps elif isPressed: char = scancodeToChar(code) self.text.moveCursor(QTextCursor.End) self.text.insertPlainText( char if self.writeInCaps else char.lower()) def onMousePosition(self, x: int, y: int): self.viewer.setMousePosition(x, y) def onBitmap(self, event: FastPathBitmapEvent): parsedEvent = self.outputEventParser.parseBitmapEvent(event) for bitmapData in parsedEvent.bitmapUpdateData: self.handleBitmap(bitmapData) def handleBitmap(self, bitmapData: BitmapUpdateData): image = RDPBitmapToQtImage( bitmapData.width, bitmapData.heigth, bitmapData.bitsPerPixel, bitmapData.flags & BitmapFlags.BITMAP_COMPRESSION != 0, bitmapData.bitmapData) self.viewer.notifyImage(bitmapData.destLeft, bitmapData.destTop, image, bitmapData.destRight - bitmapData.destLeft + 1, bitmapData.destBottom - bitmapData.destTop + 1) def onClientInfo(self, pdu: PlayerMessagePDU): clientInfoPDU = self.clientInfoParser.parse(pdu.payload) self.text.insertPlainText( "USERNAME: {}\nPASSWORD: {}\nDOMAIN: {}\n".format( clientInfoPDU.username.replace("\0", ""), clientInfoPDU.password.replace("\0", ""), clientInfoPDU.domain.replace("\0", ""))) self.text.insertPlainText("--------------------\n") def onSlowPathPDU(self, pdu: PlayerMessagePDU): pdu = self.dataParser.parse(pdu.payload) if isinstance(pdu, ConfirmActivePDU): self.viewer.resize( pdu.parsedCapabilitySets[ CapabilityType.CAPSTYPE_BITMAP].desktopWidth, pdu.parsedCapabilitySets[ CapabilityType.CAPSTYPE_BITMAP].desktopHeight) elif isinstance( pdu, UpdatePDU ) and pdu.updateType == SlowPathUpdateType.SLOWPATH_UPDATETYPE_BITMAP: updates = BitmapParser().parseBitmapUpdateData(pdu.updateData) for bitmap in updates: self.handleBitmap(bitmap) elif isinstance(pdu, InputPDU): for event in pdu.events: if isinstance(event, MouseEvent): self.onMousePosition(event.x, event.y) elif isinstance(event, KeyboardEvent): self.onScanCode( event.keyCode, event.flags & KeyboardFlag.KBDFLAGS_DOWN != 0) def onClipboardData(self, pdu: PlayerMessagePDU): formatDataResponsePDU: FormatDataResponsePDU = self.clipboardParser.parse( pdu.payload) self.text.moveCursor(QTextCursor.End) self.text.insertPlainText("\n=============\n") self.text.insertPlainText("CLIPBOARD DATA: {}".format( decodeUTF16LE(formatDataResponsePDU.requestedFormatData))) self.text.insertPlainText("\n=============\n") def onClientData(self, pdu: PlayerMessagePDU): """ Prints the clientName on the screen """ clientDataPDU = self.clientConnectionParser.parse(pdu.payload) self.text.moveCursor(QTextCursor.End) self.text.insertPlainText("--------------------\n") self.text.insertPlainText( f"HOST: {clientDataPDU.coreData.clientName.strip(chr(0))}\n") def reassembleEvent( self, event: FastPathOutputEvent ) -> Optional[Union[FastPathBitmapEvent, FastPathOutputEvent]]: """ Handles FastPath event reassembly as described in https://msdn.microsoft.com/en-us/library/cc240622.aspx :param event: A potentially segmented fastpath output event :return: a FastPathBitmapEvent if a complete PDU has been reassembled, otherwise None. If the event is not fragmented, returns the original event. """ fragmentationFlag = FastPathFragmentation((event.header & 0b00110000) >> 4) if fragmentationFlag == FastPathFragmentation.FASTPATH_FRAGMENT_SINGLE: return event elif fragmentationFlag == FastPathFragmentation.FASTPATH_FRAGMENT_FIRST: self.buffer = event.payload elif fragmentationFlag == FastPathFragmentation.FASTPATH_FRAGMENT_NEXT: self.buffer += event.payload elif fragmentationFlag == FastPathFragmentation.FASTPATH_FRAGMENT_LAST: self.buffer += event.payload event.payload = self.buffer return self.outputEventParser.parseBitmapEvent(event) return None
def __init__(self, parser=ClipboardParser()): Layer.__init__(self, parser, hasNext=False)