예제 #1
0
 def __init__(self, parser: BasicSecurityParser):
     """
     :param parser: the parser to use for security traffic.
     :type parser: Parser
     """
     Layer.__init__(self, parser, hasNext=True)
     self.mainParser = parser
     self.clientInfoParser = ClientInfoParser()
예제 #2
0
    def onClientInfo(self, pdu: PlayerPDU):
        parser = ClientInfoParser()
        clientInfoPDU = parser.parse(pdu.payload)
        info = self.json[JSON_KEY_INFO]

        info["date"] = pdu.timestamp
        info["username"] = clientInfoPDU.username.replace("\x00", "")
        info["password"] = clientInfoPDU.password.replace("\x00", "")
        info["domain"] = clientInfoPDU.domain.replace("\x00", "")
예제 #3
0
    def onClientInfo(self, pdu: PlayerPDU):
        parser = ClientInfoParser()
        clientInfoPDU = parser.parse(pdu.payload)

        self.writeSeparator()

        self.writeText("USERNAME: {}\nPASSWORD: {}\nDOMAIN: {}\n".format(
            clientInfoPDU.username.replace("\x00", ""),
            clientInfoPDU.password.replace("\x00", ""),
            clientInfoPDU.domain.replace("\x00", "")))

        self.writeSeparator()
예제 #4
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""
예제 #5
0
파일: server.py 프로젝트: macdaliot/pyrdp
    def onClientInfoReceived(self, data: bytes):
        """
        Called when client info data is received.
        Record the PDU and send it to the MITMClient.
        """
        pdu = ClientInfoParser().parse(data)

        clientAddress = None
        if pdu.extraInfo:
            clientAddress = decodeUTF16LE(pdu.extraInfo.clientAddress)
        self.log.info("Client address: %(clientAddress)s",
                      {"clientAddress": clientAddress})

        self.log.debug("Client Info received: %(clientInfoPDU)s",
                       {"clientInfoPDU": pdu})
        hasExtraInfo = pdu.extraInfo is not None
        self.log.info(
            "CLIENT INFO RECEIVED.\n"
            "USER: %(username)s\n"
            "PASSWORD: %(password)s\n"
            "DOMAIN: %(domain)s\n"
            "LOCAL IP ADDR: %(localIpAddress)s", {
                "username":
                pdu.username,
                "password":
                pdu.password,
                "domain":
                pdu.domain,
                "localIpAddress":
                pdu.extraInfo.clientAddress if hasExtraInfo else None
            })
        self.recorder.record(pdu, PlayerMessageType.CLIENT_INFO)
        self.client.onClientInfoPDUReceived(pdu)
예제 #6
0
    def onClientInfo(self, data: bytes):
        """
        Log the client connection information and replace the username and password if applicable.
        :param data: the client info data
        """
        pdu = ClientInfoParser().parse(data)

        clientAddress = None

        if pdu.extraInfo:
            clientAddress = decodeUTF16LE(pdu.extraInfo.clientAddress)

        self.log.info(
            "Client Info: username = %(username)r, password = %(password)r, domain = %(domain)r, clientAddress = %(clientAddress)r",
            {
                "username": pdu.username,
                "password": pdu.password,
                "domain": pdu.domain,
                "clientAddress": clientAddress
            })

        self.recorder.record(pdu, PlayerPDUType.CLIENT_INFO)

        # If set, replace the provided username and password to connect the user regardless of
        # the credentials they entered.
        if self.config.replacementUsername is not None:
            pdu.username = self.config.replacementUsername
        if self.config.replacementPassword is not None:
            pdu.password = self.config.replacementPassword

        if self.config.replacementUsername is not None and self.config.replacementPassword is not None:
            pdu.flags |= ClientInfoFlags.INFO_AUTOLOGON

        # Tell the server we don't want compression (unsure of the effectiveness of these flags)
        pdu.flags &= ~ClientInfoFlags.INFO_COMPRESSION
        pdu.flags &= ~ClientInfoFlags.INFO_CompressionTypeMask

        self.log.debug("Sending %(pdu)s", {"pdu": pdu})
        self.server.sendClientInfo(pdu)
