finish RDP basic security layer client side, start server side

This commit is contained in:
speyrefitte
2014-12-15 18:26:27 +01:00
parent f9f92b8215
commit f2481149d9
11 changed files with 275 additions and 156 deletions

View File

@@ -149,10 +149,16 @@ def extractRSAKey(certificate):
@return: (modulus, public exponent) @return: (modulus, public exponent)
""" """
#http://www.alvestrand.no/objectid/1.2.840.113549.1.1.1.html #http://www.alvestrand.no/objectid/1.2.840.113549.1.1.1.html
#if certificate.getComponentByName('tbsCertificate').getComponentByName('subjectPublicKeyInfo').getComponentByName('algorithm').getComponentByName('algorithm')._value != (1, 2, 840, 113549, 1, 1, 1): #disable check because nobody respect
#if certificate.getComponentByName('tbsCertificate').getComponentByName('subjectPublicKeyInfo').getComponentByName('algorithm').getComponentByName('algorithm')._value != (1, 3, 14, 3, 2, 15):
# raise InvalidExpectedDataException("Certificate doesn't contain RSA public key") # raise InvalidExpectedDataException("Certificate doesn't contain RSA public key")
rsaKey = decoder.decode(encoder.encode(certificate.getComponentByName('tbsCertificate').getComponentByName('subjectPublicKeyInfo').getComponentByName('subjectPublicKey'))[3:], asn1Spec=RSAPublicKey())[0] #extract binary data
l = 0L
for b in certificate.getComponentByName('tbsCertificate').getComponentByName('subjectPublicKeyInfo').getComponentByName('subjectPublicKey'):
l = (l << 1) | b
rsaKey = decoder.decode(hex(l)[2:-1].decode('hex'), asn1Spec=RSAPublicKey())[0]
return rsaKey.getComponentByName('modulus')._value , rsaKey.getComponentByName('publicExponent')._value return rsaKey.getComponentByName('modulus')._value , rsaKey.getComponentByName('publicExponent')._value

View File

@@ -25,7 +25,7 @@ http://msdn.microsoft.com/en-us/library/cc240508.aspx
from rdpy.core.type import UInt8, UInt16Le, UInt32Le, CompositeType, String, Stream, sizeof, FactoryType, ArrayType from rdpy.core.type import UInt8, UInt16Le, UInt32Le, CompositeType, String, Stream, sizeof, FactoryType, ArrayType
import per, mcs import per, mcs
from rdpy.core.error import InvalidExpectedDataException from rdpy.core.error import InvalidExpectedDataException
import rdpy.core.log as log from rdpy.core import log, x509
t124_02_98_oid = ( 0, 0, 20, 124, 0, 1 ) t124_02_98_oid = ( 0, 0, 20, 124, 0, 1 )
@@ -123,7 +123,7 @@ class Version(object):
class Sequence(object): class Sequence(object):
RNS_UD_SAS_DEL = 0xAA03 RNS_UD_SAS_DEL = 0xAA03
class Encryption(object): class EncryptionMethod(object):
""" """
@summary: Encryption methods supported @summary: Encryption methods supported
@see: http://msdn.microsoft.com/en-us/library/cc240511.aspx @see: http://msdn.microsoft.com/en-us/library/cc240511.aspx
@@ -133,6 +133,17 @@ class Encryption(object):
ENCRYPTION_FLAG_56BIT = 0x00000008 ENCRYPTION_FLAG_56BIT = 0x00000008
FIPS_ENCRYPTION_FLAG = 0x00000010 FIPS_ENCRYPTION_FLAG = 0x00000010
class EncryptionLevel(object):
"""
@summary: level of 'security'
@see: http://msdn.microsoft.com/en-us/library/cc240518.aspx
"""
ENCRYPTION_LEVEL_NONE = 0x00000000
ENCRYPTION_LEVEL_LOW = 0x00000000
ENCRYPTION_LEVEL_CLIENT_COMPATIBLE = 0x00000000
ENCRYPTION_LEVEL_HIGH = 0x00000000
ENCRYPTION_LEVEL_FIPS = 0x00000000
class ChannelOptions(object): class ChannelOptions(object):
""" """
@summary: Channel options @summary: Channel options
@@ -206,7 +217,7 @@ class DataBlock(CompositeType):
def DataBlockFactory(): def DataBlockFactory():
""" """
build settings in accordance of type self.type.value @summary: build settings in accordance of type self.type.value
""" """
for c in [ClientCoreData, ClientSecurityData, ClientNetworkData, ServerCoreData, ServerNetworkData, ServerSecurityData]: for c in [ClientCoreData, ClientSecurityData, ClientNetworkData, ServerCoreData, ServerNetworkData, ServerSecurityData]:
if self.type.value == c._TYPE_: if self.type.value == c._TYPE_:
@@ -224,7 +235,7 @@ class DataBlock(CompositeType):
class ClientCoreData(CompositeType): class ClientCoreData(CompositeType):
""" """
Class that represent core setting of client @summary: Class that represent core setting of client
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx @see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
""" """
_TYPE_ = MessageType.CS_CORE _TYPE_ = MessageType.CS_CORE
@@ -256,7 +267,7 @@ class ClientCoreData(CompositeType):
class ServerCoreData(CompositeType): class ServerCoreData(CompositeType):
""" """
Server side core settings structure @summary: Server side core settings structure
@see: http://msdn.microsoft.com/en-us/library/cc240517.aspx @see: http://msdn.microsoft.com/en-us/library/cc240517.aspx
""" """
_TYPE_ = MessageType.SC_CORE _TYPE_ = MessageType.SC_CORE
@@ -268,19 +279,19 @@ class ServerCoreData(CompositeType):
class ClientSecurityData(CompositeType): class ClientSecurityData(CompositeType):
""" """
Client security setting @summary: Client security setting
@see: http://msdn.microsoft.com/en-us/library/cc240511.aspx @see: http://msdn.microsoft.com/en-us/library/cc240511.aspx
""" """
_TYPE_ = MessageType.CS_SECURITY _TYPE_ = MessageType.CS_SECURITY
def __init__(self, readLen = None): def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen) CompositeType.__init__(self, readLen = readLen)
self.encryptionMethods = UInt32Le(Encryption.ENCRYPTION_FLAG_40BIT) self.encryptionMethods = UInt32Le(EncryptionMethod.ENCRYPTION_FLAG_40BIT | EncryptionMethod.ENCRYPTION_FLAG_56BIT | EncryptionMethod.ENCRYPTION_FLAG_128BIT)
self.extEncryptionMethods = UInt32Le() self.extEncryptionMethods = UInt32Le()
class ServerSecurityData(CompositeType): class ServerSecurityData(CompositeType):
""" """
Server security settings @summary: Server security settings
@see: http://msdn.microsoft.com/en-us/library/cc240518.aspx @see: http://msdn.microsoft.com/en-us/library/cc240518.aspx
""" """
_TYPE_ = MessageType.SC_SECURITY _TYPE_ = MessageType.SC_SECURITY
@@ -314,6 +325,17 @@ class ServerCertificate(CompositeType):
self.certData = FactoryType(CertificateFactory) self.certData = FactoryType(CertificateFactory)
def bin2bn(b):
"""
@summary: convert binary string to bignum
@param b: {str} binary string
@return: {long} bignum
"""
l = 0L
for ch in b:
l = (l<<8) | ord(ch)
return l
class ProprietaryServerCertificate(CompositeType): class ProprietaryServerCertificate(CompositeType):
""" """
@summary: microsoft proprietary certificate @summary: microsoft proprietary certificate
@@ -332,6 +354,13 @@ class ProprietaryServerCertificate(CompositeType):
self.wSignatureBlobLen = UInt16Le(lambda:sizeof(self.SignatureBlob)) self.wSignatureBlobLen = UInt16Le(lambda:sizeof(self.SignatureBlob))
self.SignatureBlob = String(readLen = self.wSignatureBlobLen) self.SignatureBlob = String(readLen = self.wSignatureBlobLen)
def getPublicKey(self):
"""
@return: {Tuple} (modulus, publicExponent)
"""
#reverse because bignum in little endian
return bin2bn(self.PublicKeyBlob.modulus.value[::-1]), self.PublicKeyBlob.pubExp.value
class CertBlob(CompositeType): class CertBlob(CompositeType):
""" """
@summary: certificate blob, contain x509 data @summary: certificate blob, contain x509 data
@@ -355,6 +384,13 @@ class X509CertificateChain(CompositeType):
self.CertBlobArray = ArrayType(CertBlob, readLen = self.NumCertBlobs) self.CertBlobArray = ArrayType(CertBlob, readLen = self.NumCertBlobs)
self.padding = String(readLen = UInt8(lambda:(8 + 4 * self.NumCertBlobs.value))) self.padding = String(readLen = UInt8(lambda:(8 + 4 * self.NumCertBlobs.value)))
def getPublicKey(self):
"""
@return: {Tuple} (modulus, publicExponent)
"""
#last certifcate contain publi key
return x509.extractRSAKey(x509.load(self.CertBlobArray[-1].abCert.value))
class RSAPublicKey(CompositeType): class RSAPublicKey(CompositeType):
""" """
@see: http://msdn.microsoft.com/en-us/library/cc240520.aspx @see: http://msdn.microsoft.com/en-us/library/cc240520.aspx

