diff --git a/bin/rdpy-rdpclient.py b/bin/rdpy-rdpclient.py index e1e7adb..69bc0da 100755 --- a/bin/rdpy-rdpclient.py +++ b/bin/rdpy-rdpclient.py @@ -25,7 +25,8 @@ import sys import asyncio from rdpy.core import tpkt, x224 -from rdpy.model.type import UInt8 +from rdpy.core.nla import ntlm +from rdpy.model.message import UInt8 if __name__ == '__main__': @@ -35,9 +36,9 @@ if __name__ == '__main__': reader, writer = await asyncio.open_connection( '127.0.0.1', 33389) - x224_layer = await x224.connect(tpkt.Tpkt(reader, writer)) + x224_layer = await x224.connect(tpkt.Tpkt(reader, writer), ntlm.NTLMv2("", "sylvain", "sylvain")) await x224_layer.write(UInt8(8)) - await asyncio.sleep(1000) + await asyncio.sleep(10) print("foooooooooooooooooooo") asyncio.run(tcp_echo_client('Hello World!')) \ No newline at end of file diff --git a/rdpy/core/lic.py b/rdpy/core/lic.py index 1aca35a..6e4725e 100644 --- a/rdpy/core/lic.py +++ b/rdpy/core/lic.py @@ -22,7 +22,7 @@ @see: http://msdn.microsoft.com/en-us/library/cc241880.aspx """ -from rdpy.model.type import CompositeType, CallableValue, UInt8, UInt16Le, UInt32Le, String, sizeof, FactoryType, ArrayType, Stream +from rdpy.model.type import CompositeType, CallableValue, UInt8, UInt16Le, UInt32Le, Buffer, sizeof, FactoryType, ArrayType, Stream from rdpy.model.error import InvalidExpectedDataException import rdpy.model.log as log from rdpy.core import sec @@ -102,7 +102,7 @@ class LicenseBinaryBlob(CompositeType): CompositeType.__init__(self, optional = optional) self.wBlobType = UInt16Le(blobType, constant = True if blobType != BinaryBlobType.BB_ANY_BLOB else False) self.wBlobLen = UInt16Le(lambda:sizeof(self.blobData)) - self.blobData = String(readLen = self.wBlobLen) + self.blobData = Buffer(readLen = self.wBlobLen) class LicensingErrorMessage(CompositeType): """ @@ -127,10 +127,10 @@ class ProductInformation(CompositeType): self.dwVersion = UInt32Le() self.cbCompanyName = UInt32Le(lambda:sizeof(self.pbCompanyName)) #may contain "Microsoft Corporation" from server microsoft - self.pbCompanyName = String("Microsoft Corporation", readLen = self.cbCompanyName, unicode = True) + self.pbCompanyName = Buffer("Microsoft Corporation", readLen = self.cbCompanyName, unicode = True) self.cbProductId = UInt32Le(lambda:sizeof(self.pbProductId)) #may contain "A02" from microsoft license server - self.pbProductId = String("A02", readLen = self.cbProductId, unicode = True) + self.pbProductId = Buffer("A02", readLen = self.cbProductId, unicode = True) class Scope(CompositeType): @@ -162,7 +162,7 @@ class ServerLicenseRequest(CompositeType): def __init__(self, readLen = None): CompositeType.__init__(self, readLen = readLen) - self.serverRandom = String("\x00" * 32, readLen = CallableValue(32)) + self.serverRandom = Buffer("\x00" * 32, readLen = CallableValue(32)) self.productInfo = ProductInformation() self.keyExchangeList = LicenseBinaryBlob(BinaryBlobType.BB_KEY_EXCHG_ALG_BLOB) self.serverCertificate = LicenseBinaryBlob(BinaryBlobType.BB_CERTIFICATE_BLOB) @@ -183,7 +183,7 @@ class ClientNewLicenseRequest(CompositeType): #pure microsoft client ;-) #http://msdn.microsoft.com/en-us/library/1040af38-c733-4fb3-acd1-8db8cc979eda#id10 self.platformId = UInt32Le(0x04000000 | 0x00010000) - self.clientRandom = String("\x00" * 32, readLen = CallableValue(32)) + self.clientRandom = Buffer("\x00" * 32, readLen = CallableValue(32)) self.encryptedPreMasterSecret = LicenseBinaryBlob(BinaryBlobType.BB_RANDOM_BLOB) self.ClientUserName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_USER_NAME_BLOB) self.ClientMachineName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_MACHINE_NAME_BLOB) @@ -199,7 +199,7 @@ class ServerPlatformChallenge(CompositeType): CompositeType.__init__(self, readLen = readLen) self.connectFlags = UInt32Le() self.encryptedPlatformChallenge = LicenseBinaryBlob(BinaryBlobType.BB_ANY_BLOB) - self.MACData = String(readLen = CallableValue(16)) + self.MACData = Buffer(readLen = CallableValue(16)) class ClientPLatformChallengeResponse(CompositeType): """ @@ -212,7 +212,7 @@ class ClientPLatformChallengeResponse(CompositeType): CompositeType.__init__(self, readLen = readLen) self.encryptedPlatformChallengeResponse = LicenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB) self.encryptedHWID = LicenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB) - self.MACData = String(readLen = CallableValue(16)) + self.MACData = Buffer(readLen = CallableValue(16)) class LicPacket(CompositeType): """ @@ -234,7 +234,7 @@ class LicPacket(CompositeType): if self.bMsgtype.value == c._MESSAGE_TYPE_: return c(readLen = self.wMsgSize - 4) log.debug("unknown license message : %s"%self.bMsgtype.value) - return String(readLen = self.wMsgSize - 4) + return Buffer(readLen =self.wMsgSize - 4) if message is None: message = FactoryType(LicensingMessageFactory) @@ -340,7 +340,7 @@ class LicenseManager(object): #generate hwid s = Stream() - s.write_type((UInt32Le(2), String(self._hostname + self._username + "\x00" * 16))) + s.write_type((UInt32Le(2), Buffer(self._hostname + self._username + "\x00" * 16))) hwid = s.getvalue()[:20] message = ClientPLatformChallengeResponse() diff --git a/rdpy/core/nla/cssp.py b/rdpy/core/nla/cssp.py index b05fa15..f5494c7 100644 --- a/rdpy/core/nla/cssp.py +++ b/rdpy/core/nla/cssp.py @@ -25,18 +25,19 @@ from pyasn1.type import namedtype, univ, tag import pyasn1.codec.der.encoder as der_encoder import pyasn1.codec.der.decoder as der_decoder -import pyasn1.codec.ber.encoder as ber_encoder from rdpy.core.nla import sspi -from rdpy.model.type import Stream -from rdpy.security import x509 +from rdpy.model.message import Stream from rdpy.model import error +from rdpy.security.x509 import X509Certificate + class NegoToken(univ.Sequence): componentType = namedtype.NamedTypes( namedtype.NamedType('negoToken', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))), ) + class NegoData(univ.SequenceOf): """ @summary: contain spnego ntlm of kerberos data @@ -44,6 +45,7 @@ class NegoData(univ.SequenceOf): """ componentType = NegoToken() + class TSRequest(univ.Sequence): """ @summary: main structure @@ -57,6 +59,7 @@ class TSRequest(univ.Sequence): namedtype.OptionalNamedType('errorCode', univ.Integer().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4))) ) + class TSCredentials(univ.Sequence): """ @summary: contain user information @@ -66,7 +69,8 @@ class TSCredentials(univ.Sequence): namedtype.NamedType('credType', univ.Integer().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))), namedtype.NamedType('credentials', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))) ) - + + class TSPasswordCreds(univ.Sequence): """ @summary: contain username and password @@ -78,6 +82,7 @@ class TSPasswordCreds(univ.Sequence): namedtype.NamedType('password', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))) ) + class TSCspDataDetail(univ.Sequence): """ @summary: smart card credentials @@ -91,6 +96,7 @@ class TSCspDataDetail(univ.Sequence): namedtype.OptionalNamedType('cspName', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4))) ) + class TSSmartCardCreds(univ.Sequence): """ @summary: smart card credentials @@ -103,16 +109,6 @@ class TSSmartCardCreds(univ.Sequence): namedtype.OptionalNamedType('domainHint', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))) ) -class OpenSSLRSAPublicKey(univ.Sequence): - """ - @summary: asn1 public rsa key - @see: https://tools.ietf.org/html/rfc3447 - """ - componentType = namedtype.NamedTypes( - namedtype.NamedType('unknow', univ.Integer()), - namedtype.NamedType('modulus', univ.Integer()), - namedtype.NamedType('publicExponent', univ.Integer()), - ) def encode_der_trequest(nego_types=[], auth_info=None, pub_key_auth=None): @@ -161,69 +157,50 @@ def decode_der_trequest(s): def getNegoTokens(tRequest): negoData = tRequest.getComponentByName("negoTokens") return [Stream(negoData.getComponentByPosition(i).getComponentByPosition(0).asOctets()) for i in range(len(negoData))] - -def getPubKeyAuth(tRequest): - return tRequest.getComponentByName("pubKeyAuth").asOctets() -def encodeDERTCredentials(domain, username, password): + +def encode_der_tcredentials(domain, username, password): passwordCred = TSPasswordCreds() - passwordCred.setComponentByName("domainName", univ.OctetString(domain).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))) - passwordCred.setComponentByName("userName", univ.OctetString(username).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))) - passwordCred.setComponentByName("password", univ.OctetString(password).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))) + passwordCred.setComponentByName("domainName", domain) + passwordCred.setComponentByName("userName", username) + passwordCred.setComponentByName("password", password) credentials = TSCredentials() - credentials.setComponentByName("credType", univ.Integer(1).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))) - credentials.setComponentByName("credentials", univ.OctetString(der_encoder.encode(passwordCred)).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))) + credentials.setComponentByName("credType", 1) + credentials.setComponentByName("credentials", der_encoder.encode(passwordCred)) return der_encoder.encode(credentials) async def connect(reader, writer, authentication_protocol: sspi.IAuthenticationProtocol): """ + CSSP connection sequence """ - # send negotiate message writer.write(encode_der_trequest(nego_types=[authentication_protocol.getNegotiateMessage()])) await writer.drain() - print("toto") + trequest = decode_der_trequest(await reader.read(1500)) - print("yahoo") message, interface = authentication_protocol.getAuthenticateMessage(getNegoTokens(trequest)[0]) -def recvChallenge(self, data): - """ - @summary: second state in cssp automata - @param data : {str} all data available on buffer - """ - request = decode_der_trequest(data) - message, self._interface = self._authenticationProtocol.getAuthenticateMessage(getNegoTokens(request)[0]) - #get back public key - #convert from der to ber... - pubKeyDer = crypto.dump_privatekey(crypto.FILETYPE_ASN1, self.transport.protocol._tlsConnection.get_peer_certificate().get_pubkey()) - pubKey = der_decoder.decode(pubKeyDer, asn1Spec=OpenSSLRSAPublicKey())[0] + # get binary certificate + # There is no other way to get certificate that have net been validated + peer_certificate = writer.transport._ssl_protocol._sslpipe.ssl_object._sslobj.getpeercert(True) + x509_certificate = der_decoder.decode(peer_certificate, asn1Spec=X509Certificate())[0] + public_key = x509_certificate.getComponentByName("tbsCertificate").getComponentByName("subjectPublicKeyInfo").getComponentByName("subjectPublicKey").asOctets() - rsa = x509.RSAPublicKey() - rsa.setComponentByName("modulus", univ.Integer(pubKey.getComponentByName('modulus')._value)) - rsa.setComponentByName("publicExponent", univ.Integer(pubKey.getComponentByName('publicExponent')._value)) - self._pubKeyBer = ber_encoder.encode(rsa) + # send back public key encrypted with NTLM + writer.write(encode_der_trequest(nego_types=[message], pub_key_auth=interface.GSS_WrapEx(public_key))) + await writer.drain() - #send authenticate message with public key encoded - self.transport.write(encode_der_trequest(nego_types= [message], pub_key_auth= self._interface.GSS_WrapEx(self._pubKeyBer))) - #next step is received public key incremented by one - self.dataReceived = self.recvPubKeyInc + # now check the increment + # sever must respond with the same key incremented to one + trequest = decode_der_trequest(await reader.read(1500)) + public_key_inc = interface.GSS_UnWrapEx(trequest.getComponentByName("pubKeyAuth").asOctets()) -def recvPubKeyInc(self, data): - """ - @summary: the server send the pubKeyBer + 1 - @param data : {str} all data available on buffer - """ - request = decode_der_trequest(data) - pubKeyInc = self._interface.GSS_UnWrapEx(getPubKeyAuth(request)) - #check pubKeyInc = self._pubKeyBer + 1 - if not (self._pubKeyBer[1:] == pubKeyInc[1:] and ord(self._pubKeyBer[0]) + 1 == ord(pubKeyInc[0])): + if int.from_bytes(public_key, "little") + 1 != int.from_bytes(public_key_inc, "little"): raise error.InvalidExpectedDataException("CSSP : Invalid public key increment") - domain, user, password = self._authenticationProtocol.getEncodedCredentials() - #send credentials - self.transport.write(encode_der_trequest( - auth_info= self._interface.GSS_WrapEx(encodeDERTCredentials(domain, user, password)))) + domain, user, password = authentication_protocol.getEncodedCredentials() + writer.write(encode_der_trequest(auth_info=interface.GSS_WrapEx(encode_der_tcredentials(domain, user, password)))) + await writer.drain() diff --git a/rdpy/core/nla/ntlm.py b/rdpy/core/nla/ntlm.py index ebc5afc..17da8ff 100644 --- a/rdpy/core/nla/ntlm.py +++ b/rdpy/core/nla/ntlm.py @@ -27,9 +27,10 @@ from rdpy.core.nla import sspi import rdpy.security.pyDes as pyDes import rdpy.security.rc4 as rc4 from rdpy.security.rsa_wrapper import random -from rdpy.model.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt24Le, UInt32Le, sizeof, Stream +from rdpy.model.message import CompositeType, Buffer, UInt8, UInt16Le, UInt24Le, UInt32Le, sizeof, Stream from rdpy.model import filetimes, error + class MajorVersion(object): """ @see: https://msdn.microsoft.com/en-us/library/cc236654.aspx @@ -37,7 +38,8 @@ class MajorVersion(object): """ WINDOWS_MAJOR_VERSION_5 = 0x05 WINDOWS_MAJOR_VERSION_6 = 0x06 - + + class MinorVersion(object): """ @see: https://msdn.microsoft.com/en-us/library/cc236654.aspx @@ -47,13 +49,15 @@ class MinorVersion(object): WINDOWS_MINOR_VERSION_1 = 0x01 WINDOWS_MINOR_VERSION_2 = 0x02 WINDOWS_MINOR_VERSION_3 = 0x03 - + + class NTLMRevision(object): """ @see: https://msdn.microsoft.com/en-us/library/cc236654.aspx """ NTLMSSP_REVISION_W2K3 = 0x0F - + + class Negotiate(object): """ @see: https://msdn.microsoft.com/en-us/library/cc236650.aspx @@ -79,7 +83,8 @@ class Negotiate(object): NTLMSSP_REQUEST_TARGET = 0x00000004 NTLM_NEGOTIATE_OEM = 0x00000002 NTLMSSP_NEGOTIATE_UNICODE = 0x00000001 - + + class AvId(object): """ @see: https://msdn.microsoft.com/en-us/library/cc236646.aspx @@ -124,8 +129,8 @@ class AvPair(CompositeType): def __init__(self): CompositeType.__init__(self) self.AvId = UInt16Le() - self.AvLen = UInt16Le(lambda:sizeof(self.Value)) - self.Value = String(readLen = self.AvLen) + self.AvLen = UInt16Le(lambda: sizeof(self.Value)) + self.Value = Buffer(read_len=lambda: self.AvLen.value) class MessageSignatureEx(CompositeType): """ @@ -135,7 +140,7 @@ class MessageSignatureEx(CompositeType): def __init__(self): CompositeType.__init__(self) self.Version = UInt32Le(0x00000001, constant = True) - self.Checksum = String(readLen = CallableValue(8)) + self.Checksum = Buffer(read_len=lambda: 8) self.SeqNum = UInt32Le() class NegotiateMessage(CompositeType): @@ -144,9 +149,9 @@ class NegotiateMessage(CompositeType): @see: https://msdn.microsoft.com/en-us/library/cc236641.aspx """ def __init__(self): - CompositeType.__init__(self) - self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True) - self.MessageType = UInt32Le(0x00000001, constant = True) + super().__init__() + self.Signature = Buffer(b"NTLMSSP\x00", read_len=lambda: 8, constant=True) + self.MessageType = UInt32Le(0x00000001, constant=True) self.NegotiateFlags = UInt32Le() @@ -160,7 +165,7 @@ class NegotiateMessage(CompositeType): self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION)) - self.Payload = String() + self.Payload = Buffer() class ChallengeMessage(CompositeType): """ @@ -169,8 +174,8 @@ class ChallengeMessage(CompositeType): """ def __init__(self): CompositeType.__init__(self) - self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True) - self.MessageType = UInt32Le(0x00000002, constant = True) + self.Signature = Buffer(b"NTLMSSP\x00", read_len=lambda: 8, constant=True) + self.MessageType = UInt32Le(0x00000002, constant=True) self.TargetNameLen = UInt16Le() self.TargetNameMaxLen = UInt16Le(lambda:self.TargetNameLen.value) @@ -178,15 +183,15 @@ class ChallengeMessage(CompositeType): self.NegotiateFlags = UInt32Le() - self.ServerChallenge = String(readLen = CallableValue(8)) - self.Reserved = String("\x00" * 8, readLen = CallableValue(8)) + self.ServerChallenge = Buffer(read_len=lambda: 8) + self.Reserved = Buffer(b"\x00" * 8, read_len=lambda: 8) self.TargetInfoLen = UInt16Le() - self.TargetInfoMaxLen = UInt16Le(lambda:self.TargetInfoLen.value) + self.TargetInfoMaxLen = UInt16Le(lambda: self.TargetInfoLen.value) self.TargetInfoBufferOffset = UInt32Le() - self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION)) - self.Payload = String() + self.Version = Version(conditional=lambda: (self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION)) + self.Payload = Buffer() def getTargetName(self): return getPayLoadField(self, self.TargetNameLen.value, self.TargetNameBufferOffset.value) @@ -216,8 +221,8 @@ class AuthenticateMessage(CompositeType): """ def __init__(self): CompositeType.__init__(self) - self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True) - self.MessageType = UInt32Le(0x00000003, constant = True) + self.Signature = Buffer(b"NTLMSSP\x00", read_len=lambda: 8, constant = True) + self.MessageType = UInt32Le(0x00000003, constant=True) self.LmChallengeResponseLen = UInt16Le() self.LmChallengeResponseMaxLen = UInt16Le(lambda:self.LmChallengeResponseLen.value) @@ -246,8 +251,8 @@ class AuthenticateMessage(CompositeType): self.NegotiateFlags = UInt32Le() self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION)) - self.MIC = String("\x00" * 16, readLen = CallableValue(16)) - self.Payload = String() + self.MIC = Buffer(b"\x00" * 16, read_len=lambda: 16) + self.Payload = Buffer() def getUserName(self): return getPayLoadField(self, self.UserNameLen.value, self.UserNameBufferOffset.value) @@ -347,6 +352,7 @@ def DESL(key, data): """ return DES(key[0:7], data) + DES(key[7:14], data) + DES(key[14:16] + "\x00" * 5, data) + def UNICODE(s): """ @param s: source @@ -354,6 +360,7 @@ def UNICODE(s): """ return s.encode('utf-16le') + def MD4(s): """ @summary: compute the md4 sum @@ -362,6 +369,7 @@ def MD4(s): """ return hashlib.new('md4', s).digest() + def MD5(s): """ @summary: compute the md5 sum @@ -370,13 +378,15 @@ def MD5(s): """ return hashlib.new('md5', s).digest() + def Z(m): """ @summary: fill m zero in string @param m: {int} size of string @return: \x00 * m """ - return "\x00" * m + return b"\x00" * m + def RC4K(key, plaintext): """ @@ -387,6 +397,7 @@ def RC4K(key, plaintext): """ return rc4.crypt(rc4.RC4Key(key), plaintext) + def KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge): """ @summary: Key eXchange Key for NTLMv2 @@ -397,17 +408,20 @@ def KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge): """ return SessionBaseKey + def SEALKEY(ExportedSessionKey, client): if client: - return MD5(ExportedSessionKey + "session key to client-to-server sealing key magic constant\0") + return MD5(ExportedSessionKey + b"session key to client-to-server sealing key magic constant\0") else: - return MD5(ExportedSessionKey + "session key to server-to-client sealing key magic constant\0") + return MD5(ExportedSessionKey + b"session key to server-to-client sealing key magic constant\0") + def SIGNKEY(ExportedSessionKey, client): if client: - return MD5(ExportedSessionKey + "session key to client-to-server signing key magic constant\0") + return MD5(ExportedSessionKey + b"session key to client-to-server signing key magic constant\0") else: - return MD5(ExportedSessionKey + "session key to server-to-client signing key magic constant\0") + return MD5(ExportedSessionKey + b"session key to server-to-client signing key magic constant\0") + def HMAC_MD5(key, data): """ @@ -417,6 +431,7 @@ def HMAC_MD5(key, data): """ return hmac.new(key, data, hashlib.md5).digest() + def NTOWFv2(Passwd, User, UserDom): """ @summary: Version 2 of NTLM hash function @@ -427,6 +442,7 @@ def NTOWFv2(Passwd, User, UserDom): """ return HMAC_MD5(MD4(UNICODE(Passwd)), UNICODE(User.upper() + UserDom)) + def LMOWFv2(Passwd, User, UserDom): """ @summary: Same as NTOWFv2 @@ -437,14 +453,15 @@ def LMOWFv2(Passwd, User, UserDom): """ return NTOWFv2(Passwd, User, UserDom) + def ComputeResponsev2(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChallenge, Time, ServerName): """ @summary: process NTLMv2 Authenticate hash @param NegFlg: {int} Negotiation flags come from challenge message @see: https://msdn.microsoft.com/en-us/library/cc236700.aspx """ - Responserversion = "\x01" - HiResponserversion = "\x01" + Responserversion = b"\x01" + HiResponserversion = b"\x01" temp = Responserversion + HiResponserversion + Z(6) + Time + ClientChallenge + Z(4) + ServerName NTProofStr = HMAC_MD5(ResponseKeyNT, ServerChallenge + temp) @@ -455,6 +472,7 @@ def ComputeResponsev2(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChall return NtChallengeResponse, LmChallengeResponse, SessionBaseKey + def MAC(handle, SigningKey, SeqNum, Message): """ @summary: generate signature for application message @@ -475,6 +493,7 @@ def MAC(handle, SigningKey, SeqNum, Message): return signature + def MIC(ExportedSessionKey, negotiateMessage, challengeMessage, authenticateMessage): """ @summary: Compute MIC signature @@ -487,12 +506,13 @@ def MIC(ExportedSessionKey, negotiateMessage, challengeMessage, authenticateMess s = Stream() s.write_type((negotiateMessage, challengeMessage, authenticateMessage)) return HMAC_MD5(ExportedSessionKey, s.getvalue()) - + + class NTLMv2(sspi.IAuthenticationProtocol): """ @summary: Handle NTLMv2 Authentication """ - def __init__(self, domain, user, password): + def __init__(self, domain: str, user: str, password: str): self._domain = domain self._user = user self._password = password @@ -538,7 +558,7 @@ class NTLMv2(sspi.IAuthenticationProtocol): computeMIC = False ServerName = self._challengeMessage.getTargetInfo() infos = self._challengeMessage.getTargetInfoAsAvPairArray() - if infos.has_key(AvId.MsvAvTimestamp): + if AvId.MsvAvTimestamp in infos.keys(): Timestamp = infos[AvId.MsvAvTimestamp] computeMIC = True else: @@ -554,7 +574,7 @@ class NTLMv2(sspi.IAuthenticationProtocol): if self._challengeMessage.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_UNICODE: self._enableUnicode = True domain, user = UNICODE(domain), UNICODE(user) - self._authenticateMessage = createAuthenticationMessage(self._challengeMessage.NegotiateFlags.value, domain, user, NtChallengeResponse, LmChallengeResponse, EncryptedRandomSessionKey, "") + self._authenticateMessage = createAuthenticationMessage(self._challengeMessage.NegotiateFlags.value, domain, user, NtChallengeResponse, LmChallengeResponse, EncryptedRandomSessionKey, b"") if computeMIC: self._authenticateMessage.MIC.value = MIC(ExportedSessionKey, self._negotiateMessage, self._challengeMessage, self._authenticateMessage) @@ -616,16 +636,13 @@ class NTLMv2SecurityInterface(sspi.IGenericSecurityService): @summary: decrypt data with key exchange in Authentication protocol @param data: {str} """ - signature = MessageSignatureEx() - message = String() - s = Stream(data) - s.read_type((signature, message)) + signature, message = Stream(data).read_type((MessageSignatureEx(), Buffer())) #decrypt message plaintextMessage = rc4.crypt(self._decryptHandle, message.value) checksum = rc4.crypt(self._decryptHandle, signature.Checksum.value) - #recompute checksum + # recompute checksum t = Stream() t.write_type(signature.SeqNum) verify = HMAC_MD5(self._verifyKey, t.getvalue() + plaintextMessage)[:8] diff --git a/rdpy/core/pdu/caps.py b/rdpy/core/pdu/caps.py index 14b2d89..88d73a1 100644 --- a/rdpy/core/pdu/caps.py +++ b/rdpy/core/pdu/caps.py @@ -24,7 +24,7 @@ Definition of structure use for capabilities nego Use in PDU layer """ -from rdpy.model.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType +from rdpy.model.type import CompositeType, CallableValue, Buffer, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType class CapsType(object): @@ -241,7 +241,7 @@ class Capability(CompositeType): return c(readLen = self.lengthCapability - 4) log.debug("unknown Capability type : %s"%hex(self.capabilitySetType.value)) #read entire packet - return String(readLen = self.lengthCapability - 4) + return Buffer(readLen =self.lengthCapability - 4) if capability is None: capability = FactoryType(CapabilityFactory) @@ -309,7 +309,7 @@ class OrderCapability(CompositeType): def __init__(self, readLen = None): CompositeType.__init__(self, readLen = readLen) - self.terminalDescriptor = String("\x00" * 16, readLen = CallableValue(16)) + self.terminalDescriptor = Buffer("\x00" * 16, readLen = CallableValue(16)) self.pad4octetsA = UInt32Le(0) self.desktopSaveXGranularity = UInt16Le(1) self.desktopSaveYGranularity = UInt16Le(20) @@ -389,7 +389,7 @@ class InputCapability(CompositeType): #same value as gcc.ClientCoreSettings.keyboardFnKeys self.keyboardFunctionKey = UInt32Le() #same value as gcc.ClientCoreSettingrrs.imeFileName - self.imeFileName = String("\x00" * 64, readLen = CallableValue(64)) + self.imeFileName = Buffer("\x00" * 64, readLen = CallableValue(64)) class BrushCapability(CompositeType): """ diff --git a/rdpy/core/pdu/data.py b/rdpy/core/pdu/data.py index 4fba42d..fb7e831 100644 --- a/rdpy/core/pdu/data.py +++ b/rdpy/core/pdu/data.py @@ -22,7 +22,7 @@ Implement the main graphic layer In this layer are managed all mains bitmap update orders end user inputs """ -from rdpy.model.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType +from rdpy.model.type import CompositeType, CallableValue, Buffer, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType from rdpy.model.error import InvalidExpectedDataException import rdpy.model.log as log from rdpy.core.pdu import caps, order @@ -481,7 +481,7 @@ class PDU(CompositeType): return c(readLen = CallableValue(self.shareControlHeader.totalLength.value - sizeof(self.shareControlHeader))) log.debug("unknown PDU type : %s"%hex(self.shareControlHeader.pduType.value)) #read entire packet - return String(readLen = CallableValue(self.shareControlHeader.totalLength.value - sizeof(self.shareControlHeader))) + return Buffer(readLen = CallableValue(self.shareControlHeader.totalLength.value - sizeof(self.shareControlHeader))) if pduMessage is None: pduMessage = FactoryType(PDUMessageFactory) @@ -503,7 +503,7 @@ class DemandActivePDU(CompositeType): self.shareId = UInt32Le() self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) self.lengthCombinedCapabilities = UInt16Le(lambda:(sizeof(self.numberCapabilities) + sizeof(self.pad2Octets) + sizeof(self.capabilitySets))) - self.sourceDescriptor = String("rdpy", readLen = self.lengthSourceDescriptor) + self.sourceDescriptor = Buffer("rdpy", readLen = self.lengthSourceDescriptor) self.numberCapabilities = UInt16Le(lambda:len(self.capabilitySets._array)) self.pad2Octets = UInt16Le() self.capabilitySets = ArrayType(caps.Capability, readLen = self.numberCapabilities) @@ -523,7 +523,7 @@ class ConfirmActivePDU(CompositeType): self.originatorId = UInt16Le(0x03EA, constant = True) self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) self.lengthCombinedCapabilities = UInt16Le(lambda:(sizeof(self.numberCapabilities) + sizeof(self.pad2Octets) + sizeof(self.capabilitySets))) - self.sourceDescriptor = String("rdpy", readLen = self.lengthSourceDescriptor) + self.sourceDescriptor = Buffer("rdpy", readLen = self.lengthSourceDescriptor) self.numberCapabilities = UInt16Le(lambda:len(self.capabilitySets._array)) self.pad2Octets = UInt16Le() self.capabilitySets = ArrayType(caps.Capability, readLen = self.numberCapabilities) @@ -542,7 +542,7 @@ class DeactiveAllPDU(CompositeType): CompositeType.__init__(self, optional = True, readLen = readLen) self.shareId = UInt32Le() self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) - self.sourceDescriptor = String("rdpy", readLen = self.lengthSourceDescriptor) + self.sourceDescriptor = Buffer("rdpy", readLen = self.lengthSourceDescriptor) class DataPDU(CompositeType): """ @@ -563,7 +563,7 @@ class DataPDU(CompositeType): if self.shareDataHeader.pduType2.value == c._PDUTYPE2_: return c(readLen = CallableValue(readLen.value - sizeof(self.shareDataHeader))) log.debug("unknown PDU data type : %s"%hex(self.shareDataHeader.pduType2.value)) - return String(readLen = CallableValue(readLen.value - sizeof(self.shareDataHeader))) + return Buffer(readLen = CallableValue(readLen.value - sizeof(self.shareDataHeader))) if pduData is None: pduData = FactoryType(PDUDataFactory) @@ -780,7 +780,7 @@ class UpdateDataPDU(CompositeType): if self.updateType.value == c._UPDATE_TYPE_: return c(readLen = CallableValue(readLen.value - 2)) log.debug("unknown PDU update data type : %s"%hex(self.updateType.value)) - return String(readLen = CallableValue(readLen.value - 2)) + return Buffer(readLen = CallableValue(readLen.value - 2)) if updateData is None: updateData = FactoryType(UpdateDataFactory, conditional = lambda:(self.updateType.value != UpdateType.UPDATETYPE_SYNCHRONIZE)) @@ -799,7 +799,7 @@ class SaveSessionInfoPDU(CompositeType): CompositeType.__init__(self, readLen = readLen) self.infoType = UInt32Le() #TODO parse info data - self.infoData = String() + self.infoData = Buffer() class FastPathUpdatePDU(CompositeType): """ @@ -820,7 +820,7 @@ class FastPathUpdatePDU(CompositeType): if (self.updateHeader.value & 0xf) == c._FASTPATH_UPDATE_TYPE_: return c(readLen = self.size) log.debug("unknown Fast Path PDU update data type : %s"%hex(self.updateHeader.value & 0xf)) - return String(readLen = self.size) + return Buffer(readLen = self.size) if updateData is None: updateData = FactoryType(UpdateDataFactory) @@ -902,7 +902,7 @@ class BitmapData(CompositeType): self.flags = UInt16Le() self.bitmapLength = UInt16Le(lambda:(sizeof(self.bitmapComprHdr) + sizeof(self.bitmapDataStream))) self.bitmapComprHdr = BitmapCompressedDataHeader(bodySize = lambda:sizeof(self.bitmapDataStream), scanWidth = lambda:self.width.value, uncompressedSize = lambda:(self.width.value * self.height.value * self.bitsPerPixel.value), conditional = lambda:((self.flags.value & BitmapFlag.BITMAP_COMPRESSION) and not (self.flags.value & BitmapFlag.NO_BITMAP_COMPRESSION_HDR))) - self.bitmapDataStream = String(bitmapDataStream, readLen = CallableValue(lambda:(self.bitmapLength.value if (not self.flags.value & BitmapFlag.BITMAP_COMPRESSION or self.flags.value & BitmapFlag.NO_BITMAP_COMPRESSION_HDR) else self.bitmapComprHdr.cbCompMainBodySize.value))) + self.bitmapDataStream = Buffer(bitmapDataStream, readLen = CallableValue(lambda:(self.bitmapLength.value if (not self.flags.value & BitmapFlag.BITMAP_COMPRESSION or self.flags.value & BitmapFlag.NO_BITMAP_COMPRESSION_HDR) else self.bitmapComprHdr.cbCompMainBodySize.value))) class FastPathBitmapUpdateDataPDU(CompositeType): """ diff --git a/rdpy/core/pdu/order.py b/rdpy/core/pdu/order.py index bd829bf..2158401 100644 --- a/rdpy/core/pdu/order.py +++ b/rdpy/core/pdu/order.py @@ -23,7 +23,7 @@ GDI order structure from rdpy.model import log from rdpy.model.error import InvalidExpectedDataException -from rdpy.model.type import CompositeType, UInt8, String, FactoryType, SInt8, SInt16Le +from rdpy.model.type import CompositeType, UInt8, Buffer, FactoryType, SInt8, SInt16Le class ControlFlag(object): """ @@ -100,7 +100,7 @@ class PrimaryDrawingOrder(CompositeType): return c(self.controlFlags) log.debug("unknown Order type : %s"%hex(self.orderType.value)) #read entire packet - return String() + return Buffer() if order is None: order = FactoryType(OrderFactory) diff --git a/rdpy/core/sec.py b/rdpy/core/sec.py index 1a924cb..1035824 100644 --- a/rdpy/core/sec.py +++ b/rdpy/core/sec.py @@ -25,7 +25,7 @@ from hashlib import sha1 as sha from hashlib import md5 from rdpy.core import tpkt, lic from rdpy.core.t125 import gcc, mcs -from rdpy.model.type import CompositeType, CallableValue, Stream, UInt32Le, UInt16Le, String, sizeof, UInt8 +from rdpy.model.type import CompositeType, CallableValue, Stream, UInt32Le, UInt16Le, Buffer, sizeof, UInt8 from rdpy.model.layer import LayerAutomata, IStreamSender from rdpy.model.error import InvalidExpectedDataException from rdpy.model import log @@ -310,8 +310,8 @@ class ClientSecurityExchangePDU(CompositeType): def __init__(self): CompositeType.__init__(self) self.length = UInt32Le(lambda:(sizeof(self) - 4)) - self.encryptedClientRandom = String(readLen = CallableValue(lambda:(self.length.value - 8))) - self.padding = String("\x00" * 8, readLen = CallableValue(8)) + self.encryptedClientRandom = Buffer(readLen = CallableValue(lambda:(self.length.value - 8))) + self.padding = Buffer("\x00" * 8, readLen = CallableValue(8)) class RDPInfo(CompositeType): """ @@ -331,13 +331,13 @@ class RDPInfo(CompositeType): self.cbAlternateShell = UInt16Le(lambda:sizeof(self.alternateShell) - 2) self.cbWorkingDir = UInt16Le(lambda:sizeof(self.workingDir) - 2) #microsoft domain - self.domain = String(readLen = CallableValue(lambda:self.cbDomain.value + 2), unicode = True) - self.userName = String(readLen = CallableValue(lambda:self.cbUserName.value + 2), unicode = True) - self.password = String(readLen = CallableValue(lambda:self.cbPassword.value + 2), unicode = True) + self.domain = Buffer(readLen = CallableValue(lambda: self.cbDomain.value + 2), unicode = True) + self.userName = Buffer(readLen = CallableValue(lambda: self.cbUserName.value + 2), unicode = True) + self.password = Buffer(readLen = CallableValue(lambda: self.cbPassword.value + 2), unicode = True) #shell execute at start of session - self.alternateShell = String(readLen = CallableValue(lambda:self.cbAlternateShell.value + 2), unicode = True) + self.alternateShell = Buffer(readLen = CallableValue(lambda: self.cbAlternateShell.value + 2), unicode = True) #working directory for session - self.workingDir = String(readLen = CallableValue(lambda:self.cbWorkingDir.value + 2), unicode = True) + self.workingDir = Buffer(readLen = CallableValue(lambda: self.cbWorkingDir.value + 2), unicode = True) self.extendedInfo = RDPExtendedInfo(conditional = extendedInfoConditional) class RDPExtendedInfo(CompositeType): @@ -348,11 +348,11 @@ class RDPExtendedInfo(CompositeType): CompositeType.__init__(self, conditional = conditional) self.clientAddressFamily = UInt16Le(AfInet.AF_INET) self.cbClientAddress = UInt16Le(lambda:sizeof(self.clientAddress)) - self.clientAddress = String(readLen = self.cbClientAddress, unicode = True) + self.clientAddress = Buffer(readLen = self.cbClientAddress, unicode = True) self.cbClientDir = UInt16Le(lambda:sizeof(self.clientDir)) - self.clientDir = String(readLen = self.cbClientDir, unicode = True) + self.clientDir = Buffer(readLen = self.cbClientDir, unicode = True) #TODO make tiomezone - self.clientTimeZone = String("\x00" * 172) + self.clientTimeZone = Buffer("\x00" * 172) self.clientSessionId = UInt32Le() self.performanceFlags = UInt32Le() @@ -410,8 +410,8 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP self._decryptRc4 = rc4.RC4Key(self._currentDecrytKey) self._nbDecryptedPacket = 0 - signature = String(readLen = CallableValue(8)) - encryptedPayload = String() + signature = Buffer(readLen = CallableValue(8)) + encryptedPayload = Buffer() s.read_type((signature, encryptedPayload)) decrypted = rc4.crypt(self._decryptRc4, encryptedPayload.value) @@ -447,9 +447,9 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP s.write_type(data) if saltedMacGeneration: - return (String(macSaltedData(self._macKey, s.getvalue(), self._nbEncryptedPacket - 1)[:8]), String(rc4.crypt(self._encryptRc4, s.getvalue()))) + return (Buffer(macSaltedData(self._macKey, s.getvalue(), self._nbEncryptedPacket - 1)[:8]), Buffer(rc4.crypt(self._encryptRc4, s.getvalue()))) else: - return (String(macData(self._macKey, s.getvalue())[:8]), String(rc4.crypt(self._encryptRc4, s.getvalue()))) + return (Buffer(macData(self._macKey, s.getvalue())[:8]), Buffer(rc4.crypt(self._encryptRc4, s.getvalue()))) def recv(self, data): """ diff --git a/rdpy/core/t125/ber.py b/rdpy/core/t125/ber.py index a69969a..709eb51 100644 --- a/rdpy/core/t125/ber.py +++ b/rdpy/core/t125/ber.py @@ -22,7 +22,7 @@ Basic Encoding Rules use in RDP. ASN.1 standard """ -from rdpy.model.type import UInt8, UInt16Be, UInt32Be, String +from rdpy.model.type import UInt8, UInt16Be, UInt32Be, Buffer from rdpy.model.error import InvalidExpectedDataException, InvalidSize class BerPc(object): @@ -235,7 +235,7 @@ def writeOctetstring(value): @param value: string @return: BER octet string block """ - return (writeUniversalTag(Tag.BER_TAG_OCTET_STRING, False), writeLength(len(value)), String(value)) + return (writeUniversalTag(Tag.BER_TAG_OCTET_STRING, False), writeLength(len(value)), Buffer(value)) def readEnumerated(s): """ diff --git a/rdpy/core/t125/gcc.py b/rdpy/core/t125/gcc.py index 8eb88cb..82508ee 100644 --- a/rdpy/core/t125/gcc.py +++ b/rdpy/core/t125/gcc.py @@ -23,7 +23,7 @@ http://msdn.microsoft.com/en-us/library/cc240508.aspx """ from hashlib import md5 -from rdpy.model.type import UInt8, UInt16Le, UInt32Le, CompositeType, CallableValue, String, Stream, sizeof, FactoryType, ArrayType +from rdpy.model.type import UInt8, UInt16Le, UInt32Le, CompositeType, CallableValue, Buffer, Stream, sizeof, FactoryType, ArrayType from rdpy.core.t125 import per, mcs from rdpy.model.error import InvalidExpectedDataException from rdpy.model import log @@ -227,7 +227,7 @@ class DataBlock(CompositeType): return c(readLen = self.length - 4) log.debug("unknown GCC block type : %s"%hex(self.type.value)) #read entire packet - return String(readLen = self.length - 4) + return Buffer(readLen =self.length - 4) if dataBlock is None: dataBlock = FactoryType(DataBlockFactory) @@ -252,18 +252,18 @@ class ClientCoreData(CompositeType): self.sasSequence = UInt16Le(Sequence.RNS_UD_SAS_DEL) self.kbdLayout = UInt32Le(KeyboardLayout.US) self.clientBuild = UInt32Le(3790) - self.clientName = String("rdpy" + "\x00"*11, readLen = CallableValue(32), unicode = True) + self.clientName = Buffer("rdpy" + "\x00" * 11, readLen = CallableValue(32), unicode = True) self.keyboardType = UInt32Le(KeyboardType.IBM_101_102_KEYS) self.keyboardSubType = UInt32Le(0) self.keyboardFnKeys = UInt32Le(12) - self.imeFileName = String("\x00"*64, readLen = CallableValue(64), optional = True) + self.imeFileName = Buffer("\x00" * 64, readLen = CallableValue(64), optional = True) self.postBeta2ColorDepth = UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP, optional = True) self.clientProductId = UInt16Le(1, optional = True) self.serialNumber = UInt32Le(0, optional = True) self.highColorDepth = UInt16Le(HighColor.HIGH_COLOR_24BPP, optional = True) self.supportedColorDepths = UInt16Le(Support.RNS_UD_15BPP_SUPPORT | Support.RNS_UD_16BPP_SUPPORT | Support.RNS_UD_24BPP_SUPPORT | Support.RNS_UD_32BPP_SUPPORT, optional = True) self.earlyCapabilityFlags = UInt16Le(CapabilityFlags.RNS_UD_CS_SUPPORT_ERRINFO_PDU, optional = True) - self.clientDigProductId = String("\x00"*64, readLen = CallableValue(64), optional = True) + self.clientDigProductId = Buffer("\x00" * 64, readLen = CallableValue(64), optional = True) self.connectionType = UInt8(optional = True) self.pad1octet = UInt8(optional = True) self.serverSelectedProtocol = UInt32Le(optional = True) @@ -306,7 +306,7 @@ class ServerSecurityData(CompositeType): self.encryptionLevel = UInt32Le() self.serverRandomLen = UInt32Le(0x00000020, constant = True, conditional = lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel == 0)) self.serverCertLen = UInt32Le(lambda:sizeof(self.serverCertificate), conditional = lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel == 0)) - self.serverRandom = String(readLen = self.serverRandomLen, conditional = lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel == 0)) + self.serverRandom = Buffer(readLen = self.serverRandomLen, conditional = lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel == 0)) self.serverCertificate = ServerCertificate(readLen = self.serverCertLen, conditional = lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel == 0)) class ServerCertificate(CompositeType): @@ -355,8 +355,8 @@ class ProprietaryServerCertificate(CompositeType): self.PublicKeyBlob = RSAPublicKey(readLen = self.wPublicKeyBlobLen) self.wSignatureBlobType = UInt16Le(0x0008, constant = True) self.wSignatureBlobLen = UInt16Le(lambda:(sizeof(self.SignatureBlob) + sizeof(self.padding))) - self.SignatureBlob = String(readLen = CallableValue(lambda:(self.wSignatureBlobLen.value - sizeof(self.padding)))) - self.padding = String(b"\x00" * 8, readLen = CallableValue(8)) + self.SignatureBlob = Buffer(readLen = CallableValue(lambda:(self.wSignatureBlobLen.value - sizeof(self.padding)))) + self.padding = Buffer(b"\x00" * 8, readLen = CallableValue(8)) def getPublicKey(self): """ @@ -405,7 +405,7 @@ class CertBlob(CompositeType): def __init__(self): CompositeType.__init__(self) self.cbCert = UInt32Le(lambda:sizeof(self.abCert)) - self.abCert = String(readLen = self.cbCert) + self.abCert = Buffer(readLen = self.cbCert) class X509CertificateChain(CompositeType): """ @@ -418,7 +418,7 @@ class X509CertificateChain(CompositeType): CompositeType.__init__(self) self.NumCertBlobs = UInt32Le() self.CertBlobArray = ArrayType(CertBlob, readLen = self.NumCertBlobs) - self.padding = String(readLen = CallableValue(lambda:(8 + 4 * self.NumCertBlobs.value))) + self.padding = Buffer(readLen = CallableValue(lambda:(8 + 4 * self.NumCertBlobs.value))) def getPublicKey(self): """ @@ -447,8 +447,8 @@ class RSAPublicKey(CompositeType): self.bitlen = UInt32Le(lambda:((self.keylen.value - 8) * 8)) self.datalen = UInt32Le(lambda:((self.bitlen.value / 8) - 1)) self.pubExp = UInt32Le() - self.modulus = String(readLen = CallableValue(lambda:(self.keylen.value - 8))) - self.padding = String("\x00" * 8, readLen = CallableValue(8)) + self.modulus = Buffer(readLen = CallableValue(lambda:(self.keylen.value - 8))) + self.padding = Buffer("\x00" * 8, readLen = CallableValue(8)) class ChannelDef(CompositeType): """ @@ -458,7 +458,7 @@ class ChannelDef(CompositeType): def __init__(self, name = "", options = 0): CompositeType.__init__(self) #name of channel - self.name = String(name[0:8] + "\x00" * (8 - len(name)), readLen = CallableValue(8)) + self.name = Buffer(name[0:8] + "\x00" * (8 - len(name)), readLen = CallableValue(8)) #unknown self.options = UInt32Le() diff --git a/rdpy/core/t125/mcs.py b/rdpy/core/t125/mcs.py index 4c4a4e3..61e33dd 100644 --- a/rdpy/core/t125/mcs.py +++ b/rdpy/core/t125/mcs.py @@ -25,7 +25,7 @@ The main channel is the graphical channel. It exist channel for file system order, audio channel, clipboard etc... """ from rdpy.model.layer import LayerAutomata, IStreamSender, Layer -from rdpy.model.type import sizeof, Stream, UInt8, UInt16Le, String +from rdpy.model.message import sizeof, Stream, UInt8, UInt16Le, Buffer from rdpy.model.error import InvalidExpectedDataException, InvalidValue, InvalidSize, CallPureVirtualFuntion from rdpy.core.t125.ber import writeLength import rdpy.model.log as log @@ -182,7 +182,7 @@ class MCSLayer(LayerAutomata): @summary: Send disconnect provider ultimatum """ self._transport.send((UInt8(self.writeMCSPDUHeader(DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM, 1)), - per.writeEnumerates(0x80), String("\x00" * 6))) + per.writeEnumerates(0x80), Buffer("\x00" * 6))) self._transport.close() def allChannelConnected(self): diff --git a/rdpy/core/t125/per.py b/rdpy/core/t125/per.py index f762908..f629a4f 100644 --- a/rdpy/core/t125/per.py +++ b/rdpy/core/t125/per.py @@ -21,7 +21,7 @@ Per encoded function """ -from rdpy.model.type import UInt8, UInt16Be, UInt32Be, String +from rdpy.model.message import UInt8, UInt16Be, UInt32Be, Buffer from rdpy.model.error import InvalidValue, InvalidExpectedDataException def readLength(s): @@ -264,7 +264,7 @@ def writePadding(length): @param length: length of padding @return: String with \x00 * length """ - return String("\x00"*length) + return Buffer("\x00" * length) def readOctetStream(s, octetStream, minValue = 0): """ diff --git a/rdpy/core/tpkt.py b/rdpy/core/tpkt.py index bdc493d..19d5ecf 100644 --- a/rdpy/core/tpkt.py +++ b/rdpy/core/tpkt.py @@ -25,13 +25,12 @@ Use to build correct size packet and handle slow path and fast path mode import asyncio import ssl -from rdpy.core.nla import cssp, ntlm +from rdpy.core.nla import cssp, sspi from rdpy.model.layer import RawLayer -from rdpy.model.type import UInt8, UInt16Be, sizeof, Stream -from rdpy.model.error import CallPureVirtualFuntion +from rdpy.model.message import UInt8, UInt16Be, sizeof, Stream -class Action(object): +class Action: """ @see: http://msdn.microsoft.com/en-us/library/cc240621.aspx @see: http://msdn.microsoft.com/en-us/library/cc240589.aspx @@ -40,7 +39,7 @@ class Action(object): FASTPATH_ACTION_X224 = 0x3 -class SecFlags(object): +class SecFlags: """ @see: http://msdn.microsoft.com/en-us/library/cc240621.aspx """ @@ -163,13 +162,18 @@ class Tpkt: ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) ssl_ctx.check_hostname = False ssl_ctx.verify_mode = ssl.VerifyMode.CERT_NONE + reader, writer = await asyncio.open_connection(sock=self.writer.transport._sock, ssl=ssl_ctx, server_hostname="") return Tpkt(reader, writer) - async def start_nla(self): + async def start_nla(self, authentication_protocol: sspi.IAuthenticationProtocol): """ use to start NLA (NTLM over SSL) protocol must be called after startTLS function + + :ivar authentication_protocol: Authentication protocol use by CSSP to authenticate user + and transfert credentials """ tpkt = await self.start_tls() - await cssp.connect(tpkt.reader, tpkt.writer, ntlm.NTLMv2("", "sylvain", "sylvain")) + await cssp.connect(tpkt.reader, tpkt.writer, authentication_protocol) + return tpkt \ No newline at end of file diff --git a/rdpy/core/x224.py b/rdpy/core/x224.py index 5e3ecba..54f5849 100644 --- a/rdpy/core/x224.py +++ b/rdpy/core/x224.py @@ -24,13 +24,14 @@ This layer have main goal to negociate SSL transport RDP basic security is supported only on client side """ from rdpy.core import tpkt +from rdpy.core.nla import sspi from rdpy.model import log -from rdpy.model.layer import LayerAutomata, IStreamSender -from rdpy.model.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof, String +from rdpy.model.message import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof, Buffer from rdpy.model.error import InvalidExpectedDataException, RDPSecurityNegoFail -class MessageType(object): + +class MessageType: """ @summary: Message type """ @@ -40,7 +41,8 @@ class MessageType(object): X224_TPDU_DATA = 0xF0 X224_TPDU_ERROR = 0x70 -class NegociationType(object): + +class NegociationType: """ @summary: Negotiation header """ @@ -48,7 +50,8 @@ class NegociationType(object): TYPE_RDP_NEG_RSP = 0x02 TYPE_RDP_NEG_FAILURE = 0x03 -class Protocols(object): + +class Protocols: """ @summary: Protocols available for x224 layer @see: https://msdn.microsoft.com/en-us/library/cc240500.aspx @@ -57,8 +60,9 @@ class Protocols(object): PROTOCOL_SSL = 0x00000001 PROTOCOL_HYBRID = 0x00000002 PROTOCOL_HYBRID_EX = 0x00000008 - -class NegotiationFailureCode(object): + + +class NegotiationFailureCode: """ @summary: Protocol negotiation failure code """ @@ -70,23 +74,23 @@ class NegotiationFailureCode(object): SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006 -class ClientConnectionRequestPDU(CompositeType): +class ConnectionRequestPDU(CompositeType): """ - @summary: Connection request - client -> server - @see: http://msdn.microsoft.com/en-us/library/cc240470.aspx + Connection Request PDU + Use to send protocol security level available for the client + :see: http://msdn.microsoft.com/en-us/library/cc240470.aspx """ def __init__(self): CompositeType.__init__(self) self.len = UInt8(lambda:sizeof(self) - 1) - self.code = UInt8(MessageType.X224_TPDU_CONNECTION_REQUEST, constant = True) + self.code = UInt8(MessageType.X224_TPDU_CONNECTION_REQUEST, constant=True) self.padding = (UInt16Be(), UInt16Be(), UInt8()) - self.cookie = String(until = "\x0d\x0a", conditional = lambda:(self.len._is_readed and self.len.value > 14)) - #read if there is enough data + self.cookie = Buffer(until=b"\x0d\x0a", conditional=lambda: (self.len._is_readed and self.len.value > 14)) + # read if there is enough data self.protocolNeg = Negotiation(optional = True) -class ServerConnectionConfirm(CompositeType): +class ConnectionConfirmPDU(CompositeType): """ @summary: Server response @see: http://msdn.microsoft.com/en-us/library/cc240506.aspx @@ -159,55 +163,38 @@ class X224: await self.tpkt.write((X224DataHeader(), message)) -async def connect(tpkt: tpkt.Tpkt) -> X224: +async def connect(tpkt: tpkt.Tpkt, authentication_protocol: sspi.IAuthenticationProtocol) -> X224: """ - @summary: Write connection request message - Next state is recvConnectionConfirm - @see: http://msdn.microsoft.com/en-us/library/cc240500.aspx + Negotiate the security level and generate a X224 configured layer + + :ivar tpkt: this is the tpkt layer use to negotiate the security level + :ivar authentication_protocol: Authentication protocol is used by NLA authentication + Actually only NTLMv2 is available + + :see: http://msdn.microsoft.com/en-us/library/cc240500.aspx """ - message = ClientConnectionRequestPDU() - message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_REQ - message.protocolNeg.selectedProtocol.value = Protocols.PROTOCOL_HYBRID | Protocols.PROTOCOL_SSL - await tpkt.write(message) - selected_protocol = await read_connection_confirm(await tpkt.read()) + request = ConnectionRequestPDU() + request.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_REQ + request.protocolNeg.selectedProtocol.value = Protocols.PROTOCOL_HYBRID | Protocols.PROTOCOL_SSL + await tpkt.write(request) + + respond = (await tpkt.read()).read_type(ConnectionConfirmPDU()) + if respond.protocolNeg.failureCode._is_readed: + raise RDPSecurityNegoFail("negotiation failure code %x"%respond.protocolNeg.failureCode.value) + + selected_protocol = Protocols.PROTOCOL_RDP + if respond.protocolNeg._is_readed: + selected_protocol = respond.protocolNeg.selectedProtocol.value + if selected_protocol in [Protocols.PROTOCOL_HYBRID_EX]: raise InvalidExpectedDataException("RDPY doesn't support PROTOCOL_HYBRID_EX security Layer") - if selected_protocol == Protocols.PROTOCOL_RDP: - log.warning("*" * 43) - log.warning("*" + " " * 10 + "RDP Security selected" + " " * 10 + "*") - log.warning("*" * 43) + if selected_protocol == Protocols.PROTOCOL_RDP: return X224(tpkt) elif selected_protocol == Protocols.PROTOCOL_SSL: - log.info("*" * 43) - log.info("*" + " " * 10 + "SSL Security selected" + " " * 10 + "*") - log.info("*" * 43) return X224(await tpkt.start_tls()) elif selected_protocol == Protocols.PROTOCOL_HYBRID: - log.info("*" * 43) - log.info("*" + " " * 10 + "NLA Security selected" + " " * 10 + "*") - log.info("*" * 43) - return X224(await tpkt.start_nla()) - - -async def read_connection_confirm(data) -> int: - """ - Read connection confirm and return the negotiated protocol - :ivar data: Stream that contain connection confirm - :see: response -> https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/b2975bdc-6d56-49ee-9c57-f2ff3a0b6817 - :see: failure -> https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/1b3920e7-0116-4345-bc45-f2c4ad012761 - """ - message = ServerConnectionConfirm() - data.read_type(message) - - if message.protocolNeg.failureCode._is_readed: - raise RDPSecurityNegoFail("negotiation failure code %x"%message.protocolNeg.failureCode.value) - - # check presence of negotiation response - if message.protocolNeg._is_readed: - return message.protocolNeg.selectedProtocol.value - else: - return Protocols.PROTOCOL_RDP + return X224(await tpkt.start_nla(authentication_protocol)) class Server(X224): @@ -240,7 +227,7 @@ class Server(X224): @param data: {Stream} @see : http://msdn.microsoft.com/en-us/library/cc240470.aspx """ - message = ClientConnectionRequestPDU() + message = ConnectionRequestPDU() data.read_type(message) if not message.protocolNeg._is_readed: @@ -258,7 +245,7 @@ class Server(X224): if not self._selectedProtocol & Protocols.PROTOCOL_SSL and self._forceSSL: log.warning("server reject client because doesn't support SSL") #send error message and quit - message = ServerConnectionConfirm() + message = ConnectionConfirmPDU() message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_FAILURE message.protocolNeg.failureCode.value = NegotiationFailureCode.SSL_REQUIRED_BY_SERVER self._transport.send(message) @@ -274,7 +261,7 @@ class Server(X224): Next state is recvData @see : http://msdn.microsoft.com/en-us/library/cc240501.aspx """ - message = ServerConnectionConfirm() + message = ConnectionConfirmPDU() message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_RSP message.protocolNeg.selectedProtocol.value = self._selectedProtocol self._transport.send(message) diff --git a/rdpy/model/type.py b/rdpy/model/message.py similarity index 80% rename from rdpy/model/type.py rename to rdpy/model/message.py index 0a7f435..f94cd71 100644 --- a/rdpy/model/type.py +++ b/rdpy/model/message.py @@ -43,23 +43,18 @@ def sizeof(element): for i in element: size += sizeof(i) return size - elif isinstance(element, Type) and element._conditional(): + elif isinstance(element, Message) and element._conditional(): return element.__sizeof__() - return 0 + return 0 -class Type: +class Message: """ @summary: Root type object inheritance Record conditional optional of constant mechanism """ - def __init__(self, conditional=lambda:True, optional=False, constant=False): + def __init__(self, conditional=lambda: True, optional=False, constant=False): """ - @param conditional : Callable object - Read and Write operation depend on return of this function - @param optional: If there is no enough byte in current stream - And optional is True, read type is ignored - @param constant: Check if object value doesn't change after read operation """ self._conditional = conditional self._optional = optional @@ -70,7 +65,7 @@ class Type: self._is_readed = False # use to know if type was written self._is_writed = False - + def write(self, s): """ @summary: Check conditional callback @@ -81,7 +76,7 @@ class Type: if not self._is_writed: return self.__write__(s) - + def read(self, s): """ @summary: Check conditional callback @@ -93,12 +88,12 @@ class Type: self._is_readed = self._conditional() if not self._is_readed: return - + # not constant mode direct reading if not self._constant: self.__read__(s) return - + # constant mode old = deepcopy(self) self.__read__(s) @@ -107,21 +102,21 @@ class Type: # rollback read value s.seek(-sizeof(self), 1) raise InvalidExpectedDataException("%s const value expected %s != %s"%(self.__class__, old.value, self.value)) - + def __read__(self, s): """ @summary: Interface definition of private read function @param s: Stream """ raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "__read__", "Type")) - + def __write__(self, s): """ @summary: Interface definition of private write function @param s: Stream """ raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "__write__", "Type")) - + def __sizeof__(self): """ @summary: Return size of type use for sizeof function @@ -130,22 +125,22 @@ class Type: raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "__sizeof__", "Type")) -class CallableValue: +class DynMessage(Message): """ - @summary: Expression evaluate when is get or set - Ex: Type contain length of array and array - To know the size of array you need to read - length field before. At ctor time no length was read. - You need a callable object that will be evaluate when it will be used + Expression evaluate when is get or set + Ex: Type contain length of array and array + To know the size of array you need to read + length field before. At ctor time no length was read. + You need a callable object that will be evaluate when it will be used """ - def __init__(self, value): + def __init__(self, **kwargs): """ @param value: value will be wrapped (raw python type | lambda | function) """ + super().__init__(**kwargs) self._value = None - self.value = value - - def __getValue__(self): + + def get_value(self): """ @summary: Call when value is get -> Evaluate inner expression Can be overwritten to add specific check before @@ -153,8 +148,8 @@ class CallableValue: @return: value expression evaluated """ return self._value() - - def __setValue__(self, value): + + def set_value(self, value): """ @summary: Call when value is set Can be overwritten to add specific check before @@ -164,27 +159,13 @@ class CallableValue: value_callable = lambda:value if callable(value): value_callable = value - + self._value = value_callable - - @property - def value(self): - """ - @summary: Evaluate callable expression - @return: result of callable value - """ - return self.__getValue__() - - @value.setter - def value(self, value): - """ - @summary: Setter of value - @param value: new value encompass in value type object - """ - self.__setValue__(value) + + value = property(get_value, set_value) -class SimpleType(Type, CallableValue): +class SimpleType(DynMessage): """ @summary: Non composite type leaf in type tree @@ -202,47 +183,12 @@ class SimpleType(Type, CallableValue): And optional is True, read type is ignored @param constant: Check if object value doesn't change after read operation """ + super().__init__(conditional=conditional, optional=optional, constant=constant) self._signed = signed self._typeSize = typeSize self._structFormat = structFormat - Type.__init__(self, conditional = conditional, optional = optional, constant = constant) - CallableValue.__init__(self, value) - - def __getValue__(self): - """ - @summary: Check value if match range of type - And apply sign - Ex: UInt8 can be > 255 - @return: Python value wrap into type - @raise InvalidValue: if value doesn't respect type range - @see: CallableValue.__getValue__ - """ - value = CallableValue.__getValue__(self) - - #check value now because it can be an callable value - #and evaluate a this time - - if not self.isInRange(value): - raise InvalidValue("value is out of range for %s"%self.__class__) - if self._signed: - return value - else: - return value & self.mask() + self.value = value - def __setValue__(self, value): - """ - @summary: Check if new value respect type declaration - Ex: UInt8 can be > 256 - @param value: new value (raw python type | lambda | function) - @raise InvalidValue: if value doesn't respect type range - @see: CallableValue.__setValue__ - """ - #check static value range - if not callable(value) and not self.isInRange(value): - raise InvalidValue("value is out of range for %s"%self.__class__) - - CallableValue.__setValue__(self, value) - def __write__(self, s): """ @summary: Write value in stream @@ -251,7 +197,7 @@ class SimpleType(Type, CallableValue): @param s: Stream that will be written """ s.write(struct.pack(self._structFormat, self.value)) - + def __read__(self, s): """ @summary: Read inner value from stream @@ -262,39 +208,17 @@ class SimpleType(Type, CallableValue): """ if s.data_len() < self._typeSize: raise InvalidSize("Stream is too small to read expected SimpleType") - self.value = struct.unpack(self._structFormat, s.read(self._typeSize))[0] - - def mask(self): - """ - @summary: Compute bit mask for type - Because in Python all numbers are Int long or float - Cache result in self._mask field - """ - if "_mask" not in self.__dict__.keys(): - mask = 0xff - for _ in range(1, self._typeSize): - mask = mask << 8 | 0xff - self._mask = mask - return self._mask - - def isInRange(self, value): - """ - @summary: Check if value is in range represented by mask - @param value: Python value - @return: true if value is in type range - """ - if self._signed: - return not (value < -(self.mask() >> 1) or value > (self.mask() >> 1)) - else: - return not (value < 0 or value > self.mask()) - + value = struct.unpack(self._structFormat, s.read(self._typeSize))[0] + + self.value = value + def __sizeof__(self): """ @summary: Return size of type in bytes @return: typeSize pass in constructor """ return self._typeSize - + def __eq__(self, other): """ @summary: Compare two simple type @@ -318,7 +242,7 @@ class SimpleType(Type, CallableValue): if not isinstance(other, SimpleType): other = self.__class__(other) return self.value.__ne__(other.value) - + def __invert__(self): """ @summary: Implement not operator @@ -328,7 +252,7 @@ class SimpleType(Type, CallableValue): if not self._signed: invert &= self.mask() return self.__class__(invert) - + def __add__(self, other): """ @summary: Implement addition operator @@ -340,7 +264,7 @@ class SimpleType(Type, CallableValue): if not isinstance(other, SimpleType): other = self.__class__(other) return self.__class__(self.value.__add__(other.value)) - + def __sub__(self, other): """ @summary: Implement sub operator @@ -352,7 +276,7 @@ class SimpleType(Type, CallableValue): if not isinstance(other, SimpleType): other = self.__class__(other) return self.__class__(self.value.__sub__(other.value)) - + def __and__(self, other): """ @summary: Implement bitwise and operator @@ -364,7 +288,7 @@ class SimpleType(Type, CallableValue): if not isinstance(other, SimpleType): other = self.__class__(other) return self.__class__(self.value.__and__(other.value)) - + def __or__(self, other): """ @summary: Implement bitwise or operator @@ -376,7 +300,7 @@ class SimpleType(Type, CallableValue): if not isinstance(other, SimpleType): other = self.__class__(other) return self.__class__(self.value.__or__(other.value)) - + def __xor__(self, other): """ @summary: Implement bitwise xor operator @@ -388,7 +312,7 @@ class SimpleType(Type, CallableValue): if not isinstance(other, SimpleType): other = self.__class__(other) return self.__class__(self.value.__xor__(other.value)) - + def __lshift__(self, other): """ @summary: Left shift operator @@ -400,7 +324,7 @@ class SimpleType(Type, CallableValue): if not isinstance(other, SimpleType): other = self.__class__(other) return self.__class__(self.value.__lshift__(other.value)) - + def __rshift__(self, other): """ @summary: Right shift operator @@ -412,14 +336,14 @@ class SimpleType(Type, CallableValue): if not isinstance(other, SimpleType): other = self.__class__(other) return self.__class__(self.value.__rshift__(other.value)) - + def __hash__(self): """ @summary: Hash function to handle simple type in hash collection @return: hash of inner value """ return hash(self.value) - + def __nonzero__(self): """ @summary: Boolean conversion @@ -427,14 +351,14 @@ class SimpleType(Type, CallableValue): """ return bool(self.value) - -class CompositeType(Type): + +class CompositeType(Message): """ @summary: Type node in Type tree Track type field declared in __init__ function Ex: self.lengthOfPacket = UInt16Le() -> record lengthOfPacket as sub type of node """ - def __init__(self, conditional = lambda:True, optional = False, constant = False, readLen = None): + def __init__(self, read_len = None, conditional = lambda:True, optional = False, constant = False, ): """ @param conditional : Callable object Read and Write operation depend on return of this function @@ -444,11 +368,12 @@ class CompositeType(Type): @param readLen: Max length in bytes can be readed from stream Use to check length information """ - Type.__init__(self, conditional = conditional, optional = optional, constant = constant) - #list of ordoned type + super().__init__(conditional=conditional, optional=optional, constant=constant) + + # list of ordoned type self._typeName = [] - self._readLen = readLen - + self._read_len = read_len + def __setattr__(self, name, value): """ @summary: Track Type field @@ -457,10 +382,10 @@ class CompositeType(Type): @param name: name of new attribute @param value: value of new attribute """ - if name[0] != '_' and (isinstance(value, Type) or isinstance(value, tuple)) and not name in self._typeName: + if name[0] != '_' and (isinstance(value, Message) or isinstance(value, tuple)) and not name in self._typeName: self._typeName.append(name) self.__dict__[name] = value - + def __read__(self, s): """ @summary: Read composite type @@ -471,18 +396,18 @@ class CompositeType(Type): @raise InvalidSize: if stream is greater than readLen parameter """ readLen = 0 - for name in self._typeName: + for name in self._typeName: try: s.read_type(self.__dict__[name]) readLen += sizeof(self.__dict__[name]) - #read is ok but read out of bound - if not self._readLen is None and readLen > self._readLen.value: - #roll back + # read is ok but read out of bound + if not self._read_len is None and readLen > self._read_len.value: + # roll back s.pos -= sizeof(self.__dict__[name]) - #and notify if not optional + # and notify if not optional if not self.__dict__[name]._optional: raise InvalidSize("Impossible to read type %s : read length is too small"%(self.__class__)) - + except Exception as e: log.error("Error during read %s::%s"%(self.__class__, name)) #roll back already read @@ -491,11 +416,11 @@ class CompositeType(Type): break s.seek(-sizeof(self.__dict__[tmpName]), 1) raise e - - if not self._readLen is None and readLen < self._readLen.value: - log.debug("Still have correct data in packet %s, read %s bytes as padding"%(self.__class__, self._readLen.value - readLen)) - s.read(self._readLen.value - readLen) - + + if not self._read_len is None and readLen < self._read_len.value: + log.debug("Still have correct data in packet %s, read %s bytes as padding"%(self.__class__, self._read_len.value - readLen)) + s.read(self._read_len.value - readLen) + def __write__(self, s): """ @summary: Write all sub-type handle by __setattr__ function @@ -508,15 +433,15 @@ class CompositeType(Type): except Exception as e: log.error("Error during write %s::%s"%(self.__class__, name)) raise e - + def __sizeof__(self): """ @summary: Call sizeof on each sub type @return: sum of sizeof of each Type attributes """ - if self._is_readed and not self._readLen is None: - return self._readLen.value - + if self._is_readed and not self._read_len is None: + return self._read_len.value + size = 0 for name in self._typeName: size += sizeof(self.__dict__[name]) @@ -535,7 +460,7 @@ class CompositeType(Type): if self.__dict__[name] != other.__dict__[name]: return False return True - + def __ne__(self, other): """ @summary: return not equal result operator @@ -551,7 +476,7 @@ All simple Raw type use in RDPY class UInt8(SimpleType): """ @summary: unsigned byte - """ + """ def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False): """ @param value: python value wrap @@ -566,7 +491,7 @@ class UInt8(SimpleType): class SInt8(SimpleType): """ @summary: signed byte - """ + """ def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False): """ @param value: python value wrap @@ -577,8 +502,8 @@ class SInt8(SimpleType): @param constant: Check if object value doesn't change after read operation """ SimpleType.__init__(self, "b", 1, True, value, conditional = conditional, optional = optional, constant = constant) - - + + class UInt16Be(SimpleType): """ @summary: unsigned short @@ -594,7 +519,7 @@ class UInt16Be(SimpleType): @param constant: Check if object value doesn't change after read operation """ SimpleType.__init__(self, ">H", 2, False, value, conditional = conditional, optional = optional, constant = constant) - + class UInt16Le(SimpleType): """ @summary: unsigned short @@ -610,7 +535,7 @@ class UInt16Le(SimpleType): @param constant: Check if object value doesn't change after read operation """ SimpleType.__init__(self, "I", 4, False, value, conditional = conditional, optional = optional, constant = constant) - + class UInt32Le(SimpleType): """ @summary: unsigned int @@ -658,7 +583,7 @@ class UInt32Le(SimpleType): @param constant: Check if object value doesn't change after read operation """ SimpleType.__init__(self, "I", 4, True, value, conditional = conditional, optional = optional, constant = constant) - + class UInt24Be(SimpleType): """ @summary: unsigned 24 bit integer @@ -706,21 +631,22 @@ class UInt24Be(SimpleType): @param constant: Check if object value doesn't change after read operation """ SimpleType.__init__(self, ">I", 3, False, value, conditional = conditional, optional = optional, constant = constant) - + def __write__(self, s): """ @summary: special write for a special type @param s: Stream """ s.write(struct.pack(">I", self.value)[1:]) - + def __read__(self, s): """ @summary: special read for a special type @param s: Stream """ self.value = struct.unpack(self._structFormat, '\x00' + s.read(self._typeSize))[0] - + + class UInt24Le(SimpleType): """ @summary: unsigned 24 bit integer @@ -735,99 +661,71 @@ class UInt24Le(SimpleType): And optional is True, read type is ignored @param constant: Check if object value doesn't change after read operation """ - SimpleType.__init__(self, " int: """ Compute already read size :returns: read size of stream """ return self.seek() - - def read_type(self, value: Type): + + def read_type(self, value: Message): """ Call specific read on type object or iterate over tuple elements @@ -910,14 +803,15 @@ class Stream(BytesIO): break self.pos -= sizeof(tmpElement) raise e - return - + return value + # optional value not present if self.data_len() == 0 and value._optional: return value.read(self) - + return value + def readNextType(self, t): """ @summary: read next type but didn't consume it @@ -925,8 +819,8 @@ class Stream(BytesIO): """ self.read_type(t) self.pos -= sizeof(t) - - def write_type(self, value: Type): + + def write_type(self, value: Message): """ Call specific write on type object or iterate over tuple element @@ -937,11 +831,12 @@ class Stream(BytesIO): if isinstance(value, tuple) or isinstance(value, list): for element in value: self.write_type(element) - return + return self value.write(self) + return self -class ArrayType(Type): +class ArrayType(Message): """ @summary: Factory af n element """ @@ -956,13 +851,13 @@ class ArrayType(Type): And optional is True, read type is ignored @param constant: Check if object value doesn't change after read operation """ - Type.__init__(self, conditional, optional, constant) + Message.__init__(self, conditional, optional, constant) self._typeFactory = typeFactory self._readLen = readLen self._array = [] if not init is None: self._array = init - + def __read__(self, s): """ @summary: Create readLen new object and read it @@ -979,28 +874,28 @@ class ArrayType(Type): break self._array.append(element) i += 1 - + def __write__(self, s): """ @summary: Just write array @param s: Stream """ s.write_type(self._array) - + def __getitem__(self, item): """ @summary: Magic function to be FactoryType as transparent as possible @return: index of _value """ return self._array.__getitem__(item) - + def __sizeof__(self): """ @summary: Size in bytes of all inner type """ return sizeof(self._array) - -class FactoryType(Type): + +class FactoryType(Message): """ @summary: Call a factory callback at read or write time Wrapp attribute access to inner type @@ -1014,13 +909,13 @@ class FactoryType(Type): And optional is True, read type is ignored @param constant: Check if object value doesn't change after read operation """ - Type.__init__(self, conditional, optional, constant) + Message.__init__(self, conditional, optional, constant) self._factory = factory if not callable(factory): self._factory = lambda:factory self._value = None - + def __read__(self, s): """ @summary: Call factory and write it @@ -1028,7 +923,7 @@ class FactoryType(Type): """ self._value = self._factory() s.read_type(self._value) - + def __write__(self, s): """ @summary: Call factory and read it @@ -1036,21 +931,21 @@ class FactoryType(Type): """ self._value = self._factory() s.write_type(self._value) - + def __getattr__(self, name): """ @summary: Magic function to be FactoryType as transparent as possible @return: _value parameter """ return self._value.__getattribute__(name) - + def __getitem__(self, item): """ @summary: Magic function to be FactoryType as transparent as possible @return: index of _value """ return self._value.__getitem__(item) - + def __sizeof__(self): """ @summary: Size of of object returned by factory diff --git a/rdpy/model/rss.py b/rdpy/model/rss.py index ff7c2c8..9135afc 100644 --- a/rdpy/model/rss.py +++ b/rdpy/model/rss.py @@ -22,7 +22,7 @@ Remote Session Scenario File format Private protocol format to save events """ -from rdpy.model.type import CompositeType, FactoryType, UInt8, UInt16Le, UInt32Le, String, sizeof, Stream +from rdpy.model.type import CompositeType, FactoryType, UInt8, UInt16Le, UInt32Le, Buffer, sizeof, Stream from rdpy.model import log, error import time @@ -63,7 +63,7 @@ class Event(CompositeType): return c(readLen = self.length) log.debug("unknown event type : %s"%hex(self.type.value)) #read entire packet - return String(readLen = self.length) + return Buffer(readLen = self.length) if event is None: event = FactoryType(EventFactory) @@ -88,7 +88,7 @@ class UpdateEvent(CompositeType): self.bpp = UInt8() self.format = UInt8() self.length = UInt32Le(lambda:sizeof(self.data)) - self.data = String(readLen = self.length) + self.data = Buffer(readLen = self.length) class InfoEvent(CompositeType): """ @@ -98,13 +98,13 @@ class InfoEvent(CompositeType): def __init__(self, readLen = None): CompositeType.__init__(self, readLen = readLen) self.lenUsername = UInt16Le(lambda:sizeof(self.username)) - self.username = String(readLen = self.lenUsername) + self.username = Buffer(readLen = self.lenUsername) self.lenPassword = UInt16Le(lambda:sizeof(self.password)) - self.password = String(readLen = self.lenPassword) + self.password = Buffer(readLen = self.lenPassword) self.lenDomain = UInt16Le(lambda:sizeof(self.domain)) - self.domain = String(readLen = self.lenDomain) + self.domain = Buffer(readLen = self.lenDomain) self.lenHostname = UInt16Le(lambda:sizeof(self.hostname)) - self.hostname = String(readLen = self.lenHostname) + self.hostname = Buffer(readLen = self.lenHostname) class ScreenEvent(CompositeType): """ diff --git a/rdpy/security/rc4.py b/rdpy/security/rc4.py index 5802cb1..3830a3e 100644 --- a/rdpy/security/rc4.py +++ b/rdpy/security/rc4.py @@ -24,7 +24,7 @@ def KSA(key): keylength = len(key) - S = range(256) + S = list(range(256)) j = 0 for i in range(256): @@ -50,8 +50,10 @@ def RC4(key): S = KSA(key) return PRGA(S) -def RC4Key(key): - return RC4([ord(c) for c in key]) -def crypt(keystream, plaintext): - return "".join([chr(ord(c) ^ keystream.next()) for c in plaintext]) \ No newline at end of file +def RC4Key(key): + return RC4(key) + + +def crypt(keystream, plaintext: bytes) -> bytes: + return bytes([c ^ next(keystream) for c in plaintext]) diff --git a/test/test_protocol_rdp_x224.py b/test/test_protocol_rdp_x224.py index a60de79..3d4ab16 100644 --- a/test/test_protocol_rdp_x224.py +++ b/test/test_protocol_rdp_x224.py @@ -91,7 +91,7 @@ class X224Test(unittest.TestCase): s = type.Stream() s.write_type(data) s.pos = 0 - t = x224.ClientConnectionRequestPDU() + t = x224.ConnectionRequestPDU() s.read_type(t) if t.protocolNeg.code != x224.NegociationType.TYPE_RDP_NEG_REQ: @@ -112,7 +112,7 @@ class X224Test(unittest.TestCase): @summary: unit test for X224Client.recvConnectionConfirm and sendConnectionRequest function check negotiation failure """ - message = x224.ServerConnectionConfirm() + message = x224.ConnectionConfirmPDU() message.protocolNeg.code.value = x224.NegociationType.TYPE_RDP_NEG_FAILURE s = type.Stream() s.write_type(message) @@ -141,7 +141,7 @@ class X224Test(unittest.TestCase): def recvData(data): raise X224Test.X224_PASS() - message = x224.ServerConnectionConfirm() + message = x224.ConnectionConfirmPDU() message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_SSL s = type.Stream() @@ -165,14 +165,14 @@ class X224Test(unittest.TestCase): class Transport(object): def send(self, data): - if not isinstance(data, x224.ServerConnectionConfirm): + if not isinstance(data, x224.ConnectionConfirmPDU): raise X224Test.X224_FAIL() if data.protocolNeg.code.value != x224.NegociationType.TYPE_RDP_NEG_FAILURE or data.protocolNeg.failureCode.value != x224.NegotiationFailureCode.SSL_REQUIRED_BY_SERVER: raise X224Test.X224_FAIL() def close(self): raise X224Test.X224_PASS() - message = x224.ClientConnectionRequestPDU() + message = x224.ConnectionRequestPDU() message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_HYBRID s = type.Stream() s.write_type(message) @@ -204,7 +204,7 @@ class X224Test(unittest.TestCase): tls = True def send(self, data): - if not isinstance(data, x224.ServerConnectionConfirm): + if not isinstance(data, x224.ConnectionConfirmPDU): raise X224Test.X224_FAIL() if data.protocolNeg.code.value != x224.NegociationType.TYPE_RDP_NEG_RSP or data.protocolNeg.selectedProtocol.value != x224.Protocols.PROTOCOL_SSL: raise X224Test.X224_FAIL() @@ -214,7 +214,7 @@ class X224Test(unittest.TestCase): global connect_event connect_event = True - message = x224.ClientConnectionRequestPDU() + message = x224.ConnectionRequestPDU() message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_SSL | x224.Protocols.PROTOCOL_RDP s = type.Stream() s.write_type(message)