Update: refactor cssp code
This commit is contained in:
@@ -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!'))
|
||||||
@@ -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()
|
||||||
|
|||||||
@@ -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))))
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -125,7 +130,7 @@ class AvPair(CompositeType):
|
|||||||
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,8 +149,8 @@ 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,7 +174,7 @@ 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()
|
||||||
@@ -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,7 +221,7 @@ 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()
|
||||||
@@ -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,10 +636,7 @@ 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)
|
||||||
|
|||||||
@@ -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):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
@@ -476,7 +401,7 @@ class CompositeType(Type):
|
|||||||
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
|
||||||
@@ -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
|
||||||
@@ -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._readLen = readLen
|
self._read_len = read_len
|
||||||
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,11 +741,9 @@ 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 2 * len(self.value) + 2
|
|
||||||
else:
|
|
||||||
return len(self.value)
|
return len(self.value)
|
||||||
|
|
||||||
|
|
||||||
def encodeUnicode(s):
|
def encodeUnicode(s):
|
||||||
"""
|
"""
|
||||||
@summary: Encode string in unicode
|
@summary: Encode string in unicode
|
||||||
@@ -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
|
||||||
@@ -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):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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])
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user