finish 128 bit basic rdp security layer

This commit is contained in:
speyrefitte
2014-12-10 18:32:10 +01:00
parent 47a9f75fa6
commit f3a3ad8ac3
10 changed files with 175 additions and 80 deletions

View File

@@ -34,7 +34,7 @@ h221_sc_key = "McDn";
class MessageType(object):
"""
Server to Client block
@summary: Server to Client block
GCC conference messages
@see: http://msdn.microsoft.com/en-us/library/cc240509.aspx
"""
@@ -52,7 +52,7 @@ class MessageType(object):
class ColorDepth(object):
"""
Depth color
@summary: Depth color
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
"""
RNS_UD_COLOR_8BPP = 0xCA01
@@ -62,7 +62,7 @@ class ColorDepth(object):
class HighColor(object):
"""
High color of client
@summary: High color of client
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
"""
HIGH_COLOR_4BPP = 0x0004
@@ -73,7 +73,7 @@ class HighColor(object):
class Support(object):
"""
Supported depth flag
@summary: Supported depth flag
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
"""
RNS_UD_24BPP_SUPPORT = 0x0001
@@ -83,7 +83,7 @@ class Support(object):
class CapabilityFlags(object):
"""
For more details on each flags click above
@summary: For more details on each flags click above
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
"""
RNS_UD_CS_SUPPORT_ERRINFO_PDU = 0x0001
@@ -100,7 +100,7 @@ class CapabilityFlags(object):
class ConnectionType(object):
"""
This information is correct if
@summary: This information is correct if
RNS_UD_CS_VALID_CONNECTION_TYPE flag is set on capabilityFlag
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
"""
@@ -114,7 +114,7 @@ class ConnectionType(object):
class Version(object):
"""
Supported version of RDP
@summary: Supported version of RDP
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
"""
RDP_VERSION_4 = 0x00080001
@@ -125,7 +125,7 @@ class Sequence(object):
class Encryption(object):
"""
Encryption methods supported
@summary: Encryption methods supported
@see: http://msdn.microsoft.com/en-us/library/cc240511.aspx
"""
ENCRYPTION_FLAG_40BIT = 0x00000001
@@ -135,7 +135,7 @@ class Encryption(object):
class ChannelOptions(object):
"""
Channel options
@summary: Channel options
@see: http://msdn.microsoft.com/en-us/library/cc240513.aspx
"""
CHANNEL_OPTION_INITIALIZED = 0x80000000
@@ -152,8 +152,8 @@ class ChannelOptions(object):
class KeyboardType(object):
"""
Keyboard type
IBM_101_102_KEYS is the most common keyboard type
@summary: Keyboard type
@see: IBM_101_102_KEYS is the most common keyboard type
"""
IBM_PC_XT_83_KEY = 0x00000001
OLIVETTI = 0x00000002
@@ -165,7 +165,7 @@ class KeyboardType(object):
class KeyboardLayout(object):
"""
Keyboard layout definition
@summary: Keyboard layout definition
@see: http://technet.microsoft.com/en-us/library/cc766503%28WS.10%29.aspx
"""
ARABIC = 0x00000401
@@ -197,7 +197,7 @@ class CertificateType(object):
class DataBlock(CompositeType):
"""
Block settings
@summary: Block settings
"""
def __init__(self, dataBlock = None):
CompositeType.__init__(self)

View File

@@ -275,6 +275,7 @@ class LicenseManager(object):
sessionKeyBlob = sec.generateMicrosoftKeyABBCCC(masterSecret, self._serverRandom, self._clientRandom)
self._macSalt = sessionKeyBlob[:16]
self._licenseKey = sec.finalHash(sessionKeyBlob[16:32], self._clientRandom, self._serverRandom)
self._rc4LicenseKey = rc4.RC4Key(self._licenseKey)
def recv(self, s):
"""
@@ -324,7 +325,7 @@ class LicenseManager(object):
"""
#decrypt server challenge
#it should be TEST word in unicode format
serverChallenge = rc4.crypt(self._licenseKey, self._serverEncryptedChallenge)
serverChallenge = rc4.crypt(self._rc4LicenseKey, self._serverEncryptedChallenge)
#generate hwid
s = Stream()
@@ -333,7 +334,7 @@ class LicenseManager(object):
message = ClientPLatformChallengeResponse()
message.encryptedPlatformChallengeResponse.blobData.value = self._serverEncryptedChallenge
message.encryptedHWID.blobData.value = rc4.crypt(self._licenseKey, hwid)
message.encryptedHWID.blobData.value = rc4.crypt(self._rc4LicenseKey, hwid)
message.MACData.value = sec.macData(self._macSalt, serverChallenge + hwid)
self._transport.sendFlagged(sec.SecurityFlag.SEC_LICENSE_PKT, LicPacket(message))

