def parseConnectionPDU(self, data: bytes, length: int, name: str) -> Tuple[int, int, int, bytes]: """ Parse the provided data to extract common information contained in Connection Request, Connection Confirm and Disconnect Request PDUs. :param data: bytes to parse. :param length: Length of the Connection PDU. :param name: For debugging purposes: the name of the connection PDU (like "Connection Request"). :return: A tuple of the information we find in both connection PDUs: (source, destination, options, payload) """ if length < 6: raise ParsingError( "Invalid X244 %s length indicator: indicator = %d, expected at least 6 bytes" % (name, 6)) destination = Uint16BE.unpack(data[2:4]) source = Uint16BE.unpack(data[4:6]) options = Uint8.unpack(data[6]) payload = data[7:] if len(payload) != length - 6: raise ParsingError( "Invalid X224 %s payload length: expected = %d, length = %d" % (name, length - 6, len(payload))) return source, destination, options, payload
def parseDomainParams(self, stream): """ Parse a MCSDomainParam from stream :param stream: byte stream containing the data :type stream: BytesIO :return: MCSDomainParam """ if not ber.readUniversalTag(stream, ber.Tag.BER_TAG_SEQUENCE, True): raise ParsingError("Invalid BER tag (%d expected)" % ber.Tag.BER_TAG_SEQUENCE) length = ber.readLength(stream) if length > len(stream.getvalue()): raise ParsingError( "Invalid size for DomainParameters (got %d, %d bytes left)" % (length, len(stream.getvalue()))) maxChannelIDs = ber.readInteger(stream) maxUserIDs = ber.readInteger(stream) maxTokenIDs = ber.readInteger(stream) numPriorities = ber.readInteger(stream) minThroughput = ber.readInteger(stream) maxHeight = ber.readInteger(stream) maxMCSPDUSize = ber.readInteger(stream) protocolVersion = ber.readInteger(stream) return MCSDomainParams(maxChannelIDs, maxUserIDs, maxTokenIDs, numPriorities, minThroughput, maxHeight, maxMCSPDUSize, protocolVersion)
def doParse(self, data: bytes) -> GCCPDU: """ Parses the raw data bytes into a GCCPDU :param data: PDU data. """ stream = BytesIO(data) tag = per.readChoice(stream) if tag != 0: raise ParsingError("Expected object tag (0), got %d instead" % tag) oid = per.readObjectIdentifier(stream) if oid != GCCParser.T124_02_98_OID: raise ParsingError("Invalid object identifier: %r, expected %r" % (oid, GCCParser.T124_02_98_OID)) _length = per.readLength(stream) header = per.readChoice(stream) if header not in self.parsers: raise UnknownPDUTypeError( "Trying to parse unknown GCC PDU type %s" % header, header) pdu = self.parsers[header](stream) return pdu
def parse(self, data: bytes) -> X224PDU: """ Read the byte stream and return a corresponding X224PDU """ length = Uint8.unpack(data[0]) header = Uint8.unpack(data[1]) >> 4 if header in list(X224PDUType): header = X224PDUType(header) if length < 2: raise ParsingError( "Invalid X224 length indicator: indicator = %d, expected at least 2 bytes" % length) if len(data) < length: raise ParsingError( "Invalid X224 length indicator: indicator = %d, length = %d" % (length, len(data))) if header not in self.parsers: raise UnknownPDUTypeError( "Trying to parse unknown X224 PDU type: %s" % (header if header in X224PDUType else hex(header)), header) return self.parsers[header](data, length)
def parseConferenceCreateResponse( self, stream: BytesIO) -> GCCConferenceCreateResponsePDU: """ Parse ConferenceCreateResponse data into a GCCPDU :param stream: byte stream containing the PDU data """ nodeID = Uint16BE.unpack(stream.read(2)) + 1001 tag = per.readInteger(stream) result = per.readEnumeration(stream) userDataCount = per.readNumberOfSet(stream) if userDataCount != 1: raise ParsingError("Expected user data count to be 1, got %d" % userDataCount) userDataType = per.readChoice(stream) if userDataType != 0xc0: raise ParsingError( "Expected user data type to be 0xc0 (h221NonStandard), got %d" % userDataType) key = per.readOctetStream(stream, 4) if key != GCCParser.H221_SERVER_KEY: raise ParsingError("Expected user data key to be %s, got %s" % (GCCParser.H221_SERVER_KEY, key)) payload = per.readOctetStream(stream) return GCCConferenceCreateResponsePDU(nodeID, tag, result, payload)
def parseConferenceCreateRequest( self, stream: BytesIO) -> GCCConferenceCreateRequestPDU: """ Parse ConferenceCreateRequest data into a GCCPDU :param stream: byte stream containing the PDU data """ prop = per.readSelection(stream) if prop != 8: raise ParsingError( "Expected property to be 8 (conference name), got %d" % prop) conferenceName = per.readNumericString(stream, 1) stream.read(1) userDataCount = per.readNumberOfSet(stream) if userDataCount != 1: raise ParsingError("Expected user data count to be 1, got %d" % userDataCount) userDataType = per.readChoice(stream) if userDataType != 0xc0: raise ParsingError( "Expected user data type to be 0xc0 (h221NonStandard), got %d" % userDataType) key = per.readOctetStream(stream, 4) if key != GCCParser.H221_CLIENT_KEY: raise ParsingError("Expected user data key to be %s, got %s" % (GCCParser.H221_CLIENT_KEY, key)) payload = per.readOctetStream(stream) return GCCConferenceCreateRequestPDU(conferenceName, payload)
def doParse(self, stream): messageType = Uint16LE.unpack(stream) stream.read(2) if messageType not in self.parsers: raise ParsingError("Trying to parse invalid pointer event type") return self.parsers[messageType](stream)
def parse(self, stream): eventTime = Uint32LE.unpack(stream) messageType = Uint16LE.unpack(stream) if messageType not in self.parsers: raise ParsingError("Invalid input message type") return self.parsers[messageType](stream, eventTime)
def writeClientNetworkData(self, stream: BytesIO, network: ClientNetworkData): stream.write(Uint32LE.pack(len(network.channelDefinitions))) for channel in network.channelDefinitions: if len(channel.name) > 8: raise ParsingError("Channel name must have 8 characters maximum") stream.write(channel.name.encode().ljust(8, b"\x00")[: 8]) stream.write(Uint32LE.pack(channel.options))
def parseAttachUserRequest(self, stream: BytesIO) -> MCSAttachUserRequestPDU: """ Parse an Attach User Request PDU :param stream: stream containing the data """ if len(stream.read()) > 0: raise ParsingError("Unexpected payload") return MCSAttachUserRequestPDU()
def parseError(self, data, length): """ Parse a Error PDU from the raw bytes :type data: bytes :param length: The length in bytes of the Error PDU. :return: X224ErrorPDU """ if length < 4: raise ParsingError("Invalid X224 Error PDU length indicator: indicator = %d, expected at least 4 bytes") destination = Uint16BE.unpack(data[2 : 4]) cause = Uint8.unpack(data[4]) payload = data[5 :] if len(payload) != length - 4: raise ParsingError("Invalid X224 Error PDU payload length: expected = %d, length = %d" % (length - 4, len(payload))) return X224ErrorPDU(destination, cause, payload)
def write(self, event): stream = BytesIO() Uint16LE.pack(event.messageType, stream) stream.write(b"\x00" * 2) if event.messageType not in self.writers: raise ParsingError("Trying to write invalid pointer event type") self.writers[event.messageType](stream, event) return stream.getvalue()
def parseDisconnectProviderUltimatum(self, stream: BytesIO) -> MCSDisconnectProviderUltimatumPDU: """ Parse a Disconnect Provider Ultimatum PDU :param stream: stream containing the data """ reason = per.readEnumeration(stream) if len(stream.read()) > 0: raise ParsingError("Unexpected payload") return MCSDisconnectProviderUltimatumPDU(reason)
def parseStructure(self, stream: BytesIO) -> typing.Union[ClientCoreData, ClientNetworkData, ClientSecurityData, ClientClusterData]: header = Uint16LE.unpack(stream) length = Uint16LE.unpack(stream) - 4 data = stream.read(length) if len(data) != length: raise ParsingError("Client Data length field does not match actual size") substream = BytesIO(data) if header not in self.parsers: raise UnknownPDUTypeError("Trying to parse unknown client data structure %s" % header, header) return self.parsers[header](substream)
def parseStructure(self, stream): header = Uint16LE.unpack(stream) length = Uint16LE.unpack(stream) - 4 data = stream.read(length) if len(data) != length: raise ParsingError("Client Data length field does not match actual size") substream = BytesIO(data) if header not in self.parsers: raise UnknownPDUTypeError("Trying to parse unknown client data structure %s" % header, header) return self.parsers[header](substream)
def parseChannelJoinRequest(self, stream: BytesIO) -> MCSChannelJoinRequestPDU: """ Parse a Channel Join Request PDU :param stream: stream containing the data """ data = stream.read() if len(data) < 4: raise ParsingError("Invalid Channel Join Request PDU received") initiator = Uint16BE.unpack(data[0 : 2]) + MCSChannelID.USERCHANNEL_BASE channelID = Uint16BE.unpack(data[2 : 4]) payload = data[4 :] return MCSChannelJoinRequestPDU(initiator, channelID, payload)
def parse(self, data: bytes) -> TPKTPDU: """ Read the byte stream and return a TPKTPDU """ _version = Uint8.unpack(data[0:1]) _padding = Uint8.unpack(data[1:2]) length = Uint16BE.unpack(data[2:4]) payload = data[4:length] if len(payload) != length - 4: raise ParsingError("Payload is too short for TPKT length field") return TPKTPDU(payload)
def parseClientNetworkData(self, stream): channelCount = Uint32LE.unpack(stream) data = stream.getvalue()[4:] if len(data) != channelCount * 12: raise ParsingError("Invalid channel array size") channelDefinitions = [] for _ in range(channelCount): name = stream.read(8).strip(b"\x00").decode() options = Uint32LE.unpack(stream) channelDefinitions.append(ClientChannelDefinition(name, options)) return ClientNetworkData(channelDefinitions)
def parseAttachUserConfirm(self, stream: BytesIO) -> MCSAttachUserConfirmPDU: """ Parse an Attach User Confirm PDU :param stream: stream containing the data """ result = per.readEnumeration(stream) data = stream.read() initiator = None if len(data) == 2: initiator = Uint16BE.unpack(data) + MCSChannelID.USERCHANNEL_BASE elif len(data) > 2: raise ParsingError("Unexpected payload") return MCSAttachUserConfirmPDU(result, initiator)
def parseData(self, data, length): """ Parse a Data PDU from the raw bytes :type data: bytes :param length: The length in bytes of the Data PDU. :return: X224DataPDU """ if length != 2: raise ParsingError("Invalid X224 Data PDU length indicator: expected = 2, indicator = %d" % length) code = Uint8.unpack(data[1]) & 0xf sequence = Uint8.unpack(data[2]) payload = data[3 :] return X224DataPDU(code & 1 == 1, sequence & 0x80 == 0x80, payload)
def parseClientNetworkData(self, stream: BytesIO) -> ClientNetworkData: if self.detectBlueKeepScan(stream.getvalue()): raise ExploitError("BlueKeep scan or exploit attempted") channelCount = Uint32LE.unpack(stream) data = stream.getvalue()[4 :] if len(data) != channelCount * 12: raise ParsingError("Invalid channel array size") channelDefinitions = [] for _ in range(channelCount): name = stream.read(8).strip(b"\x00").decode() options = Uint32LE.unpack(stream) channelDefinitions.append(ClientChannelDefinition(name, options)) return ClientNetworkData(channelDefinitions)
def parseChannelJoinConfirm(self, stream: BytesIO) -> MCSChannelJoinConfirmPDU: """ Parse a Channel Join Confirm PDU :param stream: stream containing the data """ result = per.readEnumeration(stream) data = stream.read() if len(data) < 4 or len(data) == 5: raise ParsingError("Invalid Channel Join Confirm PDU received") elif len(data) >= 6: channelID = Uint16BE.unpack(data[4 : 6]) payload = data[6 :] else: channelID = None payload = b"" initiator = Uint16BE.unpack(data[0 : 2]) + MCSChannelID.USERCHANNEL_BASE requested = Uint16BE.unpack(data[2 : 4]) return MCSChannelJoinConfirmPDU(result, initiator, requested, channelID, payload)