Esempio n. 1
0
    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")
Esempio n. 2
0
    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()
Esempio n. 3
0
    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""
Esempio n. 4
0
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
Esempio n. 5
0
    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
            },
        })
Esempio n. 6
0
    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)
Esempio n. 7
0
    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)
Esempio n. 8
0
    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,
        }
Esempio n. 9
0
 def __init__(self, parser=ClipboardParser()):
     super().__init__(parser)
Esempio n. 10
0
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
Esempio n. 11
0
 def __init__(self, parser=ClipboardParser()):
     Layer.__init__(self, parser, hasNext=False)