View File

@@ -362,8 +362,9 @@ class PointerCapability(CompositeType):
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.colorPointerFlag = UInt16Le()
self.colorPointerCacheSize = UInt16Le()
self.pointerCacheSize = UInt16Le()
self.colorPointerCacheSize = UInt16Le(20)
#old version of rdp doesn't support ...
#self.pointerCacheSize = UInt16Le()
class InputCapability(CompositeType):
"""

View File

@@ -24,8 +24,7 @@ In this layer are managed all mains bitmap update orders end user inputs
"""
from rdpy.core.layer import LayerAutomata
from rdpy.core.error import InvalidExpectedDataException, CallPureVirtualFuntion
from rdpy.core.type import UInt16Le
from rdpy.core.error import CallPureVirtualFuntion
import rdpy.core.log as log
import rdpy.protocol.rdp.gcc as gcc
import rdpy.protocol.rdp.tpkt as tpkt
@@ -71,7 +70,7 @@ class PDUServerListener(object):
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onSlowPathInput", "PDUServerListener"))
class PDULayer(LayerAutomata):
class PDULayer(LayerAutomata, tpkt.IFastPathListener):
"""
@summary: Global channel for MCS that handle session
identification user, licensing management, and capabilities exchange
@@ -106,6 +105,15 @@ class PDULayer(LayerAutomata):
}
#share id between client and server
self._shareId = 0x103EA
#enable or not fast path
self._fastPathSender = None
def setFastPathSender(self, fastPathSender):
"""
@param fastPathSender: {tpkt.FastPathSender}
@note: implement tpkt.IFastPathListener
"""
self._fastPathSender = fastPathSender
def sendPDU(self, pduMessage):
"""
@@ -121,7 +129,7 @@ class PDULayer(LayerAutomata):
"""
self.sendPDU(data.DataPDU(pduData, self._shareId))
class Client(PDULayer, tpkt.IFastPathListener):
class Client(PDULayer):
"""
@summary: Client automata of PDU layer
"""
@@ -131,8 +139,6 @@ class Client(PDULayer, tpkt.IFastPathListener):
"""
PDULayer.__init__(self)
self._listener = listener
#enable or not fast path
self._fastPathSender = None
def connect(self):
"""
@@ -149,13 +155,6 @@ class Client(PDULayer, tpkt.IFastPathListener):
"""
self._transport.close()
#self.sendDataPDU(data.ShutdownRequestPDU())
def setFastPathSender(self, fastPathSender):
"""
@param fastPathSender: tpkt.FastPathSender
@note: implement tpkt.IFastPathListener
"""
self._fastPathSender = fastPathSender
def recvDemandActivePDU(self, s):
"""
@@ -267,11 +266,12 @@ class Client(PDULayer, tpkt.IFastPathListener):
#http://msdn.microsoft.com/en-us/library/cc240454.aspx
self.setNextState(self.recvDemandActivePDU)
def recvFastPath(self, fastPathS):
def recvFastPath(self, secFlag, fastPathS):
"""
@summary: Implement IFastPathListener interface
Fast path is needed by RDP 8.0
@param fastPathS: Stream that contain fast path data
@param fastPathS: {Stream} that contain fast path data
@param secFlag: {SecFlags}
"""
fastPathPDU = data.FastPathUpdatePDU()
fastPathS.readType(fastPathPDU)
@@ -343,7 +343,7 @@ class Client(PDULayer, tpkt.IFastPathListener):
def sendClientFinalizeSynchronizePDU(self):
"""
send a synchronize PDU from client to server
@summary: send a synchronize PDU from client to server
"""
synchronizePDU = data.SynchronizeDataPDU(self._transport._transport.getChannelId())
self.sendDataPDU(synchronizePDU)
@@ -371,7 +371,7 @@ class Client(PDULayer, tpkt.IFastPathListener):
pdu.slowPathInputEvents._array = [data.SlowPathInputEvent(x) for x in pointerEvents]
self.sendDataPDU(pdu)
class Server(PDULayer, tpkt.IFastPathListener):
class Server(PDULayer):
"""
Server Automata of PDU layer
"""
@@ -389,14 +389,7 @@ class Server(PDULayer, tpkt.IFastPathListener):
Connect message for server automata
"""
self.sendDemandActivePDU()
self.setNextState(self.recvConfirmActivePDU)
def setFastPathSender(self, fastPathSender):
"""
@param fastPathSender: tpkt.FastPathSender
@note: implement tpkt.IFastPathListener
"""
self._fastPathSender = fastPathSender
self.setNextState(self.recvConfirmActivePDU)
def recvConfirmActivePDU(self, s):
"""
@@ -588,7 +581,8 @@ class Server(PDULayer, tpkt.IFastPathListener):
#fast path case
fastPathUpdateDataPDU = data.FastPathBitmapUpdateDataPDU()
fastPathUpdateDataPDU.rectangles._array = bitmapDatas
self._fastPathSender.sendFastPath(data.FastPathUpdatePDU(fastPathUpdateDataPDU))
self._fastPathSender.sendFastPath(0, data.FastPathUpdatePDU(fastPathUpdateDataPDU))
else:
#slow path case
updateDataPDU = data.BitmapUpdateDataPDU()

View File

@@ -50,7 +50,8 @@ def RC4(key):
S = KSA(key)
return PRGA(S)
def crypt(key, plaintext):
keystream = RC4([ord(c) for c in key])
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])

View File

@@ -45,7 +45,10 @@ class RDPClientController(pdu.layer.PDUClientListener):
#transport pdu layer
self._x224Layer = x224.Client(self._mcsLayer)
#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)
#is pdu layer is ready to send
self._isReady = False

View File

@@ -21,7 +21,8 @@
Some use full methods for security in RDP
"""
import sha, md5, rsa, gcc, rc4, lic
import sha, md5, rsa, rc4
import gcc, lic, tpkt
from rdpy.core.type import CompositeType, Stream, UInt32Le, UInt16Le, String, sizeof, UInt8
from rdpy.core.layer import LayerAutomata, IStreamSender
from rdpy.core.error import InvalidExpectedDataException
@@ -238,7 +239,7 @@ class RDPExtendedInfo(CompositeType):
self.clientSessionId = UInt32Le()
self.performanceFlags = UInt32Le()
class SecLayer(LayerAutomata, IStreamSender):
class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastPathSender):
"""
@summary: Basic RDP security manager
This layer is Transparent as possible for upper layer
@@ -248,10 +249,25 @@ class SecLayer(LayerAutomata, IStreamSender):
@param presentation: Layer (generally pdu layer)
"""
LayerAutomata.__init__(self, presentation)
#thios layer is like a fastpath proxy
self._fastPathTransport = None
self._fastPathPresentation = None
#credentials
self._info = RDPInfo(extendedInfoConditional = lambda:(self._transport.getGCCServerSettings().getBlock(gcc.MessageType.SC_CORE).rdpVersion.value == gcc.Version.RDP_VERSION_5_PLUS))
#True if classic encryption is enable
self._enableEncryption = False
#crypto random
self._clientRandom = None
self._serverRandom = None
#initialise decrypt and encrypt keys
self._decryt = None
self._encrypt = None
#current rc4 map key
self._decryptRc4 = None
self._encryptRc4 = None
def generateKeys(self):
"""
@@ -273,7 +289,12 @@ class SecLayer(LayerAutomata, IStreamSender):
signature = String(readLen = UInt8(8))
encryptedPayload = String()
s.readType((signature, encryptedPayload))
return Stream(rc4.crypt(self._decrypt, encryptedPayload.value))
decrypted = rc4.crypt(self._decryptRc4, encryptedPayload.value)
#ckeck signature
if macData(self._macKey128, decrypted)[:8] != signature.value:
raise InvalidExpectedDataException("Bad packet signature")
return Stream(decrypted)
def writeEncryptedPayload(self, data):
"""
@@ -283,7 +304,7 @@ class SecLayer(LayerAutomata, IStreamSender):
"""
s = Stream()
s.writeType(data)
return (String(macData(self._macKey128, s.getvalue())[:8]), String(rc4.crypt(self._encrypt, s.getvalue())))
return (String(macData(self._macKey128, s.getvalue())[:8]), String(rc4.crypt(self._encryptRc4, s.getvalue())))
def recv(self, data):
"""
@@ -301,7 +322,7 @@ class SecLayer(LayerAutomata, IStreamSender):
if securityFlag.value & SecurityFlag.SEC_ENCRYPT:
data = self.readEncryptedPayload(data)
self._presentation.recv(data)
def send(self, data):
@@ -324,16 +345,44 @@ class SecLayer(LayerAutomata, IStreamSender):
@param flag: {integer} security flag
@param data: {Type | Tuple}
"""
if self._enableEncryption:
flag |= SecurityFlag.SEC_ENCRYPT
if flag & SecurityFlag.SEC_ENCRYPT:
data = self.writeEncryptedPayload(data)
self.__sendFlagged__(flag, data)
def __sendFlagged__(self, flag, data):
"""
@summary: format basic message of security layer
"""
self._transport.send((UInt16Le(flag), UInt16Le(), data))
def recvFastPath(self, secFlag, fastPathS):
"""
@summary: Call when fast path packet is received
@param secFlag: {SecFlags}
@param fastPathS: {Stream}
"""
if self._enableEncryption and secFlag & tpkt.SecFlags.FASTPATH_OUTPUT_ENCRYPTED:
fastPathS = self.readEncryptedPayload(fastPathS)
self._fastPathPresentation.recvFastPath(secFlag, fastPathS)
def setFastPathListener(self, fastPathListener):
"""
@param fastPathListener : {IFastPathListener}
"""
self._fastPathPresentation = fastPathListener
def sendFastPath(self, secFlag, fastPathS):
"""
@summary: Send fastPathS Type as fast path packet
@param secFlag: {SecFlags}
@param fastPathS: {Stream} type transform to stream and send as fastpath
"""
if self._enableEncryption:
secFlag |= tpkt.SecFlags.FASTPATH_OUTPUT_ENCRYPTED
fastPathS = self.writeEncryptedPayload(fastPathS)
self._fastPathTransport.sendFastPath(secFlag, fastPathS)
def setFastPathSender(self, fastPathSender):
"""
@param fastPathSender: {tpkt.FastPathSender}
"""
self._fastPathTransport = fastPathSender
class Client(SecLayer):
"""
@@ -352,19 +401,27 @@ class Client(SecLayer):
self._clientRandom = rsa.randnum.read_random_bits(256)
self._serverRandom = self._transport.getGCCServerSettings().getBlock(gcc.MessageType.SC_SECURITY).serverRandom.value
self._decrypt, self._encrypt = self.generateKeys()
self._decryptRc4 = rc4.RC4Key(self._decrypt)
self._encryptRc4 = rc4.RC4Key(self._encrypt)
#send client random encrypted with
certificate = self._transport.getGCCServerSettings().getBlock(gcc.MessageType.SC_SECURITY).serverCertificate.certData
#reverse because bignum in little endian
serverPublicKey = rsa.PublicKey(bin2bn(certificate.PublicKeyBlob.modulus.value[::-1]), certificate.PublicKeyBlob.pubExp.value)
message = ClientSecurityExchangePDU()
#reverse because bignum in little endian
message.encryptedClientRandom.value = rsa.encrypt(self._clientRandom[::-1], serverPublicKey)[::-1]
self.sendFlagged(SecurityFlag.SEC_EXCHANGE_PKT, message)
#now all messages must be encrypted
self._enableEncryption = True
self.sendFlagged(SecurityFlag.SEC_INFO_PKT, self._info)
secFlag = SecurityFlag.SEC_INFO_PKT
if self._enableEncryption:
secFlag |= SecurityFlag.SEC_ENCRYPT
self.sendFlagged(secFlag, self._info)
self.setNextState(self.recvLicenceInfo)
def recvLicenceInfo(self, s):

