Update: refactor cssp code

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

View File

@@ -25,7 +25,8 @@ import sys
import asyncio
from rdpy.core import tpkt, x224
from rdpy.model.type import UInt8
from rdpy.core.nla import ntlm
from rdpy.model.message import UInt8
if __name__ == '__main__':
@@ -35,9 +36,9 @@ if __name__ == '__main__':
reader, writer = await asyncio.open_connection(
'127.0.0.1', 33389)
x224_layer = await x224.connect(tpkt.Tpkt(reader, writer))
x224_layer = await x224.connect(tpkt.Tpkt(reader, writer), ntlm.NTLMv2("", "sylvain", "sylvain"))
await x224_layer.write(UInt8(8))
await asyncio.sleep(1000)
await asyncio.sleep(10)
print("foooooooooooooooooooo")
asyncio.run(tcp_echo_client('Hello World!'))

View File

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

View File

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

View File

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

View File

@@ -24,7 +24,7 @@ Definition of structure use for capabilities nego
Use in PDU layer
"""
from rdpy.model.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType
from rdpy.model.type import CompositeType, CallableValue, Buffer, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType
class CapsType(object):
@@ -241,7 +241,7 @@ class Capability(CompositeType):
return c(readLen = self.lengthCapability - 4)
log.debug("unknown Capability type : %s"%hex(self.capabilitySetType.value))
#read entire packet
return String(readLen = self.lengthCapability - 4)
return Buffer(readLen =self.lengthCapability - 4)
if capability is None:
capability = FactoryType(CapabilityFactory)
@@ -309,7 +309,7 @@ class OrderCapability(CompositeType):
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.terminalDescriptor = String("\x00" * 16, readLen = CallableValue(16))
self.terminalDescriptor = Buffer("\x00" * 16, readLen = CallableValue(16))
self.pad4octetsA = UInt32Le(0)
self.desktopSaveXGranularity = UInt16Le(1)
self.desktopSaveYGranularity = UInt16Le(20)
@@ -389,7 +389,7 @@ class InputCapability(CompositeType):
#same value as gcc.ClientCoreSettings.keyboardFnKeys
self.keyboardFunctionKey = UInt32Le()
#same value as gcc.ClientCoreSettingrrs.imeFileName
self.imeFileName = String("\x00" * 64, readLen = CallableValue(64))
self.imeFileName = Buffer("\x00" * 64, readLen = CallableValue(64))
class BrushCapability(CompositeType):
"""

View File

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

View File

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

View File

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

View File

@@ -22,7 +22,7 @@ Basic Encoding Rules use in RDP.
ASN.1 standard
"""
from rdpy.model.type import UInt8, UInt16Be, UInt32Be, String
from rdpy.model.type import UInt8, UInt16Be, UInt32Be, Buffer
from rdpy.model.error import InvalidExpectedDataException, InvalidSize
class BerPc(object):
@@ -235,7 +235,7 @@ def writeOctetstring(value):
@param value: string
@return: BER octet string block
"""
return (writeUniversalTag(Tag.BER_TAG_OCTET_STRING, False), writeLength(len(value)), String(value))
return (writeUniversalTag(Tag.BER_TAG_OCTET_STRING, False), writeLength(len(value)), Buffer(value))
def readEnumerated(s):
"""

View File

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

View File

@@ -25,7 +25,7 @@ The main channel is the graphical channel.
It exist channel for file system order, audio channel, clipboard etc...
"""
from rdpy.model.layer import LayerAutomata, IStreamSender, Layer
from rdpy.model.type import sizeof, Stream, UInt8, UInt16Le, String
from rdpy.model.message import sizeof, Stream, UInt8, UInt16Le, Buffer
from rdpy.model.error import InvalidExpectedDataException, InvalidValue, InvalidSize, CallPureVirtualFuntion
from rdpy.core.t125.ber import writeLength
import rdpy.model.log as log
@@ -182,7 +182,7 @@ class MCSLayer(LayerAutomata):
@summary: Send disconnect provider ultimatum
"""
self._transport.send((UInt8(self.writeMCSPDUHeader(DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM, 1)),
per.writeEnumerates(0x80), String("\x00" * 6)))
per.writeEnumerates(0x80), Buffer("\x00" * 6)))
self._transport.close()
def allChannelConnected(self):

View File

@@ -21,7 +21,7 @@
Per encoded function
"""
from rdpy.model.type import UInt8, UInt16Be, UInt32Be, String
from rdpy.model.message import UInt8, UInt16Be, UInt32Be, Buffer
from rdpy.model.error import InvalidValue, InvalidExpectedDataException
def readLength(s):
@@ -264,7 +264,7 @@ def writePadding(length):
@param length: length of padding
@return: String with \x00 * length
"""
return String("\x00"*length)
return Buffer("\x00" * length)
def readOctetStream(s, octetStream, minValue = 0):
"""