View File

@@ -25,8 +25,8 @@
from rdpy.core.type import CompositeType, UInt8, UInt16Le, UInt32Le, String, sizeof, FactoryType, ArrayType, Stream from rdpy.core.type import CompositeType, UInt8, UInt16Le, UInt32Le, String, sizeof, FactoryType, ArrayType, Stream
from rdpy.core.error import InvalidExpectedDataException from rdpy.core.error import InvalidExpectedDataException
import rdpy.core.log as log import rdpy.core.log as log
import rc4, sec, gcc import sec, gcc
from rdpy.core import x509 from rdpy.core import x509, rc4
class MessageType(object): class MessageType(object):
""" """

View File

@@ -26,7 +26,7 @@ It exist channel for file system order, audio channel, clipboard etc...
""" """
from rdpy.core.layer import LayerAutomata, IStreamSender, Layer from rdpy.core.layer import LayerAutomata, IStreamSender, Layer
from rdpy.core.type import sizeof, Stream, UInt8, UInt16Le, String from rdpy.core.type import sizeof, Stream, UInt8, UInt16Le, String
from rdpy.core.error import InvalidExpectedDataException, InvalidValue, InvalidSize from rdpy.core.error import InvalidExpectedDataException, InvalidValue, InvalidSize, CallPureVirtualFuntion
from rdpy.protocol.rdp.ber import writeLength from rdpy.protocol.rdp.ber import writeLength
import rdpy.core.log as log import rdpy.core.log as log
@@ -59,22 +59,54 @@ class Channel:
MCS_GLOBAL_CHANNEL = 1003 MCS_GLOBAL_CHANNEL = 1003
MCS_USERCHANNEL_BASE = 1001 MCS_USERCHANNEL_BASE = 1001
class IGCCConfig(object):
"""
@summary: Channel information
"""
def getUserId(self):
"""
@return: {integer} mcs user id
@see: mcs.IGCCConfig
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "getUserId", "IGCCConfig"))
def getChannelId(self):
"""
@return: {integer} return channel id of proxy
@see: mcs.IGCCConfig
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "getChannelId", "IGCCConfig"))
def getGCCClientSettings(self):
"""
@return: {gcc.Settings} mcs layer gcc client settings
@see: mcs.IGCCConfig
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "getGCCClientSettings", "IGCCConfig"))
def getGCCServerSettings(self):
"""
@return: {gcc.Settings} mcs layer gcc server settings
@see: mcs.IGCCConfig
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "getGCCServerSettings", "IGCCConfig"))
class MCSLayer(LayerAutomata): class MCSLayer(LayerAutomata):
""" """
@summary: Multiple Channel Service layer @summary: Multiple Channel Service layer
the main layer of RDP protocol the main layer of RDP protocol
is why he can do everything and more! is why he can do everything and more!
""" """
class MCSProxySender(Layer, IStreamSender): class MCSProxySender(Layer, IStreamSender, IGCCConfig):
""" """
@summary: Proxy use to set as transport layer for upper channel @summary: Proxy use to set as transport layer for upper channel
use to abstract channel id for presentation layer use to abstract channel id for presentation layer
""" """
def __init__(self, presentation, mcs, channelId): def __init__(self, presentation, mcs, channelId):
""" """
@param presentation: presentation layer @param presentation: {Layer} presentation layer
@param mcs: MCS layer use as proxy @param mcs: {MCSLayer} MCS layer use as proxy
@param channelId: channel id for presentation layer @param channelId: {integer} channel id for presentation layer
""" """
Layer.__init__(self, presentation) Layer.__init__(self, presentation)
self._mcs = mcs self._mcs = mcs
@@ -84,6 +116,7 @@ class MCSLayer(LayerAutomata):
""" """
@summary: A send proxy function, use channel id and specific @summary: A send proxy function, use channel id and specific
send function of MCS layer send function of MCS layer
@param data: {type.Type | Tuple}
""" """
self._mcs.send(self._channelId, data) self._mcs.send(self._channelId, data)
@@ -95,35 +128,39 @@ class MCSLayer(LayerAutomata):
def getUserId(self): def getUserId(self):
""" """
@return: mcs user id @return: {integer} mcs user id
@see: mcs.IGCCConfig
""" """
return self._mcs._userId return self._mcs._userId
def getChannelId(self): def getChannelId(self):
""" """
@return: return channel id of proxy @return: {integer} return channel id of proxy
@see: mcs.IGCCConfig
""" """
return self._channelId return self._channelId
def getGCCClientSettings(self): def getGCCClientSettings(self):
""" """
@return: mcs layer gcc client settings @return: {gcc.Settings} mcs layer gcc client settings
@see: mcs.IGCCConfig
""" """
return self._mcs._clientSettings return self._mcs._clientSettings
def getGCCServerSettings(self): def getGCCServerSettings(self):
""" """
@return: mcs layer gcc server settings @return: {gcc.Settings} mcs layer gcc server settings
@see: mcs.IGCCConfig
""" """
return self._mcs._serverSettings return self._mcs._serverSettings
def __init__(self, presentation, receiveOpcode, sendOpcode, virtualChannels = []): def __init__(self, presentation, receiveOpcode, sendOpcode, virtualChannels = []):
""" """
@param presentation: presentation layer @param presentation: {Layer} presentation layer
@param virtualChannels: list additional channels like rdpsnd... [tuple(mcs.ChannelDef, layer)] @param virtualChannels: {Array(Layer]} list additional channels like rdpsnd... [tuple(mcs.ChannelDef, layer)]
@param receiveOpcode: opcode check when receive data @param receiveOpcode: {integer} opcode check when receive data
@param sendOpcode: opcode use when send data @param sendOpcode: {integer} opcode use when send data
""" """
LayerAutomata.__init__(self, presentation) LayerAutomata.__init__(self, presentation)
self._clientSettings = gcc.clientSettings() self._clientSettings = gcc.clientSettings()
@@ -163,8 +200,8 @@ class MCSLayer(LayerAutomata):
def send(self, channelId, data): def send(self, channelId, data):
""" """
@summary: Specific send function for channelId @summary: Specific send function for channelId
@param channelId: Channel use to send @param channelId: {integer} Channel use to send
@param data: message to send @param data: {type.type | tuple} message to send
""" """
self._transport.send((self.writeMCSPDUHeader(UInt8(self._sendOpcode)), self._transport.send((self.writeMCSPDUHeader(UInt8(self._sendOpcode)),
per.writeInteger16(self._userId, Channel.MCS_USERCHANNEL_BASE), per.writeInteger16(self._userId, Channel.MCS_USERCHANNEL_BASE),
@@ -175,7 +212,7 @@ class MCSLayer(LayerAutomata):
def recvData(self, data): def recvData(self, data):
""" """
@summary: Main receive method @summary: Main receive method
@param data: Stream @param data: {Stream}
""" """
opcode = UInt8() opcode = UInt8()
data.readType(opcode) data.readType(opcode)
@@ -208,11 +245,11 @@ class MCSLayer(LayerAutomata):
""" """
@summary: Write a special domain parameter structure @summary: Write a special domain parameter structure
use in connection sequence use in connection sequence
@param maxChannels: number of MCS channel use @param maxChannels: {integer} number of MCS channel use
@param maxUsers: number of MCS user used (1) @param maxUsers: {integer} number of MCS user used (1)
@param maxTokens: unknown @param maxTokens: {integer} unknown
@param maxPduSize: unknown @param maxPduSize: {integer} unknown
@return: domain parameter structure @return: {Tuple(type)} domain parameter structure
""" """
domainParam = (ber.writeInteger(maxChannels), ber.writeInteger(maxUsers), ber.writeInteger(maxTokens), domainParam = (ber.writeInteger(maxChannels), ber.writeInteger(maxUsers), ber.writeInteger(maxTokens),
ber.writeInteger(1), ber.writeInteger(0), ber.writeInteger(1), ber.writeInteger(1), ber.writeInteger(0), ber.writeInteger(1),
@@ -222,25 +259,26 @@ class MCSLayer(LayerAutomata):
def writeMCSPDUHeader(self, mcsPdu, options = 0): def writeMCSPDUHeader(self, mcsPdu, options = 0):
""" """
@summary: Write MCS PDU header @summary: Write MCS PDU header
@param mcsPdu: PDU code @param mcsPdu: {integer} PDU code
@param options: option contains in header @param options: {integer} option contains in header
@return: UInt8 @return: {integer}
""" """
return (mcsPdu << 2) | options return (mcsPdu << 2) | options
def readMCSPDUHeader(self, opcode, mcsPdu): def readMCSPDUHeader(self, opcode, mcsPdu):
""" """
@summary: Read mcsPdu header and return options parameter @summary: Read mcsPdu header and return options parameter
@param opcode: opcode @param opcode: {integer} opcode
@param mcsPdu: mcsPdu will be checked @param mcsPdu: {integer} mcsPdu will be checked
@return: true if opcode is correct @return: {boolean} true if opcode is correct
""" """
return (opcode >> 2) == mcsPdu return (opcode >> 2) == mcsPdu
def readDomainParams(self, s): def readDomainParams(self, s):
""" """
@summary: Read domain parameters structure @summary: Read domain parameters structure
@return: (max_channels, max_users, max_tokens, max_pdu_size) @param s: {Stream}
@return: {Tuple} (max_channels, max_users, max_tokens, max_pdu_size)
""" """
if not ber.readUniversalTag(s, ber.Tag.BER_TAG_SEQUENCE, True): if not ber.readUniversalTag(s, ber.Tag.BER_TAG_SEQUENCE, True):
raise InvalidValue("bad BER tags") raise InvalidValue("bad BER tags")
@@ -261,8 +299,8 @@ class Client(MCSLayer):
""" """
def __init__(self, presentation, virtualChannels = []): def __init__(self, presentation, virtualChannels = []):
""" """
@param presentation: presentation layer @param presentation: {Layer} presentation layer
@param virtualChannels: list additional channels like rdpsnd... [tuple(mcs.ChannelDef, layer)] @param virtualChannels: {Array(Layer)} list additional channels like rdpsnd... [tuple(mcs.ChannelDef, layer)]
""" """
MCSLayer.__init__(self, presentation, DomainMCSPDU.SEND_DATA_INDICATION, DomainMCSPDU.SEND_DATA_REQUEST, virtualChannels) MCSLayer.__init__(self, presentation, DomainMCSPDU.SEND_DATA_INDICATION, DomainMCSPDU.SEND_DATA_REQUEST, virtualChannels)
#use to know state of static channel #use to know state of static channel
@@ -277,9 +315,9 @@ class Client(MCSLayer):
Send ConnectInitial Send ConnectInitial
Wait ConnectResponse Wait ConnectResponse
""" """
self._clientSettings.getBlock(gcc.MessageType.CS_CORE).serverSelectedProtocol.value = self._transport._selectedProtocol self._clientSettings.CS_CORE.serverSelectedProtocol.value = self._transport._selectedProtocol
#ask for virtual channel #ask for virtual channel
self._clientSettings.getBlock(gcc.MessageType.CS_NET).channelDefArray._array = [x for (x, _) in self._virtualChannels] self._clientSettings.CS_NET.channelDefArray._array = [x for (x, _) in self._virtualChannels]
#send connect initial #send connect initial
self.sendConnectInitial() self.sendConnectInitial()
#next wait response #next wait response
@@ -319,7 +357,7 @@ class Client(MCSLayer):
Send Erect domain Request Send Erect domain Request
Send Attach User Request Send Attach User Request
Wait Attach User Confirm Wait Attach User Confirm
@param data: Stream @param data: {Stream}
""" """
ber.readApplicationTag(data, UInt8(Message.MCS_TYPE_CONNECT_RESPONSE)) ber.readApplicationTag(data, UInt8(Message.MCS_TYPE_CONNECT_RESPONSE))
ber.readEnumerated(data) ber.readEnumerated(data)
@@ -343,7 +381,7 @@ class Client(MCSLayer):
""" """
@summary: Receive an attach user confirm @summary: Receive an attach user confirm
Send Connect Channel Send Connect Channel
@param data: Stream @param data: {Stream}
""" """
opcode = UInt8() opcode = UInt8()
data.readType(opcode) data.readType(opcode)
@@ -362,7 +400,7 @@ class Client(MCSLayer):
""" """
@summary: Receive a channel join confirm from server @summary: Receive a channel join confirm from server
client automata function client automata function
@param data: Stream @param data: {Stream}
""" """
opcode = UInt8() opcode = UInt8()
data.readType(opcode) data.readType(opcode)
@@ -423,7 +461,7 @@ class Client(MCSLayer):
""" """
@summary: Send a formated Channel join request from client to server @summary: Send a formated Channel join request from client to server
client automata function client automata function
@param channelId: id of channel requested @param channelId: {integer} id of channel requested
""" """
self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.CHANNEL_JOIN_REQUEST)), self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.CHANNEL_JOIN_REQUEST)),
per.writeInteger16(self._userId, Channel.MCS_USERCHANNEL_BASE), per.writeInteger16(self._userId, Channel.MCS_USERCHANNEL_BASE),
@@ -435,8 +473,8 @@ class Server(MCSLayer):
""" """
def __init__(self, presentation, virtualChannels = []): def __init__(self, presentation, virtualChannels = []):
""" """
@param presentation: presentation layer @param presentation: {Layer} presentation layer
@param virtualChannels: list additional channels like rdpsnd... [tuple(mcs.ChannelDef, layer)] @param virtualChannels: {List(Layer)} list additional channels like rdpsnd... [tuple(mcs.ChannelDef, layer)]
""" """
MCSLayer.__init__(self, presentation, DomainMCSPDU.SEND_DATA_REQUEST, DomainMCSPDU.SEND_DATA_INDICATION, virtualChannels) MCSLayer.__init__(self, presentation, DomainMCSPDU.SEND_DATA_REQUEST, DomainMCSPDU.SEND_DATA_INDICATION, virtualChannels)
#nb channel requested #nb channel requested
@@ -447,7 +485,12 @@ class Server(MCSLayer):
@summary: Connect message for server automata @summary: Connect message for server automata
Wait Connect Initial Wait Connect Initial
""" """
self._serverSettings.getBlock(gcc.MessageType.SC_CORE).clientRequestedProtocol.value = self._transport._requestedProtocol #basic rdp security layer
if self._transport._selectedProtocol == 0:
self._serverSettings.SC_SECURITY.encryptionMethod.value = gcc.EncryptionMethod.ENCRYPTION_FLAG_128BIT
self._serverSettings.SC_SECURITY.encryptionLevel = gcc.EncryptionLevel.ENCRYPTION_LEVEL_HIGH
self._serverSettings.SC_CORE.clientRequestedProtocol.value = self._transport._requestedProtocol
self.setNextState(self.recvConnectInitial) self.setNextState(self.recvConnectInitial)
def recvConnectInitial(self, data): def recvConnectInitial(self, data):
@@ -455,7 +498,7 @@ class Server(MCSLayer):
@summary: Receive MCS connect initial from client @summary: Receive MCS connect initial from client
Send Connect Response Send Connect Response
Wait Erect Domain Request Wait Erect Domain Request
@param data: Stream @param data: {Stream}
""" """
ber.readApplicationTag(data, UInt8(Message.MCS_TYPE_CONNECT_INITIAL)) ber.readApplicationTag(data, UInt8(Message.MCS_TYPE_CONNECT_INITIAL))
ber.readOctetString(data) ber.readOctetString(data)
@@ -485,7 +528,7 @@ class Server(MCSLayer):
""" """
@summary: Receive erect domain request @summary: Receive erect domain request
Wait Attach User Request Wait Attach User Request
@param data: Stream @param data: {Stream}
""" """
opcode = UInt8() opcode = UInt8()
data.readType(opcode) data.readType(opcode)
@@ -503,7 +546,7 @@ class Server(MCSLayer):
@summary: Receive Attach user request @summary: Receive Attach user request
Send Attach User Confirm Send Attach User Confirm
Wait Channel Join Request Wait Channel Join Request
@param data: Stream @param data: {Stream}
""" """
opcode = UInt8() opcode = UInt8()
data.readType(opcode) data.readType(opcode)
@@ -518,7 +561,7 @@ class Server(MCSLayer):
""" """
@summary: Receive for each client channel a request @summary: Receive for each client channel a request
Send Channel Join Confirm or Connect upper layer when all channel are joined Send Channel Join Confirm or Connect upper layer when all channel are joined
@param data: Stream @param data: {Stream}
""" """
opcode = UInt8() opcode = UInt8()
@@ -562,8 +605,8 @@ class Server(MCSLayer):
def sendChannelJoinConfirm(self, channelId, confirm): def sendChannelJoinConfirm(self, channelId, confirm):
""" """
@summary: Send a confirm channel (or not) to client @summary: Send a confirm channel (or not) to client
@param channelId: id of channel @param channelId: {integer} id of channel
@param confirm: connection state @param confirm: {boolean} connection state
""" """
self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.CHANNEL_JOIN_CONFIRM), 2), self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.CHANNEL_JOIN_CONFIRM), 2),
per.writeEnumerates(int(confirm)), per.writeEnumerates(int(confirm)),

