Update: refactor cssp code

This commit is contained in:
citronneur
2020-04-20 22:51:32 +02:00
parent 9cac72a8d2
commit 018c59fe42
18 changed files with 371 additions and 488 deletions

View File

@@ -25,7 +25,8 @@ import sys
import asyncio import asyncio
from rdpy.core import tpkt, x224 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__': if __name__ == '__main__':
@@ -35,9 +36,9 @@ if __name__ == '__main__':
reader, writer = await asyncio.open_connection( reader, writer = await asyncio.open_connection(
'127.0.0.1', 33389) '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 x224_layer.write(UInt8(8))
await asyncio.sleep(1000) await asyncio.sleep(10)
print("foooooooooooooooooooo") print("foooooooooooooooooooo")
asyncio.run(tcp_echo_client('Hello World!')) asyncio.run(tcp_echo_client('Hello World!'))

View File

@@ -22,7 +22,7 @@
@see: http://msdn.microsoft.com/en-us/library/cc241880.aspx @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 from rdpy.model.error import InvalidExpectedDataException
import rdpy.model.log as log import rdpy.model.log as log
from rdpy.core import sec from rdpy.core import sec
@@ -102,7 +102,7 @@ class LicenseBinaryBlob(CompositeType):
CompositeType.__init__(self, optional = optional) CompositeType.__init__(self, optional = optional)
self.wBlobType = UInt16Le(blobType, constant = True if blobType != BinaryBlobType.BB_ANY_BLOB else False) self.wBlobType = UInt16Le(blobType, constant = True if blobType != BinaryBlobType.BB_ANY_BLOB else False)
self.wBlobLen = UInt16Le(lambda:sizeof(self.blobData)) self.wBlobLen = UInt16Le(lambda:sizeof(self.blobData))
self.blobData = String(readLen = self.wBlobLen) self.blobData = Buffer(readLen = self.wBlobLen)
class LicensingErrorMessage(CompositeType): class LicensingErrorMessage(CompositeType):
""" """
@@ -127,10 +127,10 @@ class ProductInformation(CompositeType):
self.dwVersion = UInt32Le() self.dwVersion = UInt32Le()
self.cbCompanyName = UInt32Le(lambda:sizeof(self.pbCompanyName)) self.cbCompanyName = UInt32Le(lambda:sizeof(self.pbCompanyName))
#may contain "Microsoft Corporation" from server microsoft #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)) self.cbProductId = UInt32Le(lambda:sizeof(self.pbProductId))
#may contain "A02" from microsoft license server #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): class Scope(CompositeType):
@@ -162,7 +162,7 @@ class ServerLicenseRequest(CompositeType):
def __init__(self, readLen = None): def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen) 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.productInfo = ProductInformation()
self.keyExchangeList = LicenseBinaryBlob(BinaryBlobType.BB_KEY_EXCHG_ALG_BLOB) self.keyExchangeList = LicenseBinaryBlob(BinaryBlobType.BB_KEY_EXCHG_ALG_BLOB)
self.serverCertificate = LicenseBinaryBlob(BinaryBlobType.BB_CERTIFICATE_BLOB) self.serverCertificate = LicenseBinaryBlob(BinaryBlobType.BB_CERTIFICATE_BLOB)
@@ -183,7 +183,7 @@ class ClientNewLicenseRequest(CompositeType):
#pure microsoft client ;-) #pure microsoft client ;-)
#http://msdn.microsoft.com/en-us/library/1040af38-c733-4fb3-acd1-8db8cc979eda#id10 #http://msdn.microsoft.com/en-us/library/1040af38-c733-4fb3-acd1-8db8cc979eda#id10
self.platformId = UInt32Le(0x04000000 | 0x00010000) 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.encryptedPreMasterSecret = LicenseBinaryBlob(BinaryBlobType.BB_RANDOM_BLOB)
self.ClientUserName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_USER_NAME_BLOB) self.ClientUserName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_USER_NAME_BLOB)
self.ClientMachineName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_MACHINE_NAME_BLOB) self.ClientMachineName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_MACHINE_NAME_BLOB)
@@ -199,7 +199,7 @@ class ServerPlatformChallenge(CompositeType):
CompositeType.__init__(self, readLen = readLen) CompositeType.__init__(self, readLen = readLen)
self.connectFlags = UInt32Le() self.connectFlags = UInt32Le()
self.encryptedPlatformChallenge = LicenseBinaryBlob(BinaryBlobType.BB_ANY_BLOB) self.encryptedPlatformChallenge = LicenseBinaryBlob(BinaryBlobType.BB_ANY_BLOB)
self.MACData = String(readLen = CallableValue(16)) self.MACData = Buffer(readLen = CallableValue(16))
class ClientPLatformChallengeResponse(CompositeType): class ClientPLatformChallengeResponse(CompositeType):
""" """
@@ -212,7 +212,7 @@ class ClientPLatformChallengeResponse(CompositeType):
CompositeType.__init__(self, readLen = readLen) CompositeType.__init__(self, readLen = readLen)
self.encryptedPlatformChallengeResponse = LicenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB) self.encryptedPlatformChallengeResponse = LicenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB)
self.encryptedHWID = 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): class LicPacket(CompositeType):
""" """
@@ -234,7 +234,7 @@ class LicPacket(CompositeType):
if self.bMsgtype.value == c._MESSAGE_TYPE_: if self.bMsgtype.value == c._MESSAGE_TYPE_:
return c(readLen = self.wMsgSize - 4) return c(readLen = self.wMsgSize - 4)
log.debug("unknown license message : %s"%self.bMsgtype.value) 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: if message is None:
message = FactoryType(LicensingMessageFactory) message = FactoryType(LicensingMessageFactory)
@@ -340,7 +340,7 @@ class LicenseManager(object):
#generate hwid #generate hwid
s = Stream() 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] hwid = s.getvalue()[:20]
message = ClientPLatformChallengeResponse() message = ClientPLatformChallengeResponse()

View File