예제 #7
0
파일: recorder.py 프로젝트: xuyi/pyrdp
    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)
예제 #8
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)
예제 #9
0
파일: server.py 프로젝트: macdaliot/pyrdp
    def __init__(self, friendlyName: str, targetHost: str, targetPort: int,
                 certificateFileName: str, privateKeyFileName: str,
                 recordHost: str, recordPort: int, replacementUsername: str,
                 replacementPassword: str):
        MCSUserObserver.__init__(self)

        self.sessionId = f"{friendlyName}{random.randrange(100000,999999)}"
        self.log = getLoggerPassFilters(
            f"{LOGGER_NAMES.MITM_CONNECTIONS}.{self.sessionId}.server")
        self.metadataFilter = ConnectionMetadataFilter(self, self.sessionId)
        self.log.addFilter(self.metadataFilter)

        self.replacementPassword = replacementPassword
        self.replacementUsername = replacementUsername
        self.targetHost = targetHost
        self.targetPort = targetPort
        self.certificateFileName = certificateFileName
        self.privateKeyFileName = privateKeyFileName
        self.clipboardObserver = None
        self.useTLS = False
        self.client: MITMClient = None
        self.clientConnector = None
        self.originalNegotiationPDU = None
        self.targetNegotiationPDU = None
        self.serverData = None
        self.rc4RSAKey = RSA.generate(2048)
        self.crypter = RC4CrypterProxy()
        self.socket = None
        self.fileHandle = open(
            "out/rdp_replay_{}_{}.pyrdp".format(
                datetime.datetime.now().strftime('%Y%m%d_%H-%M-%S'),
                random.randint(0, 1000)), "wb")

        rc4Log = getLoggerPassFilters(f"{self.log.name}.rc4")
        self.securitySettings = SecuritySettings(SecuritySettings.Mode.SERVER)
        self.securitySettings.addObserver(self.crypter)
        self.securitySettings.addObserver(RC4LoggingObserver(rc4Log))

        self.tcp = TwistedTCPLayer()
        self.tcp.createObserver(onConnection=self.onConnection,
                                onDisconnection=self.onDisconnection)

        self.segmentation = SegmentationLayer()
        self.segmentation.createObserver(
            onUnknownHeader=self.onUnknownTPKTHeader)

        self.tpkt = TPKTLayer()

        self.x224 = X224Layer()
        self.x224.createObserver(onConnectionRequest=self.onConnectionRequest,
                                 onDisconnectRequest=self.onDisconnectRequest)

        self.mcs = MCSLayer()
        self.router = MITMServerRouter(self.mcs, self)
        self.mcs.addObserver(self.router)
        self.router.createObserver(
            onConnectionReceived=self.onConnectInitial,
            onDisconnectProviderUltimatum=self.onDisconnectProviderUltimatum,
            onAttachUserRequest=self.onAttachUserRequest,
            onChannelJoinRequest=self.onChannelJoinRequest)

        self.gcc = GCCParser()

        self.rdpClientInfoParser = ClientInfoParser()
        self.rdpClientConnectionParser = ClientConnectionParser()
        self.rdpServerConnectionParser = ServerConnectionParser()

        self.securityLayer = None
        self.slowPathLayer = SlowPathLayer()
        self.fastPathLayer = None

        self.tcp.setNext(self.segmentation)
        self.segmentation.attachLayer(SegmentationPDUType.TPKT, self.tpkt)
        Layer.chain(self.tpkt, self.x224, self.mcs)

        if recordHost is not None and recordPort is not None:
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            try:
                self.socket.connect((recordHost, recordPort))
            except socket.error as e:
                logging.getLogger(LOGGER_NAMES.MITM).error(
                    "Could not connect to liveplayer: %(error)s", {"error": e})
                self.socket.close()
                self.socket = None

        recordingLayers = [FileLayer(self.fileHandle)]
        if self.socket is not None:
            recordingLayers.append(SocketLayer(self.socket))

        # Since we're intercepting communications from the original client (so we're a server),
        # We need to write back the packets as if they came from the client.
        self.recorder = Recorder(recordingLayers)
예제 #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
예제 #11
0
class SecurityLayer(Layer):
    """
    Layer for security related traffic.
    """

    def __init__(self, parser: BasicSecurityParser):
        """
        :param parser: the parser to use for security traffic.
        :type parser: Parser
        """
        Layer.__init__(self, parser, hasNext=True)
        self.mainParser = parser
        self.clientInfoParser = ClientInfoParser()

    @staticmethod
    def create(encryptionMethod, crypter):
        """
        Create a security layer using the chosen encryption method and crypter.
        :type encryptionMethod: EncryptionMethod
        :type crypter: RC4Crypter | RC4CrypterProxy
        :return: RDPSecurityLayer
        """
        if encryptionMethod in [EncryptionMethod.ENCRYPTION_40BIT, EncryptionMethod.ENCRYPTION_56BIT, EncryptionMethod.ENCRYPTION_128BIT]:
            parser = SignedSecurityParser(crypter)
            return SecurityLayer(parser)
        elif encryptionMethod == EncryptionMethod.ENCRYPTION_FIPS:
            parser = FIPSSecurityParser(crypter)
            return SecurityLayer(parser)

    def recv(self, data):
        pdu = self.mainParser.parse(data)
        try:
            self.dispatchPDU(pdu)
        except KeyboardInterrupt:
            raise
        except Exception:
            if isinstance(pdu, SecurityExchangePDU):
                log.error("Exception occurred when receiving Security Exchange. Data: %(securityExchangeData)s",
                          {"securityExchangeData": hexlify(data)})
            else:
                log.error("Exception occurred when receiving: %(data)s", {"data": hexlify(pdu.payload).decode()})
            raise

    def dispatchPDU(self, pdu):
        """
        Send the PDU to the proper object depending on its type.
        :param pdu: the pdu.
        :type pdu: PDU.
        """
        if pdu.header & SecurityFlags.SEC_EXCHANGE_PKT != 0:
            if self.observer:
                self.observer.onSecurityExchangeReceived(pdu)
        elif pdu.header & SecurityFlags.SEC_INFO_PKT != 0:
            if self.observer:
                self.observer.onClientInfoReceived(pdu.payload)
        elif pdu.header & SecurityFlags.SEC_LICENSE_PKT != 0:
            if self.observer:
                self.observer.onLicensingDataReceived(pdu.payload)
        else:
            self.pduReceived(pdu, self.hasNext)

    def send(self, data: bytes, header=0):
        pdu = SecurityPDU(header, data)
        data = self.mainParser.write(pdu)
        self.previous.send(data)

    def sendSecurityExchange(self, clientRandom):
        """
        Send a security exchange PDU through the layer.
        :param clientRandom: the client random data.
        :type clientRandom: bytes
        """
        pdu = SecurityExchangePDU(SecurityFlags.SEC_EXCHANGE_PKT, clientRandom + b"\x00" * 8)
        data = self.mainParser.writeSecurityExchange(pdu)
        self.previous.send(data)

    def sendClientInfo(self, pdu):
        """
        Send a client info PDU.
        :type pdu: ClientInfoPDU
        """
        data = self.clientInfoParser.write(pdu)
        pdu = SecurityPDU(SecurityFlags.SEC_INFO_PKT, data)
        data = self.mainParser.write(pdu)
        self.previous.send(data)

    def sendLicensing(self, data):
        """
        Send raw licensing data.
        :type data: bytes
        """
        pdu = SecurityPDU(SecurityFlags.SEC_LICENSE_PKT, data)
        self.previous.send(self.mainParser.write(pdu))
예제 #12
0
 def onClientInfoReceived(self, data: bytes):
     pdu = ClientInfoParser().parse(data)
     self.logPDU(pdu)
예제 #13
0
 def __init__(self, parser: BasicSecurityParser):
     """
     :param parser: the parser to use for security traffic.
     """
     super().__init__(parser)
     self.clientInfoParser = ClientInfoParser()