View File

@@ -359,12 +359,12 @@ class PointerCapability(CompositeType):
""" """
_TYPE_ = CapsType.CAPSTYPE_POINTER _TYPE_ = CapsType.CAPSTYPE_POINTER
def __init__(self, readLen = None): def __init__(self, isServer = False, readLen = None):
CompositeType.__init__(self, readLen = readLen) CompositeType.__init__(self, readLen = readLen)
self.colorPointerFlag = UInt16Le() self.colorPointerFlag = UInt16Le()
self.colorPointerCacheSize = UInt16Le(20) self.colorPointerCacheSize = UInt16Le(20)
#old version of rdp doesn't support ... #old version of rdp doesn't support ...
#self.pointerCacheSize = UInt16Le() self.pointerCacheSize = UInt16Le(conditional = lambda:isServer)
class InputCapability(CompositeType): class InputCapability(CompositeType):
""" """

View File

@@ -26,7 +26,6 @@ In this layer are managed all mains bitmap update orders end user inputs
from rdpy.core.layer import LayerAutomata from rdpy.core.layer import LayerAutomata
from rdpy.core.error import CallPureVirtualFuntion from rdpy.core.error import CallPureVirtualFuntion
import rdpy.core.log as log import rdpy.core.log as log
import rdpy.protocol.rdp.gcc as gcc
import rdpy.protocol.rdp.tpkt as tpkt import rdpy.protocol.rdp.tpkt as tpkt
import data, caps import data, caps
@@ -82,7 +81,7 @@ class PDULayer(LayerAutomata, tpkt.IFastPathListener):
caps.CapsType.CAPSTYPE_GENERAL : caps.Capability(caps.GeneralCapability()), caps.CapsType.CAPSTYPE_GENERAL : caps.Capability(caps.GeneralCapability()),
caps.CapsType.CAPSTYPE_BITMAP : caps.Capability(caps.BitmapCapability()), caps.CapsType.CAPSTYPE_BITMAP : caps.Capability(caps.BitmapCapability()),
caps.CapsType.CAPSTYPE_ORDER : caps.Capability(caps.OrderCapability()), caps.CapsType.CAPSTYPE_ORDER : caps.Capability(caps.OrderCapability()),
caps.CapsType.CAPSTYPE_POINTER : caps.Capability(caps.PointerCapability()), caps.CapsType.CAPSTYPE_POINTER : caps.Capability(caps.PointerCapability(isServer = True)),
caps.CapsType.CAPSTYPE_INPUT : caps.Capability(caps.InputCapability()), caps.CapsType.CAPSTYPE_INPUT : caps.Capability(caps.InputCapability()),
caps.CapsType.CAPSTYPE_VIRTUALCHANNEL : caps.Capability(caps.VirtualChannelCapability()), caps.CapsType.CAPSTYPE_VIRTUALCHANNEL : caps.Capability(caps.VirtualChannelCapability()),
caps.CapsType.CAPSTYPE_FONT : caps.Capability(caps.FontCapability()), caps.CapsType.CAPSTYPE_FONT : caps.Capability(caps.FontCapability()),
@@ -120,7 +119,7 @@ class PDULayer(LayerAutomata, tpkt.IFastPathListener):
@summary: Send a PDU data to transport layer @summary: Send a PDU data to transport layer
@param pduMessage: PDU message @param pduMessage: PDU message
""" """
self._transport.send(data.PDU(self._transport._transport.getUserId(), pduMessage)) self._transport.send(data.PDU(self._transport.getUserId(), pduMessage))
def sendDataPDU(self, pduData): def sendDataPDU(self, pduData):
""" """
@@ -144,7 +143,7 @@ class Client(PDULayer):
""" """
@summary: Connect message in client automata @summary: Connect message in client automata
""" """
self._gccCore = self._transport._transport.getGCCClientSettings().CS_CORE self._gccCore = self._transport.getGCCClientSettings().CS_CORE
self.setNextState(self.recvDemandActivePDU) self.setNextState(self.recvDemandActivePDU)
#check if client support fast path message #check if client support fast path message
self._clientFastPathSupported = False self._clientFastPathSupported = False
@@ -299,7 +298,7 @@ class Client(PDULayer):
""" """
@summary: Read an update data PDU data @summary: Read an update data PDU data
dispatch update data dispatch update data
@param: UpdateDataPDU object @param: {UpdateDataPDU} object
""" """
if updateDataPDU.updateType.value == data.UpdateType.UPDATETYPE_BITMAP: if updateDataPDU.updateType.value == data.UpdateType.UPDATETYPE_BITMAP:
self._listener.onUpdate(updateDataPDU.updateData.rectangles._array) self._listener.onUpdate(updateDataPDU.updateData.rectangles._array)
@@ -345,7 +344,7 @@ class Client(PDULayer):
""" """
@summary: send a synchronize PDU from client to server @summary: send a synchronize PDU from client to server
""" """
synchronizePDU = data.SynchronizeDataPDU(self._transport._transport.getChannelId()) synchronizePDU = data.SynchronizeDataPDU(self._transport.getChannelId())
self.sendDataPDU(synchronizePDU) self.sendDataPDU(synchronizePDU)
#ask for cooperation #ask for cooperation
@@ -364,7 +363,7 @@ class Client(PDULayer):
def sendInputEvents(self, pointerEvents): def sendInputEvents(self, pointerEvents):
""" """
send client input events @summary: send client input events
@param pointerEvents: list of pointer events @param pointerEvents: list of pointer events
""" """
pdu = data.ClientInputEventPDU() pdu = data.ClientInputEventPDU()
@@ -373,7 +372,7 @@ class Client(PDULayer):
class Server(PDULayer): class Server(PDULayer):
""" """
Server Automata of PDU layer @summary: Server Automata of PDU layer
""" """
def __init__(self, listener): def __init__(self, listener):
""" """
@@ -386,14 +385,14 @@ class Server(PDULayer):
def connect(self): def connect(self):
""" """
Connect message for server automata @summary: Connect message for server automata
""" """
self.sendDemandActivePDU() self.sendDemandActivePDU()
self.setNextState(self.recvConfirmActivePDU) self.setNextState(self.recvConfirmActivePDU)
def recvConfirmActivePDU(self, s): def recvConfirmActivePDU(self, s):
""" """
Receive confirm active PDU from client @summary: Receive confirm active PDU from client
Capabilities exchange Capabilities exchange
Wait Client Synchronize PDU Wait Client Synchronize PDU
@param s: Stream @param s: Stream
@@ -417,7 +416,7 @@ class Server(PDULayer):
def recvClientSynchronizePDU(self, s): def recvClientSynchronizePDU(self, s):
""" """
Receive from client @summary: Receive from client
Wait Control Cooperate PDU Wait Control Cooperate PDU
@param s: Stream from transport layer @param s: Stream from transport layer
""" """
@@ -432,7 +431,7 @@ class Server(PDULayer):
def recvClientControlCooperatePDU(self, s): def recvClientControlCooperatePDU(self, s):
""" """
Receive control cooperate PDU from client @summary: Receive control cooperate PDU from client
Wait Control Request PDU Wait Control Request PDU
@param s: Stream from transport layer @param s: Stream from transport layer
""" """
@@ -447,7 +446,7 @@ class Server(PDULayer):
def recvClientControlRequestPDU(self, s): def recvClientControlRequestPDU(self, s):
""" """
Receive last control PDU the request control PDU from client @summary: Receive last control PDU the request control PDU from client
Wait Font List PDU Wait Font List PDU
@param s: Stream from transport layer @param s: Stream from transport layer
""" """
@@ -462,7 +461,7 @@ class Server(PDULayer):
def recvClientFontListPDU(self, s): def recvClientFontListPDU(self, s):
""" """
Last synchronize packet from client to server @summary: Last synchronize packet from client to server
Send Server Finalize PDUs Send Server Finalize PDUs
Wait any PDU Wait any PDU
@param s: Stream from transport layer @param s: Stream from transport layer
@@ -483,7 +482,7 @@ class Server(PDULayer):
def recvPDU(self, s): def recvPDU(self, s):
""" """
Main receive function after connection sequence @summary: Main receive function after connection sequence
@param s: Stream from transport layer @param s: Stream from transport layer
""" """
pdu = data.PDU() pdu = data.PDU()
@@ -493,24 +492,25 @@ class Server(PDULayer):
def readDataPDU(self, dataPDU): def readDataPDU(self, dataPDU):
""" """
read a data PDU object @summary: read a data PDU object
@param dataPDU: DataPDU object @param dataPDU: DataPDU object
""" """
if dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SET_ERROR_INFO_PDU: if dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SET_ERROR_INFO_PDU:
errorMessage = "Unknown code %s"%hex(dataPDU.pduData.errorInfo.value) errorMessage = "Unknown code %s"%hex(dataPDU.pduData.errorInfo.value)
if data.ErrorInfo._MESSAGES_.has_key(dataPDU.pduData.errorInfo): if data.ErrorInfo._MESSAGES_.has_key(dataPDU.pduData.errorInfo):
errorMessage = data.ErrorInfo._MESSAGES_[dataPDU.pduData.errorInfo] errorMessage = data.ErrorInfo._MESSAGES_[dataPDU.pduData.errorInfo]
log.error("INFO PDU : %s"%errorMessage) log.error("INFO PDU : %s"%errorMessage)
elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_INPUT: elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_INPUT:
self._listener.onSlowPathInput(dataPDU.pduData.slowPathInputEvents._array) self._listener.onSlowPathInput(dataPDU.pduData.slowPathInputEvents._array)
elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SHUTDOWN_REQUEST: elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SHUTDOWN_REQUEST:
log.debug("Receive Shutdown Request") log.debug("Receive Shutdown Request")
self._transport.close() self._transport.close()
def recvFastPath(self, fastPathS): def recvFastPath(self, fastPathS):
""" """
Implement IFastPathListener interface @summary: Implement IFastPathListener interface
Fast path is needed by RDP 8.0 Fast path is needed by RDP 8.0
@param fastPathS: Stream that contain fast path data @param fastPathS: Stream that contain fast path data
""" """
@@ -536,9 +536,9 @@ class Server(PDULayer):
def sendServerFinalizeSynchronizePDU(self): def sendServerFinalizeSynchronizePDU(self):
""" """
Send last synchronize packet from server to client @summary: Send last synchronize packet from server to client
""" """
synchronizePDU = data.SynchronizeDataPDU(self._transport._transport.getChannelId()) synchronizePDU = data.SynchronizeDataPDU(self._transport.getChannelId())
self.sendDataPDU(synchronizePDU) self.sendDataPDU(synchronizePDU)
#ask for cooperation #ask for cooperation
@@ -557,7 +557,7 @@ class Server(PDULayer):
def sendPDU(self, pduMessage): def sendPDU(self, pduMessage):
""" """
Send a PDU data to transport layer @summary: Send a PDU data to transport layer
@param pduMessage: PDU message @param pduMessage: PDU message
""" """
PDULayer.sendPDU(self, pduMessage) PDULayer.sendPDU(self, pduMessage)
@@ -568,7 +568,7 @@ class Server(PDULayer):
def sendBitmapUpdatePDU(self, bitmapDatas): def sendBitmapUpdatePDU(self, bitmapDatas):
""" """
Send bitmap update data @summary: Send bitmap update data
@param bitmapDatas: List of data.BitmapData @param bitmapDatas: List of data.BitmapData
""" """
#check bitmap header for client that want it (very old client) #check bitmap header for client that want it (very old client)