View File

@@ -25,13 +25,12 @@ Use to build correct size packet and handle slow path and fast path mode
import asyncio
import ssl
from rdpy.core.nla import cssp, ntlm
from rdpy.core.nla import cssp, sspi
from rdpy.model.layer import RawLayer
from rdpy.model.type import UInt8, UInt16Be, sizeof, Stream
from rdpy.model.error import CallPureVirtualFuntion
from rdpy.model.message import UInt8, UInt16Be, sizeof, Stream
class Action(object):
class Action:
"""
@see: http://msdn.microsoft.com/en-us/library/cc240621.aspx
@see: http://msdn.microsoft.com/en-us/library/cc240589.aspx
@@ -40,7 +39,7 @@ class Action(object):
FASTPATH_ACTION_X224 = 0x3
class SecFlags(object):
class SecFlags:
"""
@see: http://msdn.microsoft.com/en-us/library/cc240621.aspx
"""
@@ -163,13 +162,18 @@ class Tpkt:
ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ssl_ctx.check_hostname = False
ssl_ctx.verify_mode = ssl.VerifyMode.CERT_NONE
reader, writer = await asyncio.open_connection(sock=self.writer.transport._sock, ssl=ssl_ctx, server_hostname="")
return Tpkt(reader, writer)
async def start_nla(self):
async def start_nla(self, authentication_protocol: sspi.IAuthenticationProtocol):
"""
use to start NLA (NTLM over SSL) protocol
must be called after startTLS function
:ivar authentication_protocol: Authentication protocol use by CSSP to authenticate user
and transfert credentials
"""
tpkt = await self.start_tls()
await cssp.connect(tpkt.reader, tpkt.writer, ntlm.NTLMv2("", "sylvain", "sylvain"))
await cssp.connect(tpkt.reader, tpkt.writer, authentication_protocol)
return tpkt

View File

@@ -24,13 +24,14 @@ This layer have main goal to negociate SSL transport
RDP basic security is supported only on client side
"""
from rdpy.core import tpkt
from rdpy.core.nla import sspi
from rdpy.model import log
from rdpy.model.layer import LayerAutomata, IStreamSender
from rdpy.model.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof, String
from rdpy.model.message import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof, Buffer
from rdpy.model.error import InvalidExpectedDataException, RDPSecurityNegoFail
class MessageType(object):
class MessageType:
"""
@summary: Message type
"""
@@ -40,7 +41,8 @@ class MessageType(object):
X224_TPDU_DATA = 0xF0
X224_TPDU_ERROR = 0x70
class NegociationType(object):
class NegociationType:
"""
@summary: Negotiation header
"""
@@ -48,7 +50,8 @@ class NegociationType(object):
TYPE_RDP_NEG_RSP = 0x02
TYPE_RDP_NEG_FAILURE = 0x03
class Protocols(object):
class Protocols:
"""
@summary: Protocols available for x224 layer
@see: https://msdn.microsoft.com/en-us/library/cc240500.aspx
@@ -57,8 +60,9 @@ class Protocols(object):
PROTOCOL_SSL = 0x00000001
PROTOCOL_HYBRID = 0x00000002
PROTOCOL_HYBRID_EX = 0x00000008
class NegotiationFailureCode(object):
class NegotiationFailureCode:
"""
@summary: Protocol negotiation failure code
"""
@@ -70,23 +74,23 @@ class NegotiationFailureCode(object):
SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006
class ClientConnectionRequestPDU(CompositeType):
class ConnectionRequestPDU(CompositeType):
"""
@summary: Connection request
client -> server
@see: http://msdn.microsoft.com/en-us/library/cc240470.aspx
Connection Request PDU
Use to send protocol security level available for the client
:see: http://msdn.microsoft.com/en-us/library/cc240470.aspx
"""
def __init__(self):
CompositeType.__init__(self)
self.len = UInt8(lambda:sizeof(self) - 1)
self.code = UInt8(MessageType.X224_TPDU_CONNECTION_REQUEST, constant = True)
self.code = UInt8(MessageType.X224_TPDU_CONNECTION_REQUEST, constant=True)
self.padding = (UInt16Be(), UInt16Be(), UInt8())
self.cookie = String(until = "\x0d\x0a", conditional = lambda:(self.len._is_readed and self.len.value > 14))
#read if there is enough data
self.cookie = Buffer(until=b"\x0d\x0a", conditional=lambda: (self.len._is_readed and self.len.value > 14))
# read if there is enough data
self.protocolNeg = Negotiation(optional = True)
class ServerConnectionConfirm(CompositeType):
class ConnectionConfirmPDU(CompositeType):
"""
@summary: Server response
@see: http://msdn.microsoft.com/en-us/library/cc240506.aspx
@@ -159,55 +163,38 @@ class X224:
await self.tpkt.write((X224DataHeader(), message))
async def connect(tpkt: tpkt.Tpkt) -> X224:
async def connect(tpkt: tpkt.Tpkt, authentication_protocol: sspi.IAuthenticationProtocol) -> X224:
"""
@summary: Write connection request message
Next state is recvConnectionConfirm
@see: http://msdn.microsoft.com/en-us/library/cc240500.aspx
Negotiate the security level and generate a X224 configured layer
:ivar tpkt: this is the tpkt layer use to negotiate the security level
:ivar authentication_protocol: Authentication protocol is used by NLA authentication
Actually only NTLMv2 is available
:see: http://msdn.microsoft.com/en-us/library/cc240500.aspx
"""
message = ClientConnectionRequestPDU()
message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_REQ
message.protocolNeg.selectedProtocol.value = Protocols.PROTOCOL_HYBRID | Protocols.PROTOCOL_SSL
await tpkt.write(message)
selected_protocol = await read_connection_confirm(await tpkt.read())
request = ConnectionRequestPDU()
request.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_REQ
request.protocolNeg.selectedProtocol.value = Protocols.PROTOCOL_HYBRID | Protocols.PROTOCOL_SSL
await tpkt.write(request)
respond = (await tpkt.read()).read_type(ConnectionConfirmPDU())
if respond.protocolNeg.failureCode._is_readed:
raise RDPSecurityNegoFail("negotiation failure code %x"%respond.protocolNeg.failureCode.value)
selected_protocol = Protocols.PROTOCOL_RDP
if respond.protocolNeg._is_readed:
selected_protocol = respond.protocolNeg.selectedProtocol.value
if selected_protocol in [Protocols.PROTOCOL_HYBRID_EX]:
raise InvalidExpectedDataException("RDPY doesn't support PROTOCOL_HYBRID_EX security Layer")
if selected_protocol == Protocols.PROTOCOL_RDP:
log.warning("*" * 43)
log.warning("*" + " " * 10 + "RDP Security selected" + " " * 10 + "*")
log.warning("*" * 43)
if selected_protocol == Protocols.PROTOCOL_RDP:
return X224(tpkt)
elif selected_protocol == Protocols.PROTOCOL_SSL:
log.info("*" * 43)
log.info("*" + " " * 10 + "SSL Security selected" + " " * 10 + "*")
log.info("*" * 43)
return X224(await tpkt.start_tls())
elif selected_protocol == Protocols.PROTOCOL_HYBRID:
log.info("*" * 43)
log.info("*" + " " * 10 + "NLA Security selected" + " " * 10 + "*")
log.info("*" * 43)
return X224(await tpkt.start_nla())
async def read_connection_confirm(data) -> int:
"""
Read connection confirm and return the negotiated protocol
:ivar data: Stream that contain connection confirm
:see: response -> https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/b2975bdc-6d56-49ee-9c57-f2ff3a0b6817
:see: failure -> https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/1b3920e7-0116-4345-bc45-f2c4ad012761
"""
message = ServerConnectionConfirm()
data.read_type(message)
if message.protocolNeg.failureCode._is_readed:
raise RDPSecurityNegoFail("negotiation failure code %x"%message.protocolNeg.failureCode.value)
# check presence of negotiation response
if message.protocolNeg._is_readed:
return message.protocolNeg.selectedProtocol.value
else:
return Protocols.PROTOCOL_RDP
return X224(await tpkt.start_nla(authentication_protocol))
class Server(X224):
@@ -240,7 +227,7 @@ class Server(X224):
@param data: {Stream}
@see : http://msdn.microsoft.com/en-us/library/cc240470.aspx
"""
message = ClientConnectionRequestPDU()
message = ConnectionRequestPDU()
data.read_type(message)
if not message.protocolNeg._is_readed:
@@ -258,7 +245,7 @@ class Server(X224):
if not self._selectedProtocol & Protocols.PROTOCOL_SSL and self._forceSSL:
log.warning("server reject client because doesn't support SSL")
#send error message and quit
message = ServerConnectionConfirm()
message = ConnectionConfirmPDU()
message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_FAILURE
message.protocolNeg.failureCode.value = NegotiationFailureCode.SSL_REQUIRED_BY_SERVER
self._transport.send(message)
@@ -274,7 +261,7 @@ class Server(X224):
Next state is recvData
@see : http://msdn.microsoft.com/en-us/library/cc240501.aspx
"""
message = ServerConnectionConfirm()
message = ConnectionConfirmPDU()
message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_RSP
message.protocolNeg.selectedProtocol.value = self._selectedProtocol
self._transport.send(message)

