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