View File

@@ -342,7 +342,10 @@ class RDPServerController(pdu.layer.PDUServerListener):
#transport pdu layer #transport pdu layer
self._x224Layer = x224.Server(self._mcsLayer, privateKeyFileName, certificateFileName) self._x224Layer = x224.Server(self._mcsLayer, privateKeyFileName, certificateFileName)
#transport packet (protocol layer) #transport packet (protocol layer)
self._tpktLayer = tpkt.TPKT(self._x224Layer, self._pduLayer) self._tpktLayer = tpkt.TPKT(self._x224Layer)
#fastpath stack
self._pduLayer.initFastPath(self._secLayer)
self._secLayer.initFastPath(self._tpktLayer)
#set color depth of session #set color depth of session
self.setColorDepth(colorDepth) self.setColorDepth(colorDepth)

View File

@@ -21,12 +21,12 @@
Some use full methods for security in RDP Some use full methods for security in RDP
""" """
import sha, md5, rsa, rc4 import sha, md5, rsa
import gcc, lic, tpkt import gcc, lic, tpkt, mcs
from rdpy.core.type import CompositeType, Stream, UInt32Le, UInt16Le, String, sizeof, UInt8 from rdpy.core.type import CompositeType, Stream, UInt32Le, UInt16Le, String, sizeof, UInt8
from rdpy.core.layer import LayerAutomata, IStreamSender from rdpy.core.layer import LayerAutomata, IStreamSender
from rdpy.core.error import InvalidExpectedDataException from rdpy.core.error import InvalidExpectedDataException
from rdpy.core import log, x509 from rdpy.core import log, x509, rc4
class SecurityFlag(object): class SecurityFlag(object):
""" """
@@ -235,13 +235,13 @@ def generateKeys(clientRandom, serverRandom, method):
initialSecondKey128 = finalHash(sessionKey[32:48], clientRandom, serverRandom) initialSecondKey128 = finalHash(sessionKey[32:48], clientRandom, serverRandom)
#generate valid key #generate valid key
if method == gcc.Encryption.ENCRYPTION_FLAG_40BIT: if method == gcc.EncryptionMethod.ENCRYPTION_FLAG_40BIT:
return gen40bits(macKey128), gen40bits(initialFirstKey128), gen40bits(initialSecondKey128) return gen40bits(macKey128), gen40bits(initialFirstKey128), gen40bits(initialSecondKey128)
elif method == gcc.Encryption.ENCRYPTION_FLAG_56BIT: elif method == gcc.EncryptionMethod.ENCRYPTION_FLAG_56BIT:
return gen56bits(macKey128), gen56bits(initialFirstKey128), gen56bits(initialSecondKey128) return gen56bits(macKey128), gen56bits(initialFirstKey128), gen56bits(initialSecondKey128)
elif method == gcc.Encryption.ENCRYPTION_FLAG_128BIT: elif method == gcc.EncryptionMethod.ENCRYPTION_FLAG_128BIT:
return macKey128, initialFirstKey128, initialSecondKey128 return macKey128, initialFirstKey128, initialSecondKey128
raise InvalidExpectedDataException("Bad encryption method") raise InvalidExpectedDataException("Bad encryption method")
@@ -255,29 +255,18 @@ def updateKey(initialKey, currentKey, method):
@see: http://msdn.microsoft.com/en-us/library/cc240792.aspx @see: http://msdn.microsoft.com/en-us/library/cc240792.aspx
""" """
#generate valid key #generate valid key
if method == gcc.Encryption.ENCRYPTION_FLAG_40BIT: if method == gcc.EncryptionMethod.ENCRYPTION_FLAG_40BIT:
tempKey128 = tempKey(initialKey[:8], currentKey[:8]) tempKey128 = tempKey(initialKey[:8], currentKey[:8])
return gen40bits(rc4.crypt(rc4.RC4Key(tempKey128[:8]), tempKey128[:8])) return gen40bits(rc4.crypt(rc4.RC4Key(tempKey128[:8]), tempKey128[:8]))
elif method == gcc.Encryption.ENCRYPTION_FLAG_56BIT: elif method == gcc.EncryptionMethod.ENCRYPTION_FLAG_56BIT:
tempKey128 = tempKey(initialKey[:8], currentKey[:8]) tempKey128 = tempKey(initialKey[:8], currentKey[:8])
return gen56bits(rc4.crypt(rc4.RC4Key(tempKey128[:8]), tempKey128[:8])) return gen56bits(rc4.crypt(rc4.RC4Key(tempKey128[:8]), tempKey128[:8]))
elif method == gcc.Encryption.ENCRYPTION_FLAG_128BIT: elif method == gcc.EncryptionMethod.ENCRYPTION_FLAG_128BIT:
tempKey128 = tempKey(initialKey, currentKey) tempKey128 = tempKey(initialKey, currentKey)
return rc4.crypt(rc4.RC4Key(tempKey128), tempKey128) return rc4.crypt(rc4.RC4Key(tempKey128), tempKey128)
def bin2bn(b):
"""
@summary: convert binary string to bignum
@param b: {str} binary string
@return: {long} bignum
"""
l = 0L
for ch in b:
l = (l<<8) | ord(ch)
return l
class ClientSecurityExchangePDU(CompositeType): class ClientSecurityExchangePDU(CompositeType):
""" """
@summary: contain client random for basic security @summary: contain client random for basic security
@@ -332,7 +321,7 @@ class RDPExtendedInfo(CompositeType):
self.clientSessionId = UInt32Le() self.clientSessionId = UInt32Le()
self.performanceFlags = UInt32Le() self.performanceFlags = UInt32Le()
class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastPathSender): class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastPathSender, mcs.IGCCConfig):
""" """
@summary: Standard RDP security layer @summary: Standard RDP security layer
This layer is Transparent as possible for upper layer This layer is Transparent as possible for upper layer
@@ -347,7 +336,7 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
self._fastPathPresentation = None self._fastPathPresentation = None
#credentials #credentials
self._info = RDPInfo(extendedInfoConditional = lambda:(self._transport.getGCCServerSettings().SC_CORE.rdpVersion.value == gcc.Version.RDP_VERSION_5_PLUS)) self._info = RDPInfo(extendedInfoConditional = lambda:(self.getGCCServerSettings().SC_CORE.rdpVersion.value == gcc.Version.RDP_VERSION_5_PLUS))
#True if classic encryption is enable #True if classic encryption is enable
self._enableEncryption = False self._enableEncryption = False
@@ -378,7 +367,7 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
if self._nbDecryptedPacket == 4096: if self._nbDecryptedPacket == 4096:
log.info("update decrypt key") log.info("update decrypt key")
self._currentDecrytKey = updateKey( self._initialDecrytKey, self._currentDecrytKey, self._currentDecrytKey = updateKey( self._initialDecrytKey, self._currentDecrytKey,
self._transport.getGCCServerSettings().SC_SECURITY.encryptionMethod.value) self.getGCCServerSettings().SC_SECURITY.encryptionMethod.value)
self._decryptRc4 = rc4.RC4Key(self._currentDecrytKey) self._decryptRc4 = rc4.RC4Key(self._currentDecrytKey)
self._nbDecryptedPacket = 0 self._nbDecryptedPacket = 0
@@ -405,7 +394,7 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
if self._nbEncryptedPacket == 4096: if self._nbEncryptedPacket == 4096:
log.info("update encrypt key") log.info("update encrypt key")
self._currentEncryptKey = updateKey( self._initialEncryptKey, self._currentEncryptKey, self._currentEncryptKey = updateKey( self._initialEncryptKey, self._currentEncryptKey,
self._transport.getGCCServerSettings().SC_SECURITY.encryptionMethod.value) self.getGCCServerSettings().SC_SECURITY.encryptionMethod.value)
self._encryptRc4 = rc4.RC4Key(self._currentEncryptKey) self._encryptRc4 = rc4.RC4Key(self._currentEncryptKey)
self._nbEncryptedPacket = 0 self._nbEncryptedPacket = 0
@@ -492,6 +481,34 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
""" """
self._fastPathTransport = fastPathSender self._fastPathTransport = fastPathSender
def getUserId(self):
"""
@return: {integer} mcs user id
@see: mcs.IGCCConfig
"""
return self._transport.getUserId()
def getChannelId(self):
"""
@return: {integer} return channel id of proxy
@see: mcs.IGCCConfig
"""
return self._transport.getChannelId()
def getGCCClientSettings(self):
"""
@return: {gcc.Settings} mcs layer gcc client settings
@see: mcs.IGCCConfig
"""
return self._transport.getGCCClientSettings()
def getGCCServerSettings(self):
"""
@return: {gcc.Settings} mcs layer gcc server settings
@see: mcs.IGCCConfig
"""
return self._transport.getGCCServerSettings()
class Client(SecLayer): class Client(SecLayer):
""" """
@summary: Client side of security layer @summary: Client side of security layer
@@ -502,41 +519,20 @@ class Client(SecLayer):
def connect(self): def connect(self):
""" """
@summary: send client random @summary: send client random if needed and send info packet
""" """
self._enableEncryption = self.getGCCClientSettings().CS_CORE.serverSelectedProtocol == 0
self._enableEncryption = self._transport.getGCCClientSettings().CS_CORE.serverSelectedProtocol == 0
if self._enableEncryption: if self._enableEncryption:
#generate client random self.sendClientRandom()
clientRandom = rsa.randnum.read_random_bits(256)
self._macKey, self._initialDecrytKey, self._initialEncryptKey = generateKeys( clientRandom,
self._transport.getGCCServerSettings().SC_SECURITY.serverRandom.value,
self._transport.getGCCServerSettings().SC_SECURITY.encryptionMethod.value)
#initialize keys
self._currentDecrytKey = self._initialDecrytKey
self._currentEncryptKey = self._initialEncryptKey
self._decryptRc4 = rc4.RC4Key(self._currentDecrytKey)
self._encryptRc4 = rc4.RC4Key(self._currentEncryptKey)
#send client random encrypted with self.sendInfoPkt()
certificate = self._transport.getGCCServerSettings().SC_SECURITY.serverCertificate.certData._value
if isinstance(certificate, gcc.ProprietaryServerCertificate):
modulus = bin2bn(certificate.PublicKeyBlob.modulus.value[::-1])
publicExponent = certificate.PublicKeyBlob.pubExp.value
elif isinstance(certificate, gcc.X509CertificateChain):
modulus, publicExponent = x509.extractRSAKey(x509.load(certificate.CertBlobArray[-1].abCert.value))
else:
raise InvalidExpectedDataException("unknown certificate type")
#reverse because bignum in little endian
serverPublicKey = rsa.PublicKey(modulus, publicExponent)
message = ClientSecurityExchangePDU()
#reverse because bignum in little endian
message.encryptedClientRandom.value = rsa.encrypt(clientRandom[::-1], serverPublicKey)[::-1]
self.sendFlagged(SecurityFlag.SEC_EXCHANGE_PKT, message)
def sendInfoPkt(self):
"""
@summary: send information packet (with credentials)
next state -> recvLicenceInfo
"""
secFlag = SecurityFlag.SEC_INFO_PKT secFlag = SecurityFlag.SEC_INFO_PKT
if self._enableEncryption: if self._enableEncryption:
secFlag |= SecurityFlag.SEC_ENCRYPT secFlag |= SecurityFlag.SEC_ENCRYPT
@@ -544,6 +540,29 @@ class Client(SecLayer):
self.setNextState(self.recvLicenceInfo) self.setNextState(self.recvLicenceInfo)
def sendClientRandom(self):
"""
@summary: generate and send client random and init session keys
"""
#generate client random
clientRandom = rsa.randnum.read_random_bits(256)
self._macKey, self._initialDecrytKey, self._initialEncryptKey = generateKeys( clientRandom,
self.getGCCServerSettings().SC_SECURITY.serverRandom.value,
self.getGCCServerSettings().SC_SECURITY.encryptionMethod.value)
#initialize keys
self._currentDecrytKey = self._initialDecrytKey
self._currentEncryptKey = self._initialEncryptKey
self._decryptRc4 = rc4.RC4Key(self._currentDecrytKey)
self._encryptRc4 = rc4.RC4Key(self._currentEncryptKey)
#send client random encrypted with
modulus, publicExponent = self.getGCCServerSettings().SC_SECURITY.serverCertificate.certData.getPublicKey()
serverPublicKey = rsa.PublicKey(modulus, publicExponent)
message = ClientSecurityExchangePDU()
#reverse because bignum in little endian
message.encryptedClientRandom.value = rsa.encrypt(clientRandom[::-1], serverPublicKey)[::-1]
self.sendFlagged(SecurityFlag.SEC_EXCHANGE_PKT, message)
def recvLicenceInfo(self, s): def recvLicenceInfo(self, s):
""" """
@summary: Read license info packet and check if is a valid client info @summary: Read license info packet and check if is a valid client info
@@ -574,7 +593,20 @@ class Server(SecLayer):
""" """
@summary: init automata to wait info packet @summary: init automata to wait info packet
""" """
self.setNextState(self.recvInfoPkt) self._enableEncryption = self.getGCCClientSettings().CS_CORE.serverSelectedProtocol == 0
if self._enableEncryption:
self.setNextState(self.recvClientRandom)
else:
self.setNextState(self.recvInfoPkt)
def recvClientRandom(self, s):
"""
@summary: receive client random and generate session keys
@param s: {Stream}
"""
message = ClientSecurityExchangePDU()
s.readType(message)
def recvInfoPkt(self, s): def recvInfoPkt(self, s):
""" """