@@ -25,18 +25,19 @@
from pyasn1.type import namedtype, univ, tag from pyasn1.type import namedtype, univ, tag
import pyasn1.codec.der.encoder as der_encoder import pyasn1.codec.der.encoder as der_encoder
import pyasn1.codec.der.decoder as der_decoder import pyasn1.codec.der.decoder as der_decoder
import pyasn1.codec.ber.encoder as ber_encoder
from rdpy.core.nla import sspi from rdpy.core.nla import sspi
from rdpy.model.type import Stream from rdpy.model.message import Stream
from rdpy.security import x509
from rdpy.model import error from rdpy.model import error
from rdpy.security.x509 import X509Certificate
class NegoToken(univ.Sequence): class NegoToken(univ.Sequence):
componentType = namedtype.NamedTypes( componentType = namedtype.NamedTypes(
namedtype.NamedType('negoToken', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))), namedtype.NamedType('negoToken', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
) )
class NegoData(univ.SequenceOf): class NegoData(univ.SequenceOf):
""" """
@summary: contain spnego ntlm of kerberos data @summary: contain spnego ntlm of kerberos data
@@ -44,6 +45,7 @@ class NegoData(univ.SequenceOf):
""" """
componentType = NegoToken() componentType = NegoToken()
class TSRequest(univ.Sequence): class TSRequest(univ.Sequence):
""" """
@summary: main structure @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))) namedtype.OptionalNamedType('errorCode', univ.Integer().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4)))
) )
class TSCredentials(univ.Sequence): class TSCredentials(univ.Sequence):
""" """
@summary: contain user information @summary: contain user information
@@ -67,6 +70,7 @@ class TSCredentials(univ.Sequence):
namedtype.NamedType('credentials', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))) namedtype.NamedType('credentials', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
) )
class TSPasswordCreds(univ.Sequence): class TSPasswordCreds(univ.Sequence):
""" """
@summary: contain username and password @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))) namedtype.NamedType('password', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)))
) )
class TSCspDataDetail(univ.Sequence): class TSCspDataDetail(univ.Sequence):
""" """
@summary: smart card credentials @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))) namedtype.OptionalNamedType('cspName', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4)))
) )
class TSSmartCardCreds(univ.Sequence): class TSSmartCardCreds(univ.Sequence):
""" """
@summary: smart card credentials @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))) 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): def encode_der_trequest(nego_types=[], auth_info=None, pub_key_auth=None):
@@ -162,68 +158,49 @@ def getNegoTokens(tRequest):
negoData = tRequest.getComponentByName("negoTokens") negoData = tRequest.getComponentByName("negoTokens")
return [Stream(negoData.getComponentByPosition(i).getComponentByPosition(0).asOctets()) for i in range(len(negoData))] 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 = TSPasswordCreds()
passwordCred.setComponentByName("domainName", univ.OctetString(domain).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))) passwordCred.setComponentByName("domainName", domain)
passwordCred.setComponentByName("userName", univ.OctetString(username).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))) passwordCred.setComponentByName("userName", username)
passwordCred.setComponentByName("password", univ.OctetString(password).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))) passwordCred.setComponentByName("password", password)
credentials = TSCredentials() credentials = TSCredentials()
credentials.setComponentByName("credType", univ.Integer(1).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))) credentials.setComponentByName("credType", 1)
credentials.setComponentByName("credentials", univ.OctetString(der_encoder.encode(passwordCred)).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))) credentials.setComponentByName("credentials", der_encoder.encode(passwordCred))
return der_encoder.encode(credentials) return der_encoder.encode(credentials)
async def connect(reader, writer, authentication_protocol: sspi.IAuthenticationProtocol): async def connect(reader, writer, authentication_protocol: sspi.IAuthenticationProtocol):
""" """
CSSP connection sequence
""" """
# send negotiate message # send negotiate message
writer.write(encode_der_trequest(nego_types=[authentication_protocol.getNegotiateMessage()])) writer.write(encode_der_trequest(nego_types=[authentication_protocol.getNegotiateMessage()]))
await writer.drain() await writer.drain()
print("toto")
trequest = decode_der_trequest(await reader.read(1500)) trequest = decode_der_trequest(await reader.read(1500))
print("yahoo")
message, interface = authentication_protocol.getAuthenticateMessage(getNegoTokens(trequest)[0]) message, interface = authentication_protocol.getAuthenticateMessage(getNegoTokens(trequest)[0])
def recvChallenge(self, data): # get binary certificate
""" # There is no other way to get certificate that have net been validated
@summary: second state in cssp automata peer_certificate = writer.transport._ssl_protocol._sslpipe.ssl_object._sslobj.getpeercert(True)
@param data : {str} all data available on buffer x509_certificate = der_decoder.decode(peer_certificate, asn1Spec=X509Certificate())[0]
""" public_key = x509_certificate.getComponentByName("tbsCertificate").getComponentByName("subjectPublicKeyInfo").getComponentByName("subjectPublicKey").asOctets()
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]
rsa = x509.RSAPublicKey() # send back public key encrypted with NTLM
rsa.setComponentByName("modulus", univ.Integer(pubKey.getComponentByName('modulus')._value)) writer.write(encode_der_trequest(nego_types=[message], pub_key_auth=interface.GSS_WrapEx(public_key)))
rsa.setComponentByName("publicExponent", univ.Integer(pubKey.getComponentByName('publicExponent')._value)) await writer.drain()
self._pubKeyBer = ber_encoder.encode(rsa)
#send authenticate message with public key encoded # now check the increment
self.transport.write(encode_der_trequest(nego_types= [message], pub_key_auth= self._interface.GSS_WrapEx(self._pubKeyBer))) # sever must respond with the same key incremented to one
#next step is received public key incremented by one trequest = decode_der_trequest(await reader.read(1500))
self.dataReceived = self.recvPubKeyInc public_key_inc = interface.GSS_UnWrapEx(trequest.getComponentByName("pubKeyAuth").asOctets())
def recvPubKeyInc(self, data): if int.from_bytes(public_key, "little") + 1 != int.from_bytes(public_key_inc, "little"):
"""
@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])):
raise error.InvalidExpectedDataException("CSSP : Invalid public key increment") raise error.InvalidExpectedDataException("CSSP : Invalid public key increment")
domain, user, password = self._authenticationProtocol.getEncodedCredentials() domain, user, password = authentication_protocol.getEncodedCredentials()
#send credentials writer.write(encode_der_trequest(auth_info=interface.GSS_WrapEx(encode_der_tcredentials(domain, user, password))))
self.transport.write(encode_der_trequest( await writer.drain()
auth_info= self._interface.GSS_WrapEx(encodeDERTCredentials(domain, user, password))))

View File

@@ -27,9 +27,10 @@ from rdpy.core.nla import sspi
import rdpy.security.pyDes as pyDes import rdpy.security.pyDes as pyDes
import rdpy.security.rc4 as rc4 import rdpy.security.rc4 as rc4
from rdpy.security.rsa_wrapper import random 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 from rdpy.model import filetimes, error
class MajorVersion(object): class MajorVersion(object):
""" """
@see: https://msdn.microsoft.com/en-us/library/cc236654.aspx @see: https://msdn.microsoft.com/en-us/library/cc236654.aspx
@@ -38,6 +39,7 @@ class MajorVersion(object):
WINDOWS_MAJOR_VERSION_5 = 0x05 WINDOWS_MAJOR_VERSION_5 = 0x05
WINDOWS_MAJOR_VERSION_6 = 0x06 WINDOWS_MAJOR_VERSION_6 = 0x06
class MinorVersion(object): class MinorVersion(object):
""" """
@see: https://msdn.microsoft.com/en-us/library/cc236654.aspx @see: https://msdn.microsoft.com/en-us/library/cc236654.aspx
@@ -48,12 +50,14 @@ class MinorVersion(object):
WINDOWS_MINOR_VERSION_2 = 0x02 WINDOWS_MINOR_VERSION_2 = 0x02
WINDOWS_MINOR_VERSION_3 = 0x03 WINDOWS_MINOR_VERSION_3 = 0x03
class NTLMRevision(object): class NTLMRevision(object):
""" """
@see: https://msdn.microsoft.com/en-us/library/cc236654.aspx @see: https://msdn.microsoft.com/en-us/library/cc236654.aspx
""" """
NTLMSSP_REVISION_W2K3 = 0x0F NTLMSSP_REVISION_W2K3 = 0x0F
class Negotiate(object): class Negotiate(object):
""" """
@see: https://msdn.microsoft.com/en-us/library/cc236650.aspx @see: https://msdn.microsoft.com/en-us/library/cc236650.aspx
@@ -80,6 +84,7 @@ class Negotiate(object):
NTLM_NEGOTIATE_OEM = 0x00000002 NTLM_NEGOTIATE_OEM = 0x00000002
NTLMSSP_NEGOTIATE_UNICODE = 0x00000001 NTLMSSP_NEGOTIATE_UNICODE = 0x00000001
class AvId(object): class AvId(object):
""" """
@see: https://msdn.microsoft.com/en-us/library/cc236646.aspx @see: https://msdn.microsoft.com/en-us/library/cc236646.aspx
@@ -124,8 +129,8 @@ class AvPair(CompositeType):
def __init__(self): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.AvId = UInt16Le() self.AvId = UInt16Le()
self.AvLen = UInt16Le(lambda:sizeof(self.Value)) self.AvLen = UInt16Le(lambda: sizeof(self.Value))
self.Value = String(readLen = self.AvLen) self.Value = Buffer(read_len=lambda: self.AvLen.value)
class MessageSignatureEx(CompositeType): class MessageSignatureEx(CompositeType):
""" """
@@ -135,7 +140,7 @@ class MessageSignatureEx(CompositeType):
def __init__(self): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.Version = UInt32Le(0x00000001, constant = True) self.Version = UInt32Le(0x00000001, constant = True)
self.Checksum = String(readLen = CallableValue(8)) self.Checksum = Buffer(read_len=lambda: 8)
self.SeqNum = UInt32Le() self.SeqNum = UInt32Le()
class NegotiateMessage(CompositeType): class NegotiateMessage(CompositeType):
@@ -144,9 +149,9 @@ class NegotiateMessage(CompositeType):
@see: https://msdn.microsoft.com/en-us/library/cc236641.aspx @see: https://msdn.microsoft.com/en-us/library/cc236641.aspx
""" """
def __init__(self): def __init__(self):
CompositeType.__init__(self) super().__init__()
self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True) self.Signature = Buffer(b"NTLMSSP\x00", read_len=lambda: 8, constant=True)
self.MessageType = UInt32Le(0x00000001, constant = True) self.MessageType = UInt32Le(0x00000001, constant=True)
self.NegotiateFlags = UInt32Le() self.NegotiateFlags = UInt32Le()
@@ -160,7 +165,7 @@ class NegotiateMessage(CompositeType):
self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION)) self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION))
self.Payload = String() self.Payload = Buffer()
class ChallengeMessage(CompositeType): class ChallengeMessage(CompositeType):
""" """
@@ -169,8 +174,8 @@ class ChallengeMessage(CompositeType):
""" """
def __init__(self): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True) self.Signature = Buffer(b"NTLMSSP\x00", read_len=lambda: 8, constant=True)
self.MessageType = UInt32Le(0x00000002, constant = True) self.MessageType = UInt32Le(0x00000002, constant=True)
self.TargetNameLen = UInt16Le() self.TargetNameLen = UInt16Le()
self.TargetNameMaxLen = UInt16Le(lambda:self.TargetNameLen.value) self.TargetNameMaxLen = UInt16Le(lambda:self.TargetNameLen.value)
@@ -178,15 +183,15 @@ class ChallengeMessage(CompositeType):
self.NegotiateFlags = UInt32Le() self.NegotiateFlags = UInt32Le()
self.ServerChallenge = String(readLen = CallableValue(8)) self.ServerChallenge = Buffer(read_len=lambda: 8)
self.Reserved = String("\x00" * 8, readLen = CallableValue(8)) self.Reserved = Buffer(b"\x00" * 8, read_len=lambda: 8)
self.TargetInfoLen = UInt16Le() self.TargetInfoLen = UInt16Le()
self.TargetInfoMaxLen = UInt16Le(lambda:self.TargetInfoLen.value) self.TargetInfoMaxLen = UInt16Le(lambda: self.TargetInfoLen.value)
self.TargetInfoBufferOffset = UInt32Le() self.TargetInfoBufferOffset = UInt32Le()
self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION)) self.Version = Version(conditional=lambda: (self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION))
self.Payload = String() self.Payload = Buffer()
def getTargetName(self): def getTargetName(self):
return getPayLoadField(self, self.TargetNameLen.value, self.TargetNameBufferOffset.value) return getPayLoadField(self, self.TargetNameLen.value, self.TargetNameBufferOffset.value)
@@ -216,8 +221,8 @@ class AuthenticateMessage(CompositeType):
""" """
def __init__(self): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True) self.Signature = Buffer(b"NTLMSSP\x00", read_len=lambda: 8, constant = True)
self.MessageType = UInt32Le(0x00000003, constant = True) self.MessageType = UInt32Le(0x00000003, constant=True)
self.LmChallengeResponseLen = UInt16Le() self.LmChallengeResponseLen = UInt16Le()
self.LmChallengeResponseMaxLen = UInt16Le(lambda:self.LmChallengeResponseLen.value) self.LmChallengeResponseMaxLen = UInt16Le(lambda:self.LmChallengeResponseLen.value)
@@ -246,8 +251,8 @@ class AuthenticateMessage(CompositeType):
self.NegotiateFlags = UInt32Le() self.NegotiateFlags = UInt32Le()
self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION)) self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION))
self.MIC = String("\x00" * 16, readLen = CallableValue(16)) self.MIC = Buffer(b"\x00" * 16, read_len=lambda: 16)
self.Payload = String() self.Payload = Buffer()
def getUserName(self): def getUserName(self):
return getPayLoadField(self, self.UserNameLen.value, self.UserNameBufferOffset.value) 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) return DES(key[0:7], data) + DES(key[7:14], data) + DES(key[14:16] + "\x00" * 5, data)
def UNICODE(s): def UNICODE(s):
""" """
@param s: source @param s: source
@@ -354,6 +360,7 @@ def UNICODE(s):
""" """
return s.encode('utf-16le') return s.encode('utf-16le')
def MD4(s): def MD4(s):
""" """
@summary: compute the md4 sum @summary: compute the md4 sum
@@ -362,6 +369,7 @@ def MD4(s):
""" """
return hashlib.new('md4', s).digest() return hashlib.new('md4', s).digest()
def MD5(s): def MD5(s):
""" """
@summary: compute the md5 sum @summary: compute the md5 sum
@@ -370,13 +378,15 @@ def MD5(s):
""" """
return hashlib.new('md5', s).digest() return hashlib.new('md5', s).digest()
def Z(m): def Z(m):
""" """
@summary: fill m zero in string @summary: fill m zero in string
@param m: {int} size of string @param m: {int} size of string
@return: \x00 * m @return: \x00 * m
""" """
return "\x00" * m return b"\x00" * m
def RC4K(key, plaintext): def RC4K(key, plaintext):
""" """
@@ -387,6 +397,7 @@ def RC4K(key, plaintext):
""" """
return rc4.crypt(rc4.RC4Key(key), plaintext) return rc4.crypt(rc4.RC4Key(key), plaintext)
def KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge): def KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge):
""" """
@summary: Key eXchange Key for NTLMv2 @summary: Key eXchange Key for NTLMv2
@@ -397,17 +408,20 @@ def KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge):
""" """
return SessionBaseKey return SessionBaseKey
def SEALKEY(ExportedSessionKey, client): def SEALKEY(ExportedSessionKey, client):
if 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: 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): def SIGNKEY(ExportedSessionKey, client):
if 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: 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): def HMAC_MD5(key, data):
""" """
@@ -417,6 +431,7 @@ def HMAC_MD5(key, data):
""" """
return hmac.new(key, data, hashlib.md5).digest() return hmac.new(key, data, hashlib.md5).digest()
def NTOWFv2(Passwd, User, UserDom): def NTOWFv2(Passwd, User, UserDom):
""" """
@summary: Version 2 of NTLM hash function @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)) return HMAC_MD5(MD4(UNICODE(Passwd)), UNICODE(User.upper() + UserDom))
def LMOWFv2(Passwd, User, UserDom): def LMOWFv2(Passwd, User, UserDom):
""" """
@summary: Same as NTOWFv2 @summary: Same as NTOWFv2
@@ -437,14 +453,15 @@ def LMOWFv2(Passwd, User, UserDom):
""" """
return NTOWFv2(Passwd, User, UserDom) return NTOWFv2(Passwd, User, UserDom)
def ComputeResponsev2(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChallenge, Time, ServerName): def ComputeResponsev2(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChallenge, Time, ServerName):
""" """
@summary: process NTLMv2 Authenticate hash @summary: process NTLMv2 Authenticate hash
@param NegFlg: {int} Negotiation flags come from challenge message @param NegFlg: {int} Negotiation flags come from challenge message
@see: https://msdn.microsoft.com/en-us/library/cc236700.aspx @see: https://msdn.microsoft.com/en-us/library/cc236700.aspx
""" """
Responserversion = "\x01" Responserversion = b"\x01"
HiResponserversion = "\x01" HiResponserversion = b"\x01"
temp = Responserversion + HiResponserversion + Z(6) + Time + ClientChallenge + Z(4) + ServerName temp = Responserversion + HiResponserversion + Z(6) + Time + ClientChallenge + Z(4) + ServerName
NTProofStr = HMAC_MD5(ResponseKeyNT, ServerChallenge + temp) NTProofStr = HMAC_MD5(ResponseKeyNT, ServerChallenge + temp)
@@ -455,6 +472,7 @@ def ComputeResponsev2(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChall
return NtChallengeResponse, LmChallengeResponse, SessionBaseKey return NtChallengeResponse, LmChallengeResponse, SessionBaseKey
def MAC(handle, SigningKey, SeqNum, Message): def MAC(handle, SigningKey, SeqNum, Message):
""" """
@summary: generate signature for application message @summary: generate signature for application message
@@ -475,6 +493,7 @@ def MAC(handle, SigningKey, SeqNum, Message):
return signature return signature
def MIC(ExportedSessionKey, negotiateMessage, challengeMessage, authenticateMessage): def MIC(ExportedSessionKey, negotiateMessage, challengeMessage, authenticateMessage):
""" """
@summary: Compute MIC signature @summary: Compute MIC signature
@@ -488,11 +507,12 @@ def MIC(ExportedSessionKey, negotiateMessage, challengeMessage, authenticateMess
s.write_type((negotiateMessage, challengeMessage, authenticateMessage)) s.write_type((negotiateMessage, challengeMessage, authenticateMessage))
return HMAC_MD5(ExportedSessionKey, s.getvalue()) return HMAC_MD5(ExportedSessionKey, s.getvalue())
class NTLMv2(sspi.IAuthenticationProtocol): class NTLMv2(sspi.IAuthenticationProtocol):
""" """
@summary: Handle NTLMv2 Authentication @summary: Handle NTLMv2 Authentication
""" """
def __init__(self, domain, user, password): def __init__(self, domain: str, user: str, password: str):
self._domain = domain self._domain = domain
self._user = user self._user = user
self._password = password self._password = password
@@ -538,7 +558,7 @@ class NTLMv2(sspi.IAuthenticationProtocol):
computeMIC = False computeMIC = False
ServerName = self._challengeMessage.getTargetInfo() ServerName = self._challengeMessage.getTargetInfo()
infos = self._challengeMessage.getTargetInfoAsAvPairArray() infos = self._challengeMessage.getTargetInfoAsAvPairArray()
if infos.has_key(AvId.MsvAvTimestamp): if AvId.MsvAvTimestamp in infos.keys():
Timestamp = infos[AvId.MsvAvTimestamp] Timestamp = infos[AvId.MsvAvTimestamp]
computeMIC = True computeMIC = True
else: else:
@@ -554,7 +574,7 @@ class NTLMv2(sspi.IAuthenticationProtocol):
if self._challengeMessage.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_UNICODE: if self._challengeMessage.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_UNICODE:
self._enableUnicode = True self._enableUnicode = True
domain, user = UNICODE(domain), UNICODE(user) 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: if computeMIC:
self._authenticateMessage.MIC.value = MIC(ExportedSessionKey, self._negotiateMessage, self._challengeMessage, self._authenticateMessage) 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 @summary: decrypt data with key exchange in Authentication protocol
@param data: {str} @param data: {str}
""" """
signature = MessageSignatureEx() signature, message = Stream(data).read_type((MessageSignatureEx(), Buffer()))
message = String()
s = Stream(data)
s.read_type((signature, message))
#decrypt message #decrypt message
plaintextMessage = rc4.crypt(self._decryptHandle, message.value) plaintextMessage = rc4.crypt(self._decryptHandle, message.value)
checksum = rc4.crypt(self._decryptHandle, signature.Checksum.value) checksum = rc4.crypt(self._decryptHandle, signature.Checksum.value)
#recompute checksum # recompute checksum
t = Stream() t = Stream()
t.write_type(signature.SeqNum) t.write_type(signature.SeqNum)
verify = HMAC_MD5(self._verifyKey, t.getvalue() + plaintextMessage)[:8] verify = HMAC_MD5(self._verifyKey, t.getvalue() + plaintextMessage)[:8]

View File

@@ -24,7 +24,7 @@ Definition of structure use for capabilities nego
Use in PDU layer 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): class CapsType(object):
@@ -241,7 +241,7 @@ class Capability(CompositeType):
return c(readLen = self.lengthCapability - 4) return c(readLen = self.lengthCapability - 4)
log.debug("unknown Capability type : %s"%hex(self.capabilitySetType.value)) log.debug("unknown Capability type : %s"%hex(self.capabilitySetType.value))
#read entire packet #read entire packet
return String(readLen = self.lengthCapability - 4) return Buffer(readLen =self.lengthCapability - 4)
if capability is None: if capability is None:
capability = FactoryType(CapabilityFactory) capability = FactoryType(CapabilityFactory)
@@ -309,7 +309,7 @@ class OrderCapability(CompositeType):
def __init__(self, readLen = None): def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen) 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.pad4octetsA = UInt32Le(0)
self.desktopSaveXGranularity = UInt16Le(1) self.desktopSaveXGranularity = UInt16Le(1)
self.desktopSaveYGranularity = UInt16Le(20) self.desktopSaveYGranularity = UInt16Le(20)
@@ -389,7 +389,7 @@ class InputCapability(CompositeType):
#same value as gcc.ClientCoreSettings.keyboardFnKeys #same value as gcc.ClientCoreSettings.keyboardFnKeys
self.keyboardFunctionKey = UInt32Le() self.keyboardFunctionKey = UInt32Le()
#same value as gcc.ClientCoreSettingrrs.imeFileName #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): class BrushCapability(CompositeType):
""" """

View File

@@ -22,7 +22,7 @@ Implement the main graphic layer
In this layer are managed all mains bitmap update orders end user inputs 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 from rdpy.model.error import InvalidExpectedDataException
import rdpy.model.log as log import rdpy.model.log as log
from rdpy.core.pdu import caps, order 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))) return c(readLen = CallableValue(self.shareControlHeader.totalLength.value - sizeof(self.shareControlHeader)))
log.debug("unknown PDU type : %s"%hex(self.shareControlHeader.pduType.value)) log.debug("unknown PDU type : %s"%hex(self.shareControlHeader.pduType.value))
#read entire packet #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: if pduMessage is None:
pduMessage = FactoryType(PDUMessageFactory) pduMessage = FactoryType(PDUMessageFactory)
@@ -503,7 +503,7 @@ class DemandActivePDU(CompositeType):
self.shareId = UInt32Le() self.shareId = UInt32Le()
self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor))
self.lengthCombinedCapabilities = UInt16Le(lambda:(sizeof(self.numberCapabilities) + sizeof(self.pad2Octets) + sizeof(self.capabilitySets))) 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.numberCapabilities = UInt16Le(lambda:len(self.capabilitySets._array))
self.pad2Octets = UInt16Le() self.pad2Octets = UInt16Le()
self.capabilitySets = ArrayType(caps.Capability, readLen = self.numberCapabilities) self.capabilitySets = ArrayType(caps.Capability, readLen = self.numberCapabilities)
@@ -523,7 +523,7 @@ class ConfirmActivePDU(CompositeType):
self.originatorId = UInt16Le(0x03EA, constant = True) self.originatorId = UInt16Le(0x03EA, constant = True)
self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor))
self.lengthCombinedCapabilities = UInt16Le(lambda:(sizeof(self.numberCapabilities) + sizeof(self.pad2Octets) + sizeof(self.capabilitySets))) 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.numberCapabilities = UInt16Le(lambda:len(self.capabilitySets._array))
self.pad2Octets = UInt16Le() self.pad2Octets = UInt16Le()
self.capabilitySets = ArrayType(caps.Capability, readLen = self.numberCapabilities) self.capabilitySets = ArrayType(caps.Capability, readLen = self.numberCapabilities)
@@ -542,7 +542,7 @@ class DeactiveAllPDU(CompositeType):
CompositeType.__init__(self, optional = True, readLen = readLen) CompositeType.__init__(self, optional = True, readLen = readLen)
self.shareId = UInt32Le() self.shareId = UInt32Le()
self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor))
self.sourceDescriptor = String("rdpy", readLen = self.lengthSourceDescriptor) self.sourceDescriptor = Buffer("rdpy", readLen = self.lengthSourceDescriptor)
class DataPDU(CompositeType): class DataPDU(CompositeType):
""" """
@@ -563,7 +563,7 @@ class DataPDU(CompositeType):
if self.shareDataHeader.pduType2.value == c._PDUTYPE2_: if self.shareDataHeader.pduType2.value == c._PDUTYPE2_:
return c(readLen = CallableValue(readLen.value - sizeof(self.shareDataHeader))) return c(readLen = CallableValue(readLen.value - sizeof(self.shareDataHeader)))
log.debug("unknown PDU data type : %s"%hex(self.shareDataHeader.pduType2.value)) 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: if pduData is None:
pduData = FactoryType(PDUDataFactory) pduData = FactoryType(PDUDataFactory)
@@ -780,7 +780,7 @@ class UpdateDataPDU(CompositeType):
if self.updateType.value == c._UPDATE_TYPE_: if self.updateType.value == c._UPDATE_TYPE_:
return c(readLen = CallableValue(readLen.value - 2)) return c(readLen = CallableValue(readLen.value - 2))
log.debug("unknown PDU update data type : %s"%hex(self.updateType.value)) 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: if updateData is None:
updateData = FactoryType(UpdateDataFactory, conditional = lambda:(self.updateType.value != UpdateType.UPDATETYPE_SYNCHRONIZE)) updateData = FactoryType(UpdateDataFactory, conditional = lambda:(self.updateType.value != UpdateType.UPDATETYPE_SYNCHRONIZE))
@@ -799,7 +799,7 @@ class SaveSessionInfoPDU(CompositeType):
CompositeType.__init__(self, readLen = readLen) CompositeType.__init__(self, readLen = readLen)
self.infoType = UInt32Le() self.infoType = UInt32Le()
#TODO parse info data #TODO parse info data
self.infoData = String() self.infoData = Buffer()
class FastPathUpdatePDU(CompositeType): class FastPathUpdatePDU(CompositeType):
""" """
@@ -820,7 +820,7 @@ class FastPathUpdatePDU(CompositeType):
if (self.updateHeader.value & 0xf) == c._FASTPATH_UPDATE_TYPE_: if (self.updateHeader.value & 0xf) == c._FASTPATH_UPDATE_TYPE_:
return c(readLen = self.size) return c(readLen = self.size)
log.debug("unknown Fast Path PDU update data type : %s"%hex(self.updateHeader.value & 0xf)) 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: if updateData is None:
updateData = FactoryType(UpdateDataFactory) updateData = FactoryType(UpdateDataFactory)
@@ -902,7 +902,7 @@ class BitmapData(CompositeType):
self.flags = UInt16Le() self.flags = UInt16Le()
self.bitmapLength = UInt16Le(lambda:(sizeof(self.bitmapComprHdr) + sizeof(self.bitmapDataStream))) 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.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): class FastPathBitmapUpdateDataPDU(CompositeType):
""" """

View File

@@ -23,7 +23,7 @@ GDI order structure
from rdpy.model import log from rdpy.model import log
from rdpy.model.error import InvalidExpectedDataException 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): class ControlFlag(object):
""" """
@@ -100,7 +100,7 @@ class PrimaryDrawingOrder(CompositeType):
return c(self.controlFlags) return c(self.controlFlags)
log.debug("unknown Order type : %s"%hex(self.orderType.value)) log.debug("unknown Order type : %s"%hex(self.orderType.value))
#read entire packet #read entire packet
return String() return Buffer()
if order is None: if order is None:
order = FactoryType(OrderFactory) order = FactoryType(OrderFactory)

View File

@@ -25,7 +25,7 @@ from hashlib import sha1 as sha
from hashlib import md5 from hashlib import md5
from rdpy.core import tpkt, lic from rdpy.core import tpkt, lic
from rdpy.core.t125 import gcc, mcs 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.layer import LayerAutomata, IStreamSender
from rdpy.model.error import InvalidExpectedDataException from rdpy.model.error import InvalidExpectedDataException
from rdpy.model import log from rdpy.model import log
@@ -310,8 +310,8 @@ class ClientSecurityExchangePDU(CompositeType):
def __init__(self): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.length = UInt32Le(lambda:(sizeof(self) - 4)) self.length = UInt32Le(lambda:(sizeof(self) - 4))
self.encryptedClientRandom = String(readLen = CallableValue(lambda:(self.length.value - 8))) self.encryptedClientRandom = Buffer(readLen = CallableValue(lambda:(self.length.value - 8)))
self.padding = String("\x00" * 8, readLen = CallableValue(8)) self.padding = Buffer("\x00" * 8, readLen = CallableValue(8))
class RDPInfo(CompositeType): class RDPInfo(CompositeType):
""" """
@@ -331,13 +331,13 @@ class RDPInfo(CompositeType):
self.cbAlternateShell = UInt16Le(lambda:sizeof(self.alternateShell) - 2) self.cbAlternateShell = UInt16Le(lambda:sizeof(self.alternateShell) - 2)
self.cbWorkingDir = UInt16Le(lambda:sizeof(self.workingDir) - 2) self.cbWorkingDir = UInt16Le(lambda:sizeof(self.workingDir) - 2)
#microsoft domain #microsoft domain
self.domain = String(readLen = CallableValue(lambda:self.cbDomain.value + 2), unicode = True) self.domain = Buffer(readLen = CallableValue(lambda: self.cbDomain.value + 2), unicode = True)
self.userName = String(readLen = CallableValue(lambda:self.cbUserName.value + 2), unicode = True) self.userName = Buffer(readLen = CallableValue(lambda: self.cbUserName.value + 2), unicode = True)
self.password = String(readLen = CallableValue(lambda:self.cbPassword.value + 2), unicode = True) self.password = Buffer(readLen = CallableValue(lambda: self.cbPassword.value + 2), unicode = True)
#shell execute at start of session #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 #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) self.extendedInfo = RDPExtendedInfo(conditional = extendedInfoConditional)
class RDPExtendedInfo(CompositeType): class RDPExtendedInfo(CompositeType):
@@ -348,11 +348,11 @@ class RDPExtendedInfo(CompositeType):
CompositeType.__init__(self, conditional = conditional) CompositeType.__init__(self, conditional = conditional)
self.clientAddressFamily = UInt16Le(AfInet.AF_INET) self.clientAddressFamily = UInt16Le(AfInet.AF_INET)
self.cbClientAddress = UInt16Le(lambda:sizeof(self.clientAddress)) 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.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 #TODO make tiomezone
self.clientTimeZone = String("\x00" * 172) self.clientTimeZone = Buffer("\x00" * 172)
self.clientSessionId = UInt32Le() self.clientSessionId = UInt32Le()
self.performanceFlags = UInt32Le() self.performanceFlags = UInt32Le()
@@ -410,8 +410,8 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
self._decryptRc4 = rc4.RC4Key(self._currentDecrytKey) self._decryptRc4 = rc4.RC4Key(self._currentDecrytKey)
self._nbDecryptedPacket = 0 self._nbDecryptedPacket = 0
signature = String(readLen = CallableValue(8)) signature = Buffer(readLen = CallableValue(8))
encryptedPayload = String() encryptedPayload = Buffer()
s.read_type((signature, encryptedPayload)) s.read_type((signature, encryptedPayload))
decrypted = rc4.crypt(self._decryptRc4, encryptedPayload.value) decrypted = rc4.crypt(self._decryptRc4, encryptedPayload.value)
@@ -447,9 +447,9 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
s.write_type(data) s.write_type(data)
if saltedMacGeneration: 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: 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): def recv(self, data):
""" """

View File

@@ -22,7 +22,7 @@ Basic Encoding Rules use in RDP.
ASN.1 standard 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 from rdpy.model.error import InvalidExpectedDataException, InvalidSize
class BerPc(object): class BerPc(object):
@@ -235,7 +235,7 @@ def writeOctetstring(value):
@param value: string @param value: string
@return: BER octet string block @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): def readEnumerated(s):
""" """

View File

@@ -23,7 +23,7 @@ http://msdn.microsoft.com/en-us/library/cc240508.aspx
""" """
from hashlib import md5 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.core.t125 import per, mcs
from rdpy.model.error import InvalidExpectedDataException from rdpy.model.error import InvalidExpectedDataException
from rdpy.model import log from rdpy.model import log
@@ -227,7 +227,7 @@ class DataBlock(CompositeType):
return c(readLen = self.length - 4) return c(readLen = self.length - 4)
log.debug("unknown GCC block type : %s"%hex(self.type.value)) log.debug("unknown GCC block type : %s"%hex(self.type.value))
#read entire packet #read entire packet
return String(readLen = self.length - 4) return Buffer(readLen =self.length - 4)
if dataBlock is None: if dataBlock is None:
dataBlock = FactoryType(DataBlockFactory) dataBlock = FactoryType(DataBlockFactory)
@@ -252,18 +252,18 @@ class ClientCoreData(CompositeType):
self.sasSequence = UInt16Le(Sequence.RNS_UD_SAS_DEL) self.sasSequence = UInt16Le(Sequence.RNS_UD_SAS_DEL)
self.kbdLayout = UInt32Le(KeyboardLayout.US) self.kbdLayout = UInt32Le(KeyboardLayout.US)
self.clientBuild = UInt32Le(3790) 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.keyboardType = UInt32Le(KeyboardType.IBM_101_102_KEYS)
self.keyboardSubType = UInt32Le(0) self.keyboardSubType = UInt32Le(0)
self.keyboardFnKeys = UInt32Le(12) 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.postBeta2ColorDepth = UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP, optional = True)
self.clientProductId = UInt16Le(1, optional = True) self.clientProductId = UInt16Le(1, optional = True)
self.serialNumber = UInt32Le(0, optional = True) self.serialNumber = UInt32Le(0, optional = True)
self.highColorDepth = UInt16Le(HighColor.HIGH_COLOR_24BPP, 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.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.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.connectionType = UInt8(optional = True)
self.pad1octet = UInt8(optional = True) self.pad1octet = UInt8(optional = True)
self.serverSelectedProtocol = UInt32Le(optional = True) self.serverSelectedProtocol = UInt32Le(optional = True)
@@ -306,7 +306,7 @@ class ServerSecurityData(CompositeType):
self.encryptionLevel = UInt32Le() self.encryptionLevel = UInt32Le()
self.serverRandomLen = UInt32Le(0x00000020, constant = True, conditional = lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel == 0)) 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.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)) self.serverCertificate = ServerCertificate(readLen = self.serverCertLen, conditional = lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel == 0))
class ServerCertificate(CompositeType): class ServerCertificate(CompositeType):
@@ -355,8 +355,8 @@ class ProprietaryServerCertificate(CompositeType):
self.PublicKeyBlob = RSAPublicKey(readLen = self.wPublicKeyBlobLen) self.PublicKeyBlob = RSAPublicKey(readLen = self.wPublicKeyBlobLen)
self.wSignatureBlobType = UInt16Le(0x0008, constant = True) self.wSignatureBlobType = UInt16Le(0x0008, constant = True)
self.wSignatureBlobLen = UInt16Le(lambda:(sizeof(self.SignatureBlob) + sizeof(self.padding))) self.wSignatureBlobLen = UInt16Le(lambda:(sizeof(self.SignatureBlob) + sizeof(self.padding)))
self.SignatureBlob = String(readLen = CallableValue(lambda:(self.wSignatureBlobLen.value - sizeof(self.padding)))) self.SignatureBlob = Buffer(readLen = CallableValue(lambda:(self.wSignatureBlobLen.value - sizeof(self.padding))))
self.padding = String(b"\x00" * 8, readLen = CallableValue(8)) self.padding = Buffer(b"\x00" * 8, readLen = CallableValue(8))
def getPublicKey(self): def getPublicKey(self):
""" """
@@ -405,7 +405,7 @@ class CertBlob(CompositeType):
def __init__(self): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.cbCert = UInt32Le(lambda:sizeof(self.abCert)) self.cbCert = UInt32Le(lambda:sizeof(self.abCert))
self.abCert = String(readLen = self.cbCert) self.abCert = Buffer(readLen = self.cbCert)
class X509CertificateChain(CompositeType): class X509CertificateChain(CompositeType):
""" """
@@ -418,7 +418,7 @@ class X509CertificateChain(CompositeType):
CompositeType.__init__(self) CompositeType.__init__(self)
self.NumCertBlobs = UInt32Le() self.NumCertBlobs = UInt32Le()
self.CertBlobArray = ArrayType(CertBlob, readLen = self.NumCertBlobs) 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): def getPublicKey(self):
""" """
@@ -447,8 +447,8 @@ class RSAPublicKey(CompositeType):
self.bitlen = UInt32Le(lambda:((self.keylen.value - 8) * 8)) self.bitlen = UInt32Le(lambda:((self.keylen.value - 8) * 8))
self.datalen = UInt32Le(lambda:((self.bitlen.value / 8) - 1)) self.datalen = UInt32Le(lambda:((self.bitlen.value / 8) - 1))
self.pubExp = UInt32Le() self.pubExp = UInt32Le()
self.modulus = String(readLen = CallableValue(lambda:(self.keylen.value - 8))) self.modulus = Buffer(readLen = CallableValue(lambda:(self.keylen.value - 8)))
self.padding = String("\x00" * 8, readLen = CallableValue(8)) self.padding = Buffer("\x00" * 8, readLen = CallableValue(8))
class ChannelDef(CompositeType): class ChannelDef(CompositeType):
""" """
@@ -458,7 +458,7 @@ class ChannelDef(CompositeType):
def __init__(self, name = "", options = 0): def __init__(self, name = "", options = 0):
CompositeType.__init__(self) CompositeType.__init__(self)
#name of channel #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 #unknown
self.options = UInt32Le() self.options = UInt32Le()

View File

@@ -25,7 +25,7 @@ The main channel is the graphical channel.
It exist channel for file system order, audio channel, clipboard etc... It exist channel for file system order, audio channel, clipboard etc...
""" """
from rdpy.model.layer import LayerAutomata, IStreamSender, Layer 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.model.error import InvalidExpectedDataException, InvalidValue, InvalidSize, CallPureVirtualFuntion
from rdpy.core.t125.ber import writeLength from rdpy.core.t125.ber import writeLength
import rdpy.model.log as log import rdpy.model.log as log
@@ -182,7 +182,7 @@ class MCSLayer(LayerAutomata):
@summary: Send disconnect provider ultimatum @summary: Send disconnect provider ultimatum
""" """
self._transport.send((UInt8(self.writeMCSPDUHeader(DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM, 1)), 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() self._transport.close()
def allChannelConnected(self): def allChannelConnected(self):

View File

@@ -21,7 +21,7 @@
Per encoded function 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 from rdpy.model.error import InvalidValue, InvalidExpectedDataException
def readLength(s): def readLength(s):
@@ -264,7 +264,7 @@ def writePadding(length):
@param length: length of padding @param length: length of padding
@return: String with \x00 * length @return: String with \x00 * length
""" """
return String("\x00"*length) return Buffer("\x00" * length)
def readOctetStream(s, octetStream, minValue = 0): def readOctetStream(s, octetStream, minValue = 0):
""" """

View File

@@ -25,13 +25,12 @@ Use to build correct size packet and handle slow path and fast path mode
import asyncio import asyncio
import ssl 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.layer import RawLayer
from rdpy.model.type import UInt8, UInt16Be, sizeof, Stream from rdpy.model.message import UInt8, UInt16Be, sizeof, Stream
from rdpy.model.error import CallPureVirtualFuntion
class Action(object): class Action:
""" """
@see: http://msdn.microsoft.com/en-us/library/cc240621.aspx @see: http://msdn.microsoft.com/en-us/library/cc240621.aspx
@see: http://msdn.microsoft.com/en-us/library/cc240589.aspx @see: http://msdn.microsoft.com/en-us/library/cc240589.aspx
@@ -40,7 +39,7 @@ class Action(object):
FASTPATH_ACTION_X224 = 0x3 FASTPATH_ACTION_X224 = 0x3
class SecFlags(object): class SecFlags:
""" """
@see: http://msdn.microsoft.com/en-us/library/cc240621.aspx @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 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ssl_ctx.check_hostname = False ssl_ctx.check_hostname = False
ssl_ctx.verify_mode = ssl.VerifyMode.CERT_NONE ssl_ctx.verify_mode = ssl.VerifyMode.CERT_NONE
reader, writer = await asyncio.open_connection(sock=self.writer.transport._sock, ssl=ssl_ctx, server_hostname="") reader, writer = await asyncio.open_connection(sock=self.writer.transport._sock, ssl=ssl_ctx, server_hostname="")
return Tpkt(reader, writer) 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 use to start NLA (NTLM over SSL) protocol
must be called after startTLS function 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() 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

View File

@@ -24,13 +24,14 @@ This layer have main goal to negociate SSL transport
RDP basic security is supported only on client side RDP basic security is supported only on client side
""" """
from rdpy.core import tpkt from rdpy.core import tpkt
from rdpy.core.nla import sspi
from rdpy.model import log from rdpy.model import log
from rdpy.model.layer import LayerAutomata, IStreamSender from rdpy.model.message import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof, Buffer
from rdpy.model.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof, String
from rdpy.model.error import InvalidExpectedDataException, RDPSecurityNegoFail from rdpy.model.error import InvalidExpectedDataException, RDPSecurityNegoFail
class MessageType(object):
class MessageType:
""" """
@summary: Message type @summary: Message type
""" """
@@ -40,7 +41,8 @@ class MessageType(object):
X224_TPDU_DATA = 0xF0 X224_TPDU_DATA = 0xF0
X224_TPDU_ERROR = 0x70 X224_TPDU_ERROR = 0x70
class NegociationType(object):
class NegociationType:
""" """
@summary: Negotiation header @summary: Negotiation header
""" """
@@ -48,7 +50,8 @@ class NegociationType(object):
TYPE_RDP_NEG_RSP = 0x02 TYPE_RDP_NEG_RSP = 0x02
TYPE_RDP_NEG_FAILURE = 0x03 TYPE_RDP_NEG_FAILURE = 0x03
class Protocols(object):
class Protocols:
""" """
@summary: Protocols available for x224 layer @summary: Protocols available for x224 layer
@see: https://msdn.microsoft.com/en-us/library/cc240500.aspx @see: https://msdn.microsoft.com/en-us/library/cc240500.aspx
@@ -58,7 +61,8 @@ class Protocols(object):
PROTOCOL_HYBRID = 0x00000002 PROTOCOL_HYBRID = 0x00000002
PROTOCOL_HYBRID_EX = 0x00000008 PROTOCOL_HYBRID_EX = 0x00000008
class NegotiationFailureCode(object):
class NegotiationFailureCode:
""" """
@summary: Protocol negotiation failure code @summary: Protocol negotiation failure code
""" """
@@ -70,23 +74,23 @@ class NegotiationFailureCode(object):
SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006 SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006
class ClientConnectionRequestPDU(CompositeType): class ConnectionRequestPDU(CompositeType):
""" """
@summary: Connection request Connection Request PDU
client -> server Use to send protocol security level available for the client
@see: http://msdn.microsoft.com/en-us/library/cc240470.aspx :see: http://msdn.microsoft.com/en-us/library/cc240470.aspx
""" """
def __init__(self): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.len = UInt8(lambda:sizeof(self) - 1) 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.padding = (UInt16Be(), UInt16Be(), UInt8())
self.cookie = String(until = "\x0d\x0a", conditional = lambda:(self.len._is_readed and self.len.value > 14)) self.cookie = Buffer(until=b"\x0d\x0a", conditional=lambda: (self.len._is_readed and self.len.value > 14))
#read if there is enough data # read if there is enough data
self.protocolNeg = Negotiation(optional = True) self.protocolNeg = Negotiation(optional = True)
class ServerConnectionConfirm(CompositeType): class ConnectionConfirmPDU(CompositeType):
""" """
@summary: Server response @summary: Server response
@see: http://msdn.microsoft.com/en-us/library/cc240506.aspx @see: http://msdn.microsoft.com/en-us/library/cc240506.aspx
@@ -159,55 +163,38 @@ class X224:
await self.tpkt.write((X224DataHeader(), message)) 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 Negotiate the security level and generate a X224 configured layer
Next state is recvConnectionConfirm
@see: http://msdn.microsoft.com/en-us/library/cc240500.aspx :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() request = ConnectionRequestPDU()
message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_REQ request.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_REQ
message.protocolNeg.selectedProtocol.value = Protocols.PROTOCOL_HYBRID | Protocols.PROTOCOL_SSL request.protocolNeg.selectedProtocol.value = Protocols.PROTOCOL_HYBRID | Protocols.PROTOCOL_SSL
await tpkt.write(message) await tpkt.write(request)
selected_protocol = await read_connection_confirm(await tpkt.read())
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]: if selected_protocol in [Protocols.PROTOCOL_HYBRID_EX]:
raise InvalidExpectedDataException("RDPY doesn't support PROTOCOL_HYBRID_EX security Layer") raise InvalidExpectedDataException("RDPY doesn't support PROTOCOL_HYBRID_EX security Layer")
if selected_protocol == Protocols.PROTOCOL_RDP: if selected_protocol == Protocols.PROTOCOL_RDP:
log.warning("*" * 43)
log.warning("*" + " " * 10 + "RDP Security selected" + " " * 10 + "*")
log.warning("*" * 43)
return X224(tpkt) return X224(tpkt)
elif selected_protocol == Protocols.PROTOCOL_SSL: 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()) return X224(await tpkt.start_tls())
elif selected_protocol == Protocols.PROTOCOL_HYBRID: elif selected_protocol == Protocols.PROTOCOL_HYBRID:
log.info("*" * 43) return X224(await tpkt.start_nla(authentication_protocol))
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
class Server(X224): class Server(X224):
@@ -240,7 +227,7 @@ class Server(X224):
@param data: {Stream} @param data: {Stream}
@see : http://msdn.microsoft.com/en-us/library/cc240470.aspx @see : http://msdn.microsoft.com/en-us/library/cc240470.aspx
""" """
message = ClientConnectionRequestPDU() message = ConnectionRequestPDU()
data.read_type(message) data.read_type(message)
if not message.protocolNeg._is_readed: if not message.protocolNeg._is_readed:
@@ -258,7 +245,7 @@ class Server(X224):
if not self._selectedProtocol & Protocols.PROTOCOL_SSL and self._forceSSL: if not self._selectedProtocol & Protocols.PROTOCOL_SSL and self._forceSSL:
log.warning("server reject client because doesn't support SSL") log.warning("server reject client because doesn't support SSL")
#send error message and quit #send error message and quit
message = ServerConnectionConfirm() message = ConnectionConfirmPDU()
message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_FAILURE message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_FAILURE
message.protocolNeg.failureCode.value = NegotiationFailureCode.SSL_REQUIRED_BY_SERVER message.protocolNeg.failureCode.value = NegotiationFailureCode.SSL_REQUIRED_BY_SERVER
self._transport.send(message) self._transport.send(message)
@@ -274,7 +261,7 @@ class Server(X224):
Next state is recvData Next state is recvData
@see : http://msdn.microsoft.com/en-us/library/cc240501.aspx @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.code.value = NegociationType.TYPE_RDP_NEG_RSP
message.protocolNeg.selectedProtocol.value = self._selectedProtocol message.protocolNeg.selectedProtocol.value = self._selectedProtocol
self._transport.send(message) self._transport.send(message)

View File

@@ -43,23 +43,18 @@ def sizeof(element):
for i in element: for i in element:
size += sizeof(i) size += sizeof(i)
return size return size
elif isinstance(element, Type) and element._conditional(): elif isinstance(element, Message) and element._conditional():
return element.__sizeof__() return element.__sizeof__()
return 0 return 0
class Type: class Message:
""" """
@summary: Root type object inheritance @summary: Root type object inheritance
Record conditional optional of constant mechanism 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._conditional = conditional
self._optional = optional self._optional = optional
@@ -130,22 +125,22 @@ class Type:
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "__sizeof__", "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 Expression evaluate when is get or set
Ex: Type contain length of array and array Ex: Type contain length of array and array
To know the size of array you need to read To know the size of array you need to read
length field before. At ctor time no length was 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 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) @param value: value will be wrapped (raw python type | lambda | function)
""" """
super().__init__(**kwargs)
self._value = None self._value = None
self.value = value
def __getValue__(self): def get_value(self):
""" """
@summary: Call when value is get -> Evaluate inner expression @summary: Call when value is get -> Evaluate inner expression
Can be overwritten to add specific check before Can be overwritten to add specific check before
@@ -154,7 +149,7 @@ class CallableValue:
""" """
return self._value() return self._value()
def __setValue__(self, value): def set_value(self, value):
""" """
@summary: Call when value is set @summary: Call when value is set
Can be overwritten to add specific check before Can be overwritten to add specific check before
@@ -167,24 +162,10 @@ class CallableValue:
self._value = value_callable self._value = value_callable
@property value = property(get_value, set_value)
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)
class SimpleType(Type, CallableValue): class SimpleType(DynMessage):
""" """
@summary: Non composite type @summary: Non composite type
leaf in type tree leaf in type tree
@@ -202,46 +183,11 @@ class SimpleType(Type, CallableValue):
And optional is True, read type is ignored And optional is True, read type is ignored
@param constant: Check if object value doesn't change after read operation @param constant: Check if object value doesn't change after read operation
""" """
super().__init__(conditional=conditional, optional=optional, constant=constant)
self._signed = signed self._signed = signed
self._typeSize = typeSize self._typeSize = typeSize
self._structFormat = structFormat self._structFormat = structFormat
Type.__init__(self, conditional = conditional, optional = optional, constant = constant) self.value = value
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()
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): def __write__(self, s):
""" """
@@ -262,31 +208,9 @@ class SimpleType(Type, CallableValue):
""" """
if s.data_len() < self._typeSize: if s.data_len() < self._typeSize:
raise InvalidSize("Stream is too small to read expected SimpleType") raise InvalidSize("Stream is too small to read expected SimpleType")
self.value = struct.unpack(self._structFormat, s.read(self._typeSize))[0] value = struct.unpack(self._structFormat, s.read(self._typeSize))[0]
def mask(self): self.value = value
"""
@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())
def __sizeof__(self): def __sizeof__(self):
""" """
@@ -428,13 +352,13 @@ class SimpleType(Type, CallableValue):
return bool(self.value) return bool(self.value)
class CompositeType(Type): class CompositeType(Message):
""" """
@summary: Type node in Type tree @summary: Type node in Type tree
Track type field declared in __init__ function Track type field declared in __init__ function
Ex: self.lengthOfPacket = UInt16Le() -> record lengthOfPacket as sub type of node 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 @param conditional : Callable object
Read and Write operation depend on return of this function Read and Write operation depend on return of this function
@@ -444,10 +368,11 @@ class CompositeType(Type):
@param readLen: Max length in bytes can be readed from stream @param readLen: Max length in bytes can be readed from stream
Use to check length information Use to check length information
""" """
Type.__init__(self, conditional = conditional, optional = optional, constant = constant) super().__init__(conditional=conditional, optional=optional, constant=constant)
#list of ordoned type
# list of ordoned type
self._typeName = [] self._typeName = []
self._readLen = readLen self._read_len = read_len
def __setattr__(self, name, value): def __setattr__(self, name, value):
""" """
@@ -457,7 +382,7 @@ class CompositeType(Type):
@param name: name of new attribute @param name: name of new attribute
@param value: value 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._typeName.append(name)
self.__dict__[name] = value self.__dict__[name] = value
@@ -475,11 +400,11 @@ class CompositeType(Type):
try: try:
s.read_type(self.__dict__[name]) s.read_type(self.__dict__[name])
readLen += sizeof(self.__dict__[name]) readLen += sizeof(self.__dict__[name])
#read is ok but read out of bound # read is ok but read out of bound
if not self._readLen is None and readLen > self._readLen.value: if not self._read_len is None and readLen > self._read_len.value:
#roll back # roll back
s.pos -= sizeof(self.__dict__[name]) s.pos -= sizeof(self.__dict__[name])
#and notify if not optional # and notify if not optional
if not self.__dict__[name]._optional: if not self.__dict__[name]._optional:
raise InvalidSize("Impossible to read type %s : read length is too small"%(self.__class__)) raise InvalidSize("Impossible to read type %s : read length is too small"%(self.__class__))
@@ -492,9 +417,9 @@ class CompositeType(Type):
s.seek(-sizeof(self.__dict__[tmpName]), 1) s.seek(-sizeof(self.__dict__[tmpName]), 1)
raise e raise e
if not self._readLen is None and readLen < self._readLen.value: 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._readLen.value - readLen)) log.debug("Still have correct data in packet %s, read %s bytes as padding"%(self.__class__, self._read_len.value - readLen))
s.read(self._readLen.value - readLen) s.read(self._read_len.value - readLen)
def __write__(self, s): def __write__(self, s):
""" """
@@ -514,8 +439,8 @@ class CompositeType(Type):
@summary: Call sizeof on each sub type @summary: Call sizeof on each sub type
@return: sum of sizeof of each Type attributes @return: sum of sizeof of each Type attributes
""" """
if self._is_readed and not self._readLen is None: if self._is_readed and not self._read_len is None:
return self._readLen.value return self._read_len.value
size = 0 size = 0
for name in self._typeName: for name in self._typeName:
@@ -721,6 +646,7 @@ class UInt24Be(SimpleType):
""" """
self.value = struct.unpack(self._structFormat, '\x00' + s.read(self._typeSize))[0] self.value = struct.unpack(self._structFormat, '\x00' + s.read(self._typeSize))[0]
class UInt24Le(SimpleType): class UInt24Le(SimpleType):
""" """
@summary: unsigned 24 bit integer @summary: unsigned 24 bit integer
@@ -742,7 +668,7 @@ class UInt24Le(SimpleType):
@summary: special write for a special type @summary: special write for a special type
@param s: Stream @param s: Stream
""" """
#don't write first byte # don't write first byte
s.write(struct.pack("<I", self.value)[:3]) s.write(struct.pack("<I", self.value)[:3])
def __read__(self, s): def __read__(self, s):
@@ -750,84 +676,56 @@ class UInt24Le(SimpleType):
@summary: special read for a special type @summary: special read for a special type
@param s: Stream @param s: Stream
""" """
self.value = struct.unpack(self._structFormat, s.read(self._typeSize) + '\x00')[0] self.value = struct.unpack(self._structFormat, s.read(self._typeSize) + b'\x00')[0]
class String(Type, CallableValue): class Buffer(DynMessage):
""" """
@summary: String type This a raw binary bytes data
Leaf in Type tree
""" """
def __init__(self, value=b"", readLen = None, encoding=None, conditional=lambda:True, optional=False, constant=False, until=None): def __init__(self, value: bytes = b"", read_len=None, conditional=lambda:True, optional: bool = False, constant: bool = False, until: bytes = None):
""" """
@param value: python string use for inner value
@param readLen: length use to read in stream (SimpleType) if 0 read entire stream
@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
@param unicode: Encode and decode value as unicode
@param until: read until sequence is readed or write sequence at the end of string
""" """
Type.__init__(self, conditional=conditional, optional=optional, constant=constant) super().__init__(conditional=conditional, optional=optional, constant=constant)
CallableValue.__init__(self, value) # type use to know read length
#type use to know read length self._read_len = read_len
self._readLen = readLen
self._encoding = encoding
self._until = until self._until = until
self.value = value
def __eq__(self, other): def __eq__(self, other):
""" """
""" """
return self.value.__eq__(other.value) return self.value.__eq__(other.value)
def __ne__(self, other): def __ne__(self, other):
""" """
""" """
return self.value.__ne__(other.value) return self.value.__ne__(other.value)
def __hash__(self): def __hash__(self):
""" """
@summary: hash function to treat simple type in hash collection
@return: hash of inner value
""" """
return hash(self.value) return hash(self.value)
def __str__(self): def __str__(self):
""" """
@summary: call when str function is call
@return: inner python string
""" """
return self.value return self.value
def __write__(self, s): def __write__(self, s):
""" """
@summary: Write the inner value after evaluation
Append until sequence if present
Encode in unicode format if asked
@param s: Stream
""" """
toWrite = self.value to_write = self.value
if not self._until is None: if not self._until is None:
toWrite += self._until to_write += self._until
s.write(to_write)
if self._unicode:
s.write(bytes(self.value.encode("utf-16le"), "utf-16le"))
else:
s.write(bytes(self.value, "ascii"))
def __read__(self, s): def __read__(self, s):
""" """
@summary: Read readLen bytes as string
If readLen is None read until 'until' sequence match
If until sequence is None read until end of stream
@param s: Stream
""" """
if self._readLen is None: if self._read_len is None:
if self._until is None: if self._until is None:
self.value = s.getvalue()[s.tell():] self.value = s.getvalue()[s.tell():]
else: else:
@@ -835,10 +733,7 @@ class String(Type, CallableValue):
while self.value[-len(self._until):] != self._until and s.data_len() != 0: while self.value[-len(self._until):] != self._until and s.data_len() != 0:
self.value += s.read(1) self.value += s.read(1)
else: else:
self.value = s.read(self._readLen.value) self.value = s.read(self._read_len())
if self._unicode:
self.value = self.value.decode("utf-16le")
def __sizeof__(self): def __sizeof__(self):
""" """
@@ -846,10 +741,8 @@ class String(Type, CallableValue):
if string is unicode encode return 2*len(str) + 2 if string is unicode encode return 2*len(str) + 2
@return: length of inner string @return: length of inner string
""" """
if self._unicode: return len(self.value)
return 2 * len(self.value) + 2
else:
return len(self.value)
def encodeUnicode(s): def encodeUnicode(s):
""" """
@@ -891,7 +784,7 @@ class Stream(BytesIO):
""" """
return self.seek() return self.seek()
def read_type(self, value: Type): def read_type(self, value: Message):
""" """
Call specific read on type object Call specific read on type object
or iterate over tuple elements or iterate over tuple elements
@@ -910,13 +803,14 @@ class Stream(BytesIO):
break break
self.pos -= sizeof(tmpElement) self.pos -= sizeof(tmpElement)
raise e raise e
return return value
# optional value not present # optional value not present
if self.data_len() == 0 and value._optional: if self.data_len() == 0 and value._optional:
return return
value.read(self) value.read(self)
return value
def readNextType(self, t): def readNextType(self, t):
""" """
@@ -926,7 +820,7 @@ class Stream(BytesIO):
self.read_type(t) self.read_type(t)
self.pos -= sizeof(t) self.pos -= sizeof(t)
def write_type(self, value: Type): def write_type(self, value: Message):
""" """
Call specific write on type object Call specific write on type object
or iterate over tuple element or iterate over tuple element
@@ -937,11 +831,12 @@ class Stream(BytesIO):
if isinstance(value, tuple) or isinstance(value, list): if isinstance(value, tuple) or isinstance(value, list):
for element in value: for element in value:
self.write_type(element) self.write_type(element)
return return self
value.write(self) value.write(self)
return self
class ArrayType(Type): class ArrayType(Message):
""" """
@summary: Factory af n element @summary: Factory af n element
""" """
@@ -956,7 +851,7 @@ class ArrayType(Type):
And optional is True, read type is ignored And optional is True, read type is ignored
@param constant: Check if object value doesn't change after read operation @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._typeFactory = typeFactory
self._readLen = readLen self._readLen = readLen
self._array = [] self._array = []
@@ -1000,7 +895,7 @@ class ArrayType(Type):
""" """
return sizeof(self._array) return sizeof(self._array)
class FactoryType(Type): class FactoryType(Message):
""" """
@summary: Call a factory callback at read or write time @summary: Call a factory callback at read or write time
Wrapp attribute access to inner type Wrapp attribute access to inner type
@@ -1014,7 +909,7 @@ class FactoryType(Type):
And optional is True, read type is ignored And optional is True, read type is ignored
@param constant: Check if object value doesn't change after read operation @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 self._factory = factory
if not callable(factory): if not callable(factory):
self._factory = lambda:factory self._factory = lambda:factory