View File

@@ -33,36 +33,67 @@ class Action(object):
"""
FASTPATH_ACTION_FASTPATH = 0x0
FASTPATH_ACTION_X224 = 0x3
class SecFlags(object):
"""
@see: http://msdn.microsoft.com/en-us/library/cc240621.aspx
"""
#hihi 'secure' checksum but private key is public !!!
FASTPATH_OUTPUT_SECURE_CHECKSUM = 0x1
FASTPATH_OUTPUT_ENCRYPTED = 0x2
class IFastPathListener(object):
"""
@summary: Fast path packet listener
Usually X224 layer
"""
def recvFastPath(self, fastPathS):
def recvFastPath(self, secFlag, fastPathS):
"""
@summary: Call when fast path packet is received
@param fastPathS: Stream
@param secFlag: {SecFlags}
@param fastPathS: {Stream}
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recvFastPath", "recvFastPath"))
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recvFastPath", "IFastPathListener"))
def initFastPath(self, fastPathSender):
"""
@summary: initialize stack
@param fastPathSender: {IFastPathSender}
"""
self.setFastPathSender(fastPathSender)
fastPathSender.setFastPathListener(self)
def setFastPathSender(self, fastPathSender):
"""
@summary: Call to set a fast path sender to listener
@param fastPathSender: IFastPathSender
@param fastPathSender : {IFastPathSender}
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "setFastPathSender", "recvFastPath"))
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "setFastPathSender", "IFastPathListener"))
class IFastPathSender(object):
"""
@summary: Fast path send capability
"""
def sendFastPath(self, fastPathS):
def sendFastPath(self, secFlag, fastPathS):
"""
@summary: Send fastPathS Type as fast path packet
@param secFlag: {SecFlags}
@param fastPathS: type transform to stream and send as fastpath
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendFastPath", "IFastPathSender"))
def initFastPath(self, fastPathListener):
"""
@summary: initialize stack
@param fastPathListener: {IFastPathListener}
"""
self.setFastPathListener(fastPathListener)
fastPathListener.setFastPathSender(self)
def setFastPathListener(self, fastPathListener):
"""
@param fastPathListener: {IFastPathListener}
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "setFastPathListener", "IFastPathSender"))
class TPKT(RawLayer, IFastPathSender):
"""
@@ -70,21 +101,25 @@ class TPKT(RawLayer, IFastPathSender):
represent the Raw Layer in stack (first layer)
This layer only handle size of packet and determine if is a fast path packet
"""
def __init__(self, presentation, fastPathListener = None):
def __init__(self, presentation):
"""
@param presentation: presentation layer, in RDP case is x224 layer
@param fastPathListener: IFastPathListener
"""
RawLayer.__init__(self, presentation)
#length may be coded on more than 1 bytes
self._lastShortLength = UInt8()
#fast path listener
self._fastPathListener = None
#last secure flag
self._secFlag = 0
def setFastPathListener(self, fastPathListener):
"""
@param fastPathListener : {IFastPathListener}
@note: implement IFastPathSender
"""
self._fastPathListener = fastPathListener
if not fastPathListener is None:
#set me as fast path sender
fastPathListener.setFastPathSender(self)
def connect(self):
"""
@summary: Call when transport layer connection
@@ -112,6 +147,7 @@ class TPKT(RawLayer, IFastPathSender):
self.expect(2, self.readExtendedHeader)
else:
#is fast path packet
self._secFlag = version.value >> 6
data.readType(self._lastShortLength)
if self._lastShortLength.value & 0x80:
#size is 1 byte more
@@ -147,7 +183,7 @@ class TPKT(RawLayer, IFastPathSender):
Fast path data
@param data: Stream from twisted layer
"""
self._fastPathListener.recvFastPath(data)
self._fastPathListener.recvFastPath(self._secFlag, data)
self.expect(2, self.readHeader)
def readData(self, data):
@@ -166,8 +202,9 @@ class TPKT(RawLayer, IFastPathSender):
"""
RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_X224), UInt8(0), UInt16Be(sizeof(message) + 4), message))
def sendFastPath(self, fastPathS):
def sendFastPath(self, secFlag, fastPathS):
"""
@param fastPathS: type transform to stream and send as fastpath
@param secFlag: {SecFlags}
"""
RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_FASTPATH), UInt16Be((sizeof(fastPathS) + 3) | 0x8000), fastPathS))
RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_FASTPATH | secFlag), UInt16Be((sizeof(fastPathS) + 3) | 0x8000), fastPathS))

View File

@@ -132,7 +132,7 @@ class X224Layer(LayerAutomata, IStreamSender):
LayerAutomata.__init__(self, presentation)
#default selectedProtocol is SSl
#client requested selectedProtocol
self._requestedProtocol = Protocols.PROTOCOL_RDP
self._requestedProtocol = Protocols.PROTOCOL_RDP | Protocols.PROTOCOL_SSL
#server selected selectedProtocol
self._selectedProtocol = Protocols.PROTOCOL_SSL

View File

@@ -35,5 +35,6 @@ setup(name='rdpy',
'pyopenssl',
'service_identity',
'qt4reactor',
'rsa',
],
)