View File

@@ -76,8 +76,8 @@ class IFastPathSender(object):
def sendFastPath(self, secFlag, fastPathS): def sendFastPath(self, secFlag, fastPathS):
""" """
@summary: Send fastPathS Type as fast path packet @summary: Send fastPathS Type as fast path packet
@param secFlag: {SecFlags} @param secFlag: {integer} Security flag for fastpath packet
@param fastPathS: type transform to stream and send as fastpath @param fastPathS: {Type | Tuple} type transform to stream and send as fastpath
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendFastPath", "IFastPathSender")) raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendFastPath", "IFastPathSender"))
@@ -103,7 +103,7 @@ class TPKT(RawLayer, IFastPathSender):
""" """
def __init__(self, presentation): def __init__(self, presentation):
""" """
@param presentation: presentation layer, in RDP case is x224 layer @param presentation: {Layer} presentation layer, in RDP case is x224 layer
""" """
RawLayer.__init__(self, presentation) RawLayer.__init__(self, presentation)
#length may be coded on more than 1 bytes #length may be coded on more than 1 bytes
@@ -133,8 +133,8 @@ class TPKT(RawLayer, IFastPathSender):
def readHeader(self, data): def readHeader(self, data):
""" """
Read header of TPKT packet @summary: Read header of TPKT packet
@param data: Stream received from twisted layer @param data: {Stream} received from twisted layer
""" """
#first read packet version #first read packet version
version = UInt8() version = UInt8()
@@ -158,8 +158,8 @@ class TPKT(RawLayer, IFastPathSender):
def readExtendedHeader(self, data): def readExtendedHeader(self, data):
""" """
Header may be on 4 bytes @summary: Header may be on 4 bytes
@param data: Stream from twisted layer @param data: {Stream} from twisted layer
""" """
#next state is read data #next state is read data
size = UInt16Be() size = UInt16Be()
@@ -168,8 +168,8 @@ class TPKT(RawLayer, IFastPathSender):
def readExtendedFastPathHeader(self, data): def readExtendedFastPathHeader(self, data):
""" """
Fast path header may be on 1 byte more @summary: Fast path header may be on 1 byte more
@param data: Stream from twisted layer @param data: {Stream} from twisted layer
""" """
leftPart = UInt8() leftPart = UInt8()
data.readType(leftPart) data.readType(leftPart)
@@ -180,16 +180,16 @@ class TPKT(RawLayer, IFastPathSender):
def readFastPath(self, data): def readFastPath(self, data):
""" """
Fast path data @summary: Fast path data
@param data: Stream from twisted layer @param data: {Stream} from twisted layer
""" """
self._fastPathListener.recvFastPath(self._secFlag, data) self._fastPathListener.recvFastPath(self._secFlag, data)
self.expect(2, self.readHeader) self.expect(2, self.readHeader)
def readData(self, data): def readData(self, data):
""" """
Read classic TPKT packet, last state in tpkt automata @summary: Read classic TPKT packet, last state in tpkt automata
@param data: Stream with correct size @param data: {Stream} with correct size
""" """
#next state is pass to #next state is pass to
self._presentation.recv(data) self._presentation.recv(data)
@@ -197,14 +197,14 @@ class TPKT(RawLayer, IFastPathSender):
def send(self, message): def send(self, message):
""" """
Send encompassed data @summary: Send encompassed data
@param message: network.Type message to send @param message: {network.Type} message to send
""" """
RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_X224), UInt8(0), UInt16Be(sizeof(message) + 4), message)) RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_X224), UInt8(0), UInt16Be(sizeof(message) + 4), message))
def sendFastPath(self, secFlag, fastPathS): def sendFastPath(self, secFlag, fastPathS):
""" """
@param fastPathS: type transform to stream and send as fastpath @param fastPathS: type transform to stream and send as fastpath
@param secFlag: {SecFlags} @param secFlag: {integer} Security flag for fastpath packet
""" """
RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_FASTPATH | secFlag), UInt16Be((sizeof(fastPathS) + 3) | 0x8000), fastPathS)) RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_FASTPATH | secFlag), UInt16Be((sizeof(fastPathS) + 3) | 0x8000), fastPathS))

View File

@@ -130,9 +130,8 @@ class X224Layer(LayerAutomata, IStreamSender):
@param presentation: upper layer, MCS layer in RDP case @param presentation: upper layer, MCS layer in RDP case
""" """
LayerAutomata.__init__(self, presentation) LayerAutomata.__init__(self, presentation)
#default selectedProtocol is SSl
#client requested selectedProtocol #client requested selectedProtocol
self._requestedProtocol = Protocols.PROTOCOL_RDP self._requestedProtocol = Protocols.PROTOCOL_RDP | Protocols.PROTOCOL_SSL
#server selected selectedProtocol #server selected selectedProtocol
self._selectedProtocol = Protocols.PROTOCOL_SSL self._selectedProtocol = Protocols.PROTOCOL_SSL