View File

@@ -22,7 +22,7 @@ Remote Session Scenario File format
Private protocol format to save events 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 from rdpy.model import log, error
import time import time
@@ -63,7 +63,7 @@ class Event(CompositeType):
return c(readLen = self.length) return c(readLen = self.length)
log.debug("unknown event type : %s"%hex(self.type.value)) log.debug("unknown event type : %s"%hex(self.type.value))
#read entire packet #read entire packet
return String(readLen = self.length) return Buffer(readLen = self.length)
if event is None: if event is None:
event = FactoryType(EventFactory) event = FactoryType(EventFactory)
@@ -88,7 +88,7 @@ class UpdateEvent(CompositeType):
self.bpp = UInt8() self.bpp = UInt8()
self.format = UInt8() self.format = UInt8()
self.length = UInt32Le(lambda:sizeof(self.data)) self.length = UInt32Le(lambda:sizeof(self.data))
self.data = String(readLen = self.length) self.data = Buffer(readLen = self.length)
class InfoEvent(CompositeType): class InfoEvent(CompositeType):
""" """
@@ -98,13 +98,13 @@ class InfoEvent(CompositeType):
def __init__(self, readLen = None): def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen) CompositeType.__init__(self, readLen = readLen)
self.lenUsername = UInt16Le(lambda:sizeof(self.username)) 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.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.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.lenHostname = UInt16Le(lambda:sizeof(self.hostname))
self.hostname = String(readLen = self.lenHostname) self.hostname = Buffer(readLen = self.lenHostname)
class ScreenEvent(CompositeType): class ScreenEvent(CompositeType):
""" """

