def onConnectInitial(self, pdu: MCSConnectInitialPDU): """ Parse client connection information, change some settings, disable some unimplemented features, and record the client data. :param pdu: the connect initial PDU """ gccParser = GCCParser() rdpClientConnectionParser = ClientConnectionParser() gccConferenceCreateRequestPDU: GCCConferenceCreateRequestPDU = gccParser.parse( pdu.payload) rdpClientDataPDU = rdpClientConnectionParser.parse( gccConferenceCreateRequestPDU.payload) # FIPS is not implemented, so remove this flag if it's set rdpClientDataPDU.securityData.encryptionMethods &= ~EncryptionMethod.ENCRYPTION_FIPS rdpClientDataPDU.securityData.extEncryptionMethods &= ~EncryptionMethod.ENCRYPTION_FIPS if self.state.config.downgrade: # This disables the support for the Graphics pipeline extension, which is a completely different way to # transfer graphics from server to client. https://msdn.microsoft.com/en-us/library/dn366933.aspx rdpClientDataPDU.coreData.earlyCapabilityFlags &= ~ClientCapabilityFlag.RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL # Remove 24bpp and 32bpp support, fall back to 16bpp. # 2018-12-14: This is only there because there is a bug in the pyrdp player where 24bpp # decompression in rle.c causes random crashes. If this bug is fixed, we could remove this. rdpClientDataPDU.coreData.supportedColorDepths &= ~SupportedColorDepth.RNS_UD_32BPP_SUPPORT rdpClientDataPDU.coreData.supportedColorDepths &= ~SupportedColorDepth.RNS_UD_24BPP_SUPPORT rdpClientDataPDU.coreData.highColorDepth &= ~HighColorDepth.HIGH_COLOR_24BPP if rdpClientDataPDU.coreData.highColorDepth == 0: # Means the requested color depth was 24bpp, fallback to 16bpp rdpClientDataPDU.coreData.highColorDepth |= HighColorDepth.HIGH_COLOR_16BPP rdpClientDataPDU.coreData.earlyCapabilityFlags &= ~ClientCapabilityFlag.RNS_UD_CS_WANT_32BPP_SESSION self.recorder.record(rdpClientDataPDU, PlayerPDUType.CLIENT_DATA) if rdpClientDataPDU.networkData: self.state.channelDefinitions = rdpClientDataPDU.networkData.channelDefinitions if "MS_T120" in map( lambda channelDef: channelDef.name, rdpClientDataPDU.networkData.channelDefinitions): self.log.info( "Bluekeep (CVE-2019-0708) scan or exploit attempt detected.", {"bluekeep": True}) serverGCCPDU = GCCConferenceCreateRequestPDU( "1", rdpClientConnectionParser.write(rdpClientDataPDU)) serverMCSPDU = MCSConnectInitialPDU(pdu.callingDomain, pdu.calledDomain, pdu.upward, pdu.targetParams, pdu.minParams, pdu.maxParams, gccParser.write(serverGCCPDU)) self.log.info( "Client hostname %(clientName)s", {"clientName": rdpClientDataPDU.coreData.clientName.strip("\x00")}) self.server.sendPDU(serverMCSPDU)
def onConnectResponse(self, pdu, serverData): # MCS Connect Response """ :type pdu: MCSConnectResponsePDU :type serverData: ServerDataPDU """ if pdu.result != 0: self.mcs.send(pdu) return # Replace the server's public key with our own key so we can decrypt the incoming client random cert = serverData.security.serverCertificate if cert: cert = ProprietaryCertificate(cert.signatureAlgorithmID, cert.keyAlgorithmID, cert.publicKeyType, self.rc4RSAKey, cert.signatureType, cert.signature, cert.padding) security = ServerSecurityData( # FIPS is not implemented so avoid using that serverData.security.encryptionMethod if serverData.security.encryptionMethod != EncryptionMethod.ENCRYPTION_FIPS else EncryptionMethod.ENCRYPTION_128BIT, serverData.security.encryptionLevel if serverData.security.encryptionLevel != EncryptionLevel.ENCRYPTION_LEVEL_FIPS else EncryptionLevel.ENCRYPTION_LEVEL_HIGH, serverData.security.serverRandom, cert) serverData.core.clientRequestedProtocols = self.originalNegotiationPDU.requestedProtocols self.securitySettings.serverSecurityReceived(security) self.serverData = ServerDataPDU(serverData.core, security, serverData.network) rdpParser = ServerConnectionParser() gccParser = GCCParser() gcc = self.client.conferenceCreateResponse gcc = GCCConferenceCreateResponsePDU(gcc.nodeID, gcc.tag, gcc.result, rdpParser.write(self.serverData)) pdu = MCSConnectResponsePDU(pdu.result, pdu.calledConnectID, pdu.domainParams, gccParser.write(gcc)) self.mcs.send(pdu)
def onConnectResponse(self, pdu: MCSConnectResponsePDU): """ Parse server connection information. Initialize security settings and map channel IDs to channel names. :param pdu: the connect response PDU """ if pdu.result != 0: self.client.sendPDU(pdu) else: # Parse response PDUs gccParser = GCCParser() rdpParser = ServerConnectionParser() gccPDU: GCCConferenceCreateResponsePDU = gccParser.parse(pdu.payload) serverData = rdpParser.parse(gccPDU.payload) # Save security settings self.state.securitySettings.setEncryptionMethod(serverData.securityData.encryptionMethod) self.state.securitySettings.setServerRandom(serverData.securityData.serverRandom) if serverData.securityData.serverCertificate: self.state.securitySettings.setServerPublicKey(serverData.securityData.serverCertificate.publicKey) # Map channel names to IDs self.state.channelMap[serverData.networkData.mcsChannelID] = MCSChannelName.IO for index in range(len(serverData.networkData.channels)): channelID = serverData.networkData.channels[index] name = self.state.channelDefinitions[index].name self.log.info("%(channelName)s <---> Channel #%(channelId)d", {"channelName": name, "channelId": channelID}) self.state.channelMap[channelID] = name # Replace the server's public key with our own key so we can decrypt the incoming client random cert = serverData.securityData.serverCertificate if cert: cert = ProprietaryCertificate( cert.signatureAlgorithmID, cert.keyAlgorithmID, cert.publicKeyType, self.state.rc4RSAKey, cert.signatureType, cert.signature, cert.padding ) # FIPS is not implemented so avoid using that security = ServerSecurityData( serverData.securityData.encryptionMethod if serverData.securityData.encryptionMethod != EncryptionMethod.ENCRYPTION_FIPS else EncryptionMethod.ENCRYPTION_128BIT, serverData.securityData.encryptionLevel if serverData.securityData.encryptionLevel != EncryptionLevel.ENCRYPTION_LEVEL_FIPS else EncryptionLevel.ENCRYPTION_LEVEL_HIGH, serverData.securityData.serverRandom, cert ) # The clientRequestedProtocols field MUST be the same as the one received in the X224 Connection Request serverData.coreData.clientRequestedProtocols = self.state.requestedProtocols modifiedServerData = ServerDataPDU(serverData.coreData, security, serverData.networkData) modifiedGCCPDU = GCCConferenceCreateResponsePDU(gccPDU.nodeID, gccPDU.tag, gccPDU.result, rdpParser.write(modifiedServerData)) modifiedMCSPDU = MCSConnectResponsePDU(pdu.result, pdu.calledConnectID, pdu.domainParams, gccParser.write(modifiedGCCPDU)) self.client.sendPDU(modifiedMCSPDU)