View File

@@ -43,23 +43,18 @@ def sizeof(element):
for i in element:
size += sizeof(i)
return size
elif isinstance(element, Type) and element._conditional():
elif isinstance(element, Message) and element._conditional():
return element.__sizeof__()
return 0
return 0
class Type:
class Message:
"""
@summary: Root type object inheritance
Record conditional optional of constant mechanism
"""
def __init__(self, conditional=lambda:True, optional=False, constant=False):
def __init__(self, conditional=lambda: True, optional=False, constant=False):
"""
@param conditional : Callable object
Read and Write operation depend on return of this function
@param optional: If there is no enough byte in current stream
And optional is True, read type is ignored
@param constant: Check if object value doesn't change after read operation
"""
self._conditional = conditional
self._optional = optional
@@ -70,7 +65,7 @@ class Type:
self._is_readed = False
# use to know if type was written
self._is_writed = False
def write(self, s):
"""
@summary: Check conditional callback
@@ -81,7 +76,7 @@ class Type:
if not self._is_writed:
return
self.__write__(s)
def read(self, s):
"""
@summary: Check conditional callback
@@ -93,12 +88,12 @@ class Type:
self._is_readed = self._conditional()
if not self._is_readed:
return
# not constant mode direct reading
if not self._constant:
self.__read__(s)
return
# constant mode
old = deepcopy(self)
self.__read__(s)
@@ -107,21 +102,21 @@ class Type:
# rollback read value
s.seek(-sizeof(self), 1)
raise InvalidExpectedDataException("%s const value expected %s != %s"%(self.__class__, old.value, self.value))
def __read__(self, s):
"""
@summary: Interface definition of private read function
@param s: Stream
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "__read__", "Type"))
def __write__(self, s):
"""
@summary: Interface definition of private write function
@param s: Stream
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "__write__", "Type"))
def __sizeof__(self):
"""
@summary: Return size of type use for sizeof function
@@ -130,22 +125,22 @@ class Type:
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "__sizeof__", "Type"))
class CallableValue:
class DynMessage(Message):
"""
@summary: Expression evaluate when is get or set
Ex: Type contain length of array and array
To know the size of array you need to read
length field before. At ctor time no length was read.
You need a callable object that will be evaluate when it will be used
Expression evaluate when is get or set
Ex: Type contain length of array and array
To know the size of array you need to read
length field before. At ctor time no length was read.
You need a callable object that will be evaluate when it will be used
"""
def __init__(self, value):
def __init__(self, **kwargs):
"""
@param value: value will be wrapped (raw python type | lambda | function)
"""
super().__init__(**kwargs)
self._value = None
self.value = value
def __getValue__(self):
def get_value(self):
"""
@summary: Call when value is get -> Evaluate inner expression
Can be overwritten to add specific check before
@@ -153,8 +148,8 @@ class CallableValue:
@return: value expression evaluated
"""
return self._value()
def __setValue__(self, value):
def set_value(self, value):
"""
@summary: Call when value is set
Can be overwritten to add specific check before
@@ -164,27 +159,13 @@ class CallableValue:
value_callable = lambda:value
if callable(value):
value_callable = value
self._value = value_callable
@property
def value(self):
"""
@summary: Evaluate callable expression
@return: result of callable value
"""
return self.__getValue__()
@value.setter
def value(self, value):
"""
@summary: Setter of value
@param value: new value encompass in value type object
"""
self.__setValue__(value)
value = property(get_value, set_value)
class SimpleType(Type, CallableValue):
class SimpleType(DynMessage):
"""
@summary: Non composite type
leaf in type tree
@@ -202,47 +183,12 @@ class SimpleType(Type, CallableValue):
And optional is True, read type is ignored
@param constant: Check if object value doesn't change after read operation
"""
super().__init__(conditional=conditional, optional=optional, constant=constant)
self._signed = signed
self._typeSize = typeSize
self._structFormat = structFormat
Type.__init__(self, conditional = conditional, optional = optional, constant = constant)
CallableValue.__init__(self, value)
def __getValue__(self):
"""
@summary: Check value if match range of type
And apply sign
Ex: UInt8 can be > 255
@return: Python value wrap into type
@raise InvalidValue: if value doesn't respect type range
@see: CallableValue.__getValue__
"""
value = CallableValue.__getValue__(self)
#check value now because it can be an callable value
#and evaluate a this time
if not self.isInRange(value):
raise InvalidValue("value is out of range for %s"%self.__class__)
if self._signed:
return value
else:
return value & self.mask()
self.value = value
def __setValue__(self, value):
"""
@summary: Check if new value respect type declaration
Ex: UInt8 can be > 256
@param value: new value (raw python type | lambda | function)
@raise InvalidValue: if value doesn't respect type range
@see: CallableValue.__setValue__
"""
#check static value range
if not callable(value) and not self.isInRange(value):
raise InvalidValue("value is out of range for %s"%self.__class__)
CallableValue.__setValue__(self, value)
def __write__(self, s):
"""
@summary: Write value in stream
@@ -251,7 +197,7 @@ class SimpleType(Type, CallableValue):
@param s: Stream that will be written
"""
s.write(struct.pack(self._structFormat, self.value))
def __read__(self, s):
"""
@summary: Read inner value from stream
@@ -262,39 +208,17 @@ class SimpleType(Type, CallableValue):
"""
if s.data_len() < self._typeSize:
raise InvalidSize("Stream is too small to read expected SimpleType")
self.value = struct.unpack(self._structFormat, s.read(self._typeSize))[0]
def mask(self):
"""
@summary: Compute bit mask for type
Because in Python all numbers are Int long or float
Cache result in self._mask field
"""
if "_mask" not in self.__dict__.keys():
mask = 0xff
for _ in range(1, self._typeSize):
mask = mask << 8 | 0xff
self._mask = mask
return self._mask
def isInRange(self, value):
"""
@summary: Check if value is in range represented by mask
@param value: Python value
@return: true if value is in type range
"""
if self._signed:
return not (value < -(self.mask() >> 1) or value > (self.mask() >> 1))
else:
return not (value < 0 or value > self.mask())
value = struct.unpack(self._structFormat, s.read(self._typeSize))[0]
self.value = value
def __sizeof__(self):
"""
@summary: Return size of type in bytes
@return: typeSize pass in constructor
"""
return self._typeSize
def __eq__(self, other):
"""
@summary: Compare two simple type
@@ -318,7 +242,7 @@ class SimpleType(Type, CallableValue):
if not isinstance(other, SimpleType):
other = self.__class__(other)
return self.value.__ne__(other.value)
def __invert__(self):
"""
@summary: Implement not operator
@@ -328,7 +252,7 @@ class SimpleType(Type, CallableValue):
if not self._signed:
invert &= self.mask()
return self.__class__(invert)
def __add__(self, other):
"""
@summary: Implement addition operator
@@ -340,7 +264,7 @@ class SimpleType(Type, CallableValue):
if not isinstance(other, SimpleType):
other = self.__class__(other)
return self.__class__(self.value.__add__(other.value))
def __sub__(self, other):
"""
@summary: Implement sub operator
@@ -352,7 +276,7 @@ class SimpleType(Type, CallableValue):
if not isinstance(other, SimpleType):
other = self.__class__(other)
return self.__class__(self.value.__sub__(other.value))
def __and__(self, other):
"""
@summary: Implement bitwise and operator
@@ -364,7 +288,7 @@ class SimpleType(Type, CallableValue):
if not isinstance(other, SimpleType):
other = self.__class__(other)
return self.__class__(self.value.__and__(other.value))
def __or__(self, other):
"""
@summary: Implement bitwise or operator
@@ -376,7 +300,7 @@ class SimpleType(Type, CallableValue):
if not isinstance(other, SimpleType):
other = self.__class__(other)
return self.__class__(self.value.__or__(other.value))
def __xor__(self, other):
"""
@summary: Implement bitwise xor operator
@@ -388,7 +312,7 @@ class SimpleType(Type, CallableValue):
if not isinstance(other, SimpleType):
other = self.__class__(other)
return self.__class__(self.value.__xor__(other.value))
def __lshift__(self, other):
"""
@summary: Left shift operator
@@ -400,7 +324,7 @@ class SimpleType(Type, CallableValue):
if not isinstance(other, SimpleType):
other = self.__class__(other)
return self.__class__(self.value.__lshift__(other.value))
def __rshift__(self, other):
"""
@summary: Right shift operator
@@ -412,14 +336,14 @@ class SimpleType(Type, CallableValue):
if not isinstance(other, SimpleType):
other = self.__class__(other)
return self.__class__(self.value.__rshift__(other.value))
def __hash__(self):
"""
@summary: Hash function to handle simple type in hash collection
@return: hash of inner value
"""
return hash(self.value)
def __nonzero__(self):
"""
@summary: Boolean conversion
@@ -427,14 +351,14 @@ class SimpleType(Type, CallableValue):
"""
return bool(self.value)
class CompositeType(Type):
class CompositeType(Message):
"""
@summary: Type node in Type tree
Track type field declared in __init__ function
Ex: self.lengthOfPacket = UInt16Le() -> record lengthOfPacket as sub type of node
"""
def __init__(self, conditional = lambda:True, optional = False, constant = False, readLen = None):
def __init__(self, read_len = None, conditional = lambda:True, optional = False, constant = False, ):
"""
@param conditional : Callable object
Read and Write operation depend on return of this function
@@ -444,11 +368,12 @@ class CompositeType(Type):
@param readLen: Max length in bytes can be readed from stream
Use to check length information
"""
Type.__init__(self, conditional = conditional, optional = optional, constant = constant)
#list of ordoned type
super().__init__(conditional=conditional, optional=optional, constant=constant)
# list of ordoned type
self._typeName = []
self._readLen = readLen
self._read_len = read_len
def __setattr__(self, name, value):
"""
@summary: Track Type field
@@ -457,10 +382,10 @@ class CompositeType(Type):
@param name: name of new attribute
@param value: value of new attribute
"""
if name[0] != '_' and (isinstance(value, Type) or isinstance(value, tuple)) and not name in self._typeName:
if name[0] != '_' and (isinstance(value, Message) or isinstance(value, tuple)) and not name in self._typeName:
self._typeName.append(name)
self.__dict__[name] = value
def __read__(self, s):
"""
@summary: Read composite type
@@ -471,18 +396,18 @@ class CompositeType(Type):
@raise InvalidSize: if stream is greater than readLen parameter
"""
readLen = 0
for name in self._typeName:
for name in self._typeName:
try:
s.read_type(self.__dict__[name])
readLen += sizeof(self.__dict__[name])
#read is ok but read out of bound
if not self._readLen is None and readLen > self._readLen.value:
#roll back
# read is ok but read out of bound
if not self._read_len is None and readLen > self._read_len.value:
# roll back
s.pos -= sizeof(self.__dict__[name])
#and notify if not optional
# and notify if not optional
if not self.__dict__[name]._optional:
raise InvalidSize("Impossible to read type %s : read length is too small"%(self.__class__))
except Exception as e:
log.error("Error during read %s::%s"%(self.__class__, name))
#roll back already read
@@ -491,11 +416,11 @@ class CompositeType(Type):
break
s.seek(-sizeof(self.__dict__[tmpName]), 1)
raise e
if not self._readLen is None and readLen < self._readLen.value:
log.debug("Still have correct data in packet %s, read %s bytes as padding"%(self.__class__, self._readLen.value - readLen))
s.read(self._readLen.value - readLen)
if not self._read_len is None and readLen < self._read_len.value:
log.debug("Still have correct data in packet %s, read %s bytes as padding"%(self.__class__, self._read_len.value - readLen))
s.read(self._read_len.value - readLen)
def __write__(self, s):
"""
@summary: Write all sub-type handle by __setattr__ function
@@ -508,15 +433,15 @@ class CompositeType(Type):
except Exception as e:
log.error("Error during write %s::%s"%(self.__class__, name))
raise e
def __sizeof__(self):
"""
@summary: Call sizeof on each sub type
@return: sum of sizeof of each Type attributes
"""
if self._is_readed and not self._readLen is None:
return self._readLen.value
if self._is_readed and not self._read_len is None:
return self._read_len.value
size = 0
for name in self._typeName:
size += sizeof(self.__dict__[name])
@@ -535,7 +460,7 @@ class CompositeType(Type):
if self.__dict__[name] != other.__dict__[name]:
return False
return True
def __ne__(self, other):
"""
@summary: return not equal result operator
@@ -551,7 +476,7 @@ All simple Raw type use in RDPY
class UInt8(SimpleType):
"""
@summary: unsigned byte
"""
"""
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
"""
@param value: python value wrap
@@ -566,7 +491,7 @@ class UInt8(SimpleType):
class SInt8(SimpleType):
"""
@summary: signed byte
"""
"""
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
"""
@param value: python value wrap
@@ -577,8 +502,8 @@ class SInt8(SimpleType):
@param constant: Check if object value doesn't change after read operation
"""
SimpleType.__init__(self, "b", 1, True, value, conditional = conditional, optional = optional, constant = constant)
class UInt16Be(SimpleType):
"""
@summary: unsigned short
@@ -594,7 +519,7 @@ class UInt16Be(SimpleType):
@param constant: Check if object value doesn't change after read operation
"""
SimpleType.__init__(self, ">H", 2, False, value, conditional = conditional, optional = optional, constant = constant)
class UInt16Le(SimpleType):
"""
@summary: unsigned short
@@ -610,7 +535,7 @@ class UInt16Le(SimpleType):
@param constant: Check if object value doesn't change after read operation
"""
SimpleType.__init__(self, "<H", 2, False, value, conditional = conditional, optional = optional, constant = constant)
class SInt16Le(SimpleType):
"""
@summary: signed short
@@ -626,7 +551,7 @@ class SInt16Le(SimpleType):
@param constant: Check if object value doesn't change after read operation
"""
SimpleType.__init__(self, "<h", 2, True, value, conditional = conditional, optional = optional, constant = constant)
class UInt32Be(SimpleType):
"""
@summary: unsigned int
@@ -642,7 +567,7 @@ class UInt32Be(SimpleType):
@param constant: Check if object value doesn't change after read operation
"""
SimpleType.__init__(self, ">I", 4, False, value, conditional = conditional, optional = optional, constant = constant)
class UInt32Le(SimpleType):
"""
@summary: unsigned int
@@ -658,7 +583,7 @@ class UInt32Le(SimpleType):
@param constant: Check if object value doesn't change after read operation
"""
SimpleType.__init__(self, "<I", 4, False, value, conditional = conditional, optional = optional, constant = constant)
class SInt32Le(SimpleType):
"""
@summary: signed int
@@ -674,7 +599,7 @@ class SInt32Le(SimpleType):
@param constant: Check if object value doesn't change after read operation
"""
SimpleType.__init__(self, "<I", 4, True, value, conditional = conditional, optional = optional, constant = constant)
class SInt32Be(SimpleType):
"""
@summary: signed int
@@ -690,7 +615,7 @@ class SInt32Be(SimpleType):
@param constant: Check if object value doesn't change after read operation
"""
SimpleType.__init__(self, ">I", 4, True, value, conditional = conditional, optional = optional, constant = constant)
class UInt24Be(SimpleType):
"""
@summary: unsigned 24 bit integer
@@ -706,21 +631,22 @@ class UInt24Be(SimpleType):
@param constant: Check if object value doesn't change after read operation
"""
SimpleType.__init__(self, ">I", 3, False, value, conditional = conditional, optional = optional, constant = constant)
def __write__(self, s):
"""
@summary: special write for a special type
@param s: Stream
"""
s.write(struct.pack(">I", self.value)[1:])
def __read__(self, s):
"""
@summary: special read for a special type
@param s: Stream
"""
self.value = struct.unpack(self._structFormat, '\x00' + s.read(self._typeSize))[0]
class UInt24Le(SimpleType):
"""
@summary: unsigned 24 bit integer
@@ -735,99 +661,71 @@ class UInt24Le(SimpleType):
And optional is True, read type is ignored
@param constant: Check if object value doesn't change after read operation
"""
SimpleType.__init__(self, "<I", 3, False, value, conditional = conditional, optional = optional, constant = constant)
SimpleType.__init__(self, "<I", 3, False, value, conditional = conditional, optional = optional, constant = constant)
def __write__(self, s):
"""
@summary: special write for a special type
@param s: Stream
"""
#don't write first byte
# don't write first byte
s.write(struct.pack("<I", self.value)[:3])
def __read__(self, s):
"""
@summary: special read for a special type
@param s: Stream
"""
self.value = struct.unpack(self._structFormat, s.read(self._typeSize) + '\x00')[0]
self.value = struct.unpack(self._structFormat, s.read(self._typeSize) + b'\x00')[0]
class String(Type, CallableValue):
class Buffer(DynMessage):
"""
@summary: String type
Leaf in Type tree
This a raw binary bytes data
"""
def __init__(self, value=b"", readLen = None, encoding=None, conditional=lambda:True, optional=False, constant=False, until=None):
def __init__(self, value: bytes = b"", read_len=None, conditional=lambda:True, optional: bool = False, constant: bool = False, until: bytes = None):
"""
@param value: python string use for inner value
@param readLen: length use to read in stream (SimpleType) if 0 read entire stream
@param conditional : Callable object
Read and Write operation depend on return of this function
@param optional: If there is no enough byte in current stream
And optional is True, read type is ignored
@param constant: Check if object value doesn't change after read operation
@param unicode: Encode and decode value as unicode
@param until: read until sequence is readed or write sequence at the end of string
"""
Type.__init__(self, conditional=conditional, optional=optional, constant=constant)
CallableValue.__init__(self, value)
#type use to know read length
self._readLen = readLen
self._encoding = encoding
super().__init__(conditional=conditional, optional=optional, constant=constant)
# type use to know read length
self._read_len = read_len
self._until = until
self.value = value
def __eq__(self, other):
"""
"""
return self.value.__eq__(other.value)
def __ne__(self, other):
"""
"""
return self.value.__ne__(other.value)
def __hash__(self):
"""
@summary: hash function to treat simple type in hash collection
@return: hash of inner value
"""
return hash(self.value)
def __str__(self):
"""
@summary: call when str function is call
@return: inner python string
"""
return self.value
def __write__(self, s):
"""
@summary: Write the inner value after evaluation
Append until sequence if present
Encode in unicode format if asked
@param s: Stream
"""
toWrite = self.value
to_write = self.value
if not self._until is None:
toWrite += self._until
if self._unicode:
s.write(bytes(self.value.encode("utf-16le"), "utf-16le"))
else:
s.write(bytes(self.value, "ascii"))
to_write += self._until
s.write(to_write)
def __read__(self, s):
"""
@summary: Read readLen bytes as string
If readLen is None read until 'until' sequence match
If until sequence is None read until end of stream
@param s: Stream
"""
if self._readLen is None:
if self._read_len is None:
if self._until is None:
self.value = s.getvalue()[s.tell():]
else:
@@ -835,22 +733,17 @@ class String(Type, CallableValue):
while self.value[-len(self._until):] != self._until and s.data_len() != 0:
self.value += s.read(1)
else:
self.value = s.read(self._readLen.value)
if self._unicode:
self.value = self.value.decode("utf-16le")
self.value = s.read(self._read_len())
def __sizeof__(self):
"""
@summary: return length of string
if string is unicode encode return 2*len(str) + 2
@return: length of inner string
"""
if self._unicode:
return 2 * len(self.value) + 2
else:
return len(self.value)
return len(self.value)
def encodeUnicode(s):
"""
@summary: Encode string in unicode
@@ -883,15 +776,15 @@ class Stream(BytesIO):
:returns: not yet read length
"""
return len(self.getvalue()) - self.tell()
def read_len(self) -> int:
"""
Compute already read size
:returns: read size of stream
"""
return self.seek()
def read_type(self, value: Type):
def read_type(self, value: Message):
"""
Call specific read on type object
or iterate over tuple elements
@@ -910,14 +803,15 @@ class Stream(BytesIO):
break
self.pos -= sizeof(tmpElement)
raise e
return
return value
# optional value not present
if self.data_len() == 0 and value._optional:
return
value.read(self)
return value
def readNextType(self, t):
"""
@summary: read next type but didn't consume it
@@ -925,8 +819,8 @@ class Stream(BytesIO):
"""
self.read_type(t)
self.pos -= sizeof(t)
def write_type(self, value: Type):
def write_type(self, value: Message):
"""
Call specific write on type object
or iterate over tuple element
@@ -937,11 +831,12 @@ class Stream(BytesIO):
if isinstance(value, tuple) or isinstance(value, list):
for element in value:
self.write_type(element)
return
return self
value.write(self)
return self
class ArrayType(Type):
class ArrayType(Message):
"""
@summary: Factory af n element
"""
@@ -956,13 +851,13 @@ class ArrayType(Type):
And optional is True, read type is ignored
@param constant: Check if object value doesn't change after read operation
"""
Type.__init__(self, conditional, optional, constant)
Message.__init__(self, conditional, optional, constant)
self._typeFactory = typeFactory
self._readLen = readLen
self._array = []
if not init is None:
self._array = init
def __read__(self, s):
"""
@summary: Create readLen new object and read it
@@ -979,28 +874,28 @@ class ArrayType(Type):
break
self._array.append(element)
i += 1
def __write__(self, s):
"""
@summary: Just write array
@param s: Stream
"""
s.write_type(self._array)
def __getitem__(self, item):
"""
@summary: Magic function to be FactoryType as transparent as possible
@return: index of _value
"""
return self._array.__getitem__(item)
def __sizeof__(self):
"""
@summary: Size in bytes of all inner type
"""
return sizeof(self._array)
class FactoryType(Type):
class FactoryType(Message):
"""
@summary: Call a factory callback at read or write time
Wrapp attribute access to inner type
@@ -1014,13 +909,13 @@ class FactoryType(Type):
And optional is True, read type is ignored
@param constant: Check if object value doesn't change after read operation
"""
Type.__init__(self, conditional, optional, constant)
Message.__init__(self, conditional, optional, constant)
self._factory = factory
if not callable(factory):
self._factory = lambda:factory
self._value = None
def __read__(self, s):
"""
@summary: Call factory and write it
@@ -1028,7 +923,7 @@ class FactoryType(Type):
"""
self._value = self._factory()
s.read_type(self._value)
def __write__(self, s):
"""
@summary: Call factory and read it
@@ -1036,21 +931,21 @@ class FactoryType(Type):
"""
self._value = self._factory()
s.write_type(self._value)
def __getattr__(self, name):
"""
@summary: Magic function to be FactoryType as transparent as possible
@return: _value parameter
"""
return self._value.__getattribute__(name)
def __getitem__(self, item):
"""
@summary: Magic function to be FactoryType as transparent as possible
@return: index of _value
"""
return self._value.__getitem__(item)
def __sizeof__(self):
"""
@summary: Size of of object returned by factory

View File

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

View File

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

View File

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