View File

@@ -24,7 +24,7 @@
def KSA(key): def KSA(key):
keylength = len(key) keylength = len(key)
S = range(256) S = list(range(256))
j = 0 j = 0
for i in range(256): for i in range(256):
@@ -50,8 +50,10 @@ def RC4(key):
S = KSA(key) S = KSA(key)
return PRGA(S) return PRGA(S)
def RC4Key(key):
return RC4([ord(c) for c in key])
def crypt(keystream, plaintext): def RC4Key(key):
return "".join([chr(ord(c) ^ keystream.next()) for c in plaintext]) return RC4(key)
def crypt(keystream, plaintext: bytes) -> bytes:
return bytes([c ^ next(keystream) for c in plaintext])

View File

@@ -91,7 +91,7 @@ class X224Test(unittest.TestCase):
s = type.Stream() s = type.Stream()
s.write_type(data) s.write_type(data)
s.pos = 0 s.pos = 0
t = x224.ClientConnectionRequestPDU() t = x224.ConnectionRequestPDU()
s.read_type(t) s.read_type(t)
if t.protocolNeg.code != x224.NegociationType.TYPE_RDP_NEG_REQ: 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 @summary: unit test for X224Client.recvConnectionConfirm and sendConnectionRequest function
check negotiation failure check negotiation failure
""" """
message = x224.ServerConnectionConfirm() message = x224.ConnectionConfirmPDU()
message.protocolNeg.code.value = x224.NegociationType.TYPE_RDP_NEG_FAILURE message.protocolNeg.code.value = x224.NegociationType.TYPE_RDP_NEG_FAILURE
s = type.Stream() s = type.Stream()
s.write_type(message) s.write_type(message)
@@ -141,7 +141,7 @@ class X224Test(unittest.TestCase):
def recvData(data): def recvData(data):
raise X224Test.X224_PASS() raise X224Test.X224_PASS()
message = x224.ServerConnectionConfirm() message = x224.ConnectionConfirmPDU()
message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_SSL message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_SSL
s = type.Stream() s = type.Stream()
@@ -165,14 +165,14 @@ class X224Test(unittest.TestCase):
class Transport(object): class Transport(object):
def send(self, data): def send(self, data):
if not isinstance(data, x224.ServerConnectionConfirm): if not isinstance(data, x224.ConnectionConfirmPDU):
raise X224Test.X224_FAIL() 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: 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() raise X224Test.X224_FAIL()
def close(self): def close(self):
raise X224Test.X224_PASS() raise X224Test.X224_PASS()
message = x224.ClientConnectionRequestPDU() message = x224.ConnectionRequestPDU()
message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_HYBRID message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_HYBRID
s = type.Stream() s = type.Stream()
s.write_type(message) s.write_type(message)
@@ -204,7 +204,7 @@ class X224Test(unittest.TestCase):
tls = True tls = True
def send(self, data): def send(self, data):
if not isinstance(data, x224.ServerConnectionConfirm): if not isinstance(data, x224.ConnectionConfirmPDU):
raise X224Test.X224_FAIL() raise X224Test.X224_FAIL()
if data.protocolNeg.code.value != x224.NegociationType.TYPE_RDP_NEG_RSP or data.protocolNeg.selectedProtocol.value != x224.Protocols.PROTOCOL_SSL: if data.protocolNeg.code.value != x224.NegociationType.TYPE_RDP_NEG_RSP or data.protocolNeg.selectedProtocol.value != x224.Protocols.PROTOCOL_SSL:
raise X224Test.X224_FAIL() raise X224Test.X224_FAIL()
@@ -214,7 +214,7 @@ class X224Test(unittest.TestCase):
global connect_event global connect_event
connect_event = True connect_event = True
message = x224.ClientConnectionRequestPDU() message = x224.ConnectionRequestPDU()
message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_SSL | x224.Protocols.PROTOCOL_RDP message.protocolNeg.selectedProtocol.value = x224.Protocols.PROTOCOL_SSL | x224.Protocols.PROTOCOL_RDP
s = type.Stream() s = type.Stream()
s.write_type(message) s.write_type(message)