finish RDP basic security layer for server side but have bug on faspath + basic security layer...
This commit is contained in:
@@ -22,6 +22,7 @@ Implement GCC structure use in RDP protocol
|
||||
http://msdn.microsoft.com/en-us/library/cc240508.aspx
|
||||
"""
|
||||
|
||||
import md5
|
||||
from rdpy.core.type import UInt8, UInt16Le, UInt32Le, CompositeType, String, Stream, sizeof, FactoryType, ArrayType
|
||||
import per, mcs
|
||||
from rdpy.core.error import InvalidExpectedDataException
|
||||
@@ -314,7 +315,7 @@ class ServerCertificate(CompositeType):
|
||||
"""
|
||||
def __init__(self, certData = None, readLen = None, conditional = lambda:True):
|
||||
CompositeType.__init__(self, readLen = readLen, conditional = conditional)
|
||||
self.dwVersion = UInt32Le(lambda:self.certData.__class__._TYPE_)
|
||||
self.dwVersion = UInt32Le(lambda:(self.certData.__class__._TYPE_))
|
||||
|
||||
def CertificateFactory():
|
||||
"""
|
||||
@@ -330,7 +331,7 @@ class ServerCertificate(CompositeType):
|
||||
elif not "_TYPE_" in certData.__class__.__dict__:
|
||||
raise InvalidExpectedDataException("Try to send an invalid Certificate")
|
||||
|
||||
self.certData = FactoryType(CertificateFactory)
|
||||
self.certData = certData
|
||||
|
||||
class ProprietaryServerCertificate(CompositeType):
|
||||
"""
|
||||
@@ -339,6 +340,11 @@ class ProprietaryServerCertificate(CompositeType):
|
||||
"""
|
||||
_TYPE_ = CertificateType.CERT_CHAIN_VERSION_1
|
||||
|
||||
#http://msdn.microsoft.com/en-us/library/cc240776.aspx
|
||||
_TERMINAL_SERVICES_MODULUS_ = "\x3d\x3a\x5e\xbd\x72\x43\x3e\xc9\x4d\xbb\xc1\x1e\x4a\xba\x5f\xcb\x3e\x88\x20\x87\xef\xf5\xc1\xe2\xd7\xb7\x6b\x9a\xf2\x52\x45\x95\xce\x63\x65\x6b\x58\x3a\xfe\xef\x7c\xe7\xbf\xfe\x3d\xf6\x5c\x7d\x6c\x5e\x06\x09\x1a\xf5\x61\xbb\x20\x93\x09\x5f\x05\x6d\xea\x87"
|
||||
_TERMINAL_SERVICES_PRIVATE_EXPONENT_ = "\x87\xa7\x19\x32\xda\x11\x87\x55\x58\x00\x16\x16\x25\x65\x68\xf8\x24\x3e\xe6\xfa\xe9\x67\x49\x94\xcf\x92\xcc\x33\x99\xe8\x08\x60\x17\x9a\x12\x9f\x24\xdd\xb1\x24\x99\xc7\x3a\xb8\x0a\x7b\x0d\xdd\x35\x07\x79\x17\x0b\x51\x9b\xb3\xc7\x10\x01\x13\xe7\x3f\xf3\x5f"
|
||||
_TERMINAL_SERVICES_PUBLIC_EXPONENT_ = "\x5b\x7b\x88\xc0"
|
||||
|
||||
def __init__(self):
|
||||
CompositeType.__init__(self)
|
||||
self.dwSigAlgId = UInt32Le(0x00000001, constant = True)
|
||||
@@ -347,8 +353,9 @@ class ProprietaryServerCertificate(CompositeType):
|
||||
self.wPublicKeyBlobLen = UInt16Le(lambda:sizeof(self.PublicKeyBlob))
|
||||
self.PublicKeyBlob = RSAPublicKey(readLen = self.wPublicKeyBlobLen)
|
||||
self.wSignatureBlobType = UInt16Le(0x0008, constant = True)
|
||||
self.wSignatureBlobLen = UInt16Le(lambda:sizeof(self.SignatureBlob))
|
||||
self.wSignatureBlobLen = UInt16Le(lambda:(sizeof(self.SignatureBlob) - 8))
|
||||
self.SignatureBlob = String(readLen = self.wSignatureBlobLen)
|
||||
self.padding = String("\x00" * 8, readLen = UInt8(8))
|
||||
|
||||
def getPublicKey(self):
|
||||
"""
|
||||
@@ -357,6 +364,37 @@ class ProprietaryServerCertificate(CompositeType):
|
||||
log.debug("read RSA public key from proprietary certificate")
|
||||
#reverse because bignum in little endian
|
||||
return rsa.PublicKey(self.PublicKeyBlob.pubExp.value, self.PublicKeyBlob.modulus.value[::-1])
|
||||
|
||||
def computeSignatureHash(self):
|
||||
"""
|
||||
@summary: compute hash
|
||||
"""
|
||||
s = Stream()
|
||||
s.writeType(UInt32Le(self.__class__._TYPE_))
|
||||
s.writeType(self.dwSigAlgId)
|
||||
s.writeType(self.dwKeyAlgId)
|
||||
s.writeType(self.wPublicKeyBlobType)
|
||||
s.writeType(self.wPublicKeyBlobLen)
|
||||
s.writeType(self.PublicKeyBlob)
|
||||
|
||||
md5Digest = md5.new()
|
||||
md5Digest.update(s.getvalue())
|
||||
|
||||
return md5Digest.digest() + "\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01"
|
||||
|
||||
def sign(self):
|
||||
"""
|
||||
@summary: sign proprietary certificate
|
||||
@see: http://msdn.microsoft.com/en-us/library/cc240778.aspx
|
||||
"""
|
||||
self.SignatureBlob.value = rsa.sign(self.computeSignatureHash()[::-1], rsa.PrivateKey(d = ProprietaryServerCertificate._TERMINAL_SERVICES_PRIVATE_EXPONENT_[::-1], n = ProprietaryServerCertificate._TERMINAL_SERVICES_MODULUS_[::-1]))[::-1]
|
||||
|
||||
def verify(self):
|
||||
"""
|
||||
@summary: verify certificate signature
|
||||
"""
|
||||
return rsa.verify(self.SignatureBlob.value[::-1], rsa.PublicKey(e = ProprietaryServerCertificate._TERMINAL_SERVICES_PUBLIC_EXPONENT_[::-1], n = ProprietaryServerCertificate._TERMINAL_SERVICES_MODULUS_[::-1]))[::-1] == self.computeSignatureHash()
|
||||
|
||||
|
||||
class CertBlob(CompositeType):
|
||||
"""
|
||||
@@ -389,6 +427,12 @@ class X509CertificateChain(CompositeType):
|
||||
#last certifcate contain public key
|
||||
n, e = x509.extractRSAKey(x509.load(self.CertBlobArray[-1].abCert.value))
|
||||
return rsa.PublicKey(e, n)
|
||||
|
||||
def verify(self):
|
||||
"""
|
||||
@todo: verify x509 signature
|
||||
"""
|
||||
return True
|
||||
|
||||
class RSAPublicKey(CompositeType):
|
||||
"""
|
||||
@@ -396,6 +440,7 @@ class RSAPublicKey(CompositeType):
|
||||
"""
|
||||
def __init__(self, readLen):
|
||||
CompositeType.__init__(self, readLen = readLen)
|
||||
#magic is RSA1(0x31415352)
|
||||
self.magic = UInt32Le(0x31415352, constant = True)
|
||||
self.keylen = UInt32Le(lambda:(sizeof(self.modulus) + sizeof(self.padding)))
|
||||
self.bitlen = UInt32Le(lambda:((self.keylen.value - 8) * 8))
|
||||
|
||||
@@ -492,7 +492,7 @@ class Server(MCSLayer):
|
||||
self._serverSettings.SC_SECURITY.encryptionMethod.value = gcc.EncryptionMethod.ENCRYPTION_FLAG_128BIT
|
||||
self._serverSettings.SC_SECURITY.encryptionLevel.value = gcc.EncryptionLevel.ENCRYPTION_LEVEL_HIGH
|
||||
self._serverSettings.SC_SECURITY.serverRandom.value = rsa.random(256)
|
||||
self._serverSettings.SC_SECURITY.serverCertificate.certData = self._presentation.getCertificate()
|
||||
self._serverSettings.SC_SECURITY.serverCertificate = self._presentation.getCertificate()
|
||||
|
||||
self._serverSettings.SC_CORE.clientRequestedProtocol.value = self._transport._requestedProtocol
|
||||
self.setNextState(self.recvConnectInitial)
|
||||
|
||||
@@ -235,7 +235,7 @@ class Capability(CompositeType):
|
||||
"""
|
||||
Closure for capability factory
|
||||
"""
|
||||
for c in [GeneralCapability, BitmapCapability, OrderCapability, BitmapCacheCapability, PointerCapability, InputCapability, BrushCapability, GlyphCapability, OffscreenBitmapCacheCapability, VirtualChannelCapability, SoundCapability, ControlCapability, WindowActivationCapability, FontCapability, ColorCacheCapability, ShareCapability]:
|
||||
for c in [GeneralCapability, BitmapCapability, OrderCapability, BitmapCacheCapability, PointerCapability, InputCapability, BrushCapability, GlyphCapability, OffscreenBitmapCacheCapability, VirtualChannelCapability, SoundCapability, ControlCapability, WindowActivationCapability, FontCapability, ColorCacheCapability, ShareCapability, MultiFragmentUpdate]:
|
||||
if self.capabilitySetType.value == c._TYPE_ and (self.lengthCapability.value - 4) > 0:
|
||||
return c(readLen = self.lengthCapability - 4)
|
||||
log.debug("unknown Capability type : %s"%hex(self.capabilitySetType.value))
|
||||
@@ -526,4 +526,17 @@ class ShareCapability(CompositeType):
|
||||
def __init__(self, readLen = None):
|
||||
CompositeType.__init__(self, readLen = readLen)
|
||||
self.nodeId = UInt16Le()
|
||||
self.pad2octets = UInt16Le()
|
||||
self.pad2octets = UInt16Le()
|
||||
|
||||
class MultiFragmentUpdate(CompositeType):
|
||||
"""
|
||||
@summary: Use to advertise fast path max buffer to use
|
||||
client -> server
|
||||
server -> client
|
||||
@see: http://msdn.microsoft.com/en-us/library/cc240649.aspx
|
||||
"""
|
||||
_TYPE_ = CapsType.CAPSETTYPE_MULTIFRAGMENTUPDATE
|
||||
|
||||
def __init__(self, readLen = None):
|
||||
CompositeType.__init__(self, readLen = readLen)
|
||||
self.MaxRequestSize = UInt32Le(0xffffffff)
|
||||
@@ -100,7 +100,8 @@ class PDULayer(LayerAutomata, tpkt.IFastPathListener):
|
||||
caps.CapsType.CAPSTYPE_GLYPHCACHE : caps.Capability(caps.GlyphCapability()),
|
||||
caps.CapsType.CAPSTYPE_OFFSCREENCACHE : caps.Capability(caps.OffscreenBitmapCacheCapability()),
|
||||
caps.CapsType.CAPSTYPE_VIRTUALCHANNEL : caps.Capability(caps.VirtualChannelCapability()),
|
||||
caps.CapsType.CAPSTYPE_SOUND : caps.Capability(caps.SoundCapability())
|
||||
caps.CapsType.CAPSTYPE_SOUND : caps.Capability(caps.SoundCapability()),
|
||||
caps.CapsType.CAPSETTYPE_MULTIFRAGMENTUPDATE : caps.Capability(caps.MultiFragmentUpdate())
|
||||
}
|
||||
#share id between client and server
|
||||
self._shareId = 0x103EA
|
||||
@@ -410,8 +411,8 @@ class Server(PDULayer):
|
||||
self._clientCapabilities[cap.capabilitySetType] = cap
|
||||
|
||||
#find use full flag
|
||||
self._clientFastPathSupported = self._clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability.extraFlags.value & caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED
|
||||
|
||||
self._clientFastPathSupported = bool(self._clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability.extraFlags.value & (caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED | caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED))
|
||||
|
||||
self.setNextState(self.recvClientSynchronizePDU)
|
||||
|
||||
def recvClientSynchronizePDU(self, s):
|
||||
@@ -524,7 +525,7 @@ class Server(PDULayer):
|
||||
generalCapability = self._serverCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability
|
||||
generalCapability.osMajorType.value = caps.MajorType.OSMAJORTYPE_WINDOWS
|
||||
generalCapability.osMinorType.value = caps.MinorType.OSMINORTYPE_WINDOWS_NT
|
||||
generalCapability.extraFlags.value = caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED | caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR
|
||||
generalCapability.extraFlags.value = caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED | caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR | caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED
|
||||
|
||||
inputCapability = self._serverCapabilities[caps.CapsType.CAPSTYPE_INPUT].capability
|
||||
inputCapability.inputFlags.value = caps.InputFlags.INPUT_FLAG_SCANCODES | caps.InputFlags.INPUT_FLAG_MOUSEX
|
||||
@@ -582,7 +583,6 @@ class Server(PDULayer):
|
||||
fastPathUpdateDataPDU = data.FastPathBitmapUpdateDataPDU()
|
||||
fastPathUpdateDataPDU.rectangles._array = bitmapDatas
|
||||
self._fastPathSender.sendFastPath(0, data.FastPathUpdatePDU(fastPathUpdateDataPDU))
|
||||
|
||||
else:
|
||||
#slow path case
|
||||
updateDataPDU = data.BitmapUpdateDataPDU()
|
||||
|
||||
@@ -95,40 +95,6 @@ class AfInet(object):
|
||||
"""
|
||||
AF_INET = 0x00002
|
||||
AF_INET6 = 0x0017
|
||||
|
||||
def terminalServicesSign(certificate):
|
||||
"""
|
||||
@summary: sign proprietary certificate
|
||||
@param certificate: {gcc.ProprietaryServerCertificate}
|
||||
@see: http://msdn.microsoft.com/en-us/library/cc240778.aspx
|
||||
"""
|
||||
modulus = "\x3d\x3a\x5e\xbd\x72\x43\x3e\xc9\x4d\xbb\xc1\x1e\x4a\xba\x5f\xcb\x3e\x88\x20\x87\xef\xf5\xc1\xe2\xd7\xb7\x6b\x9a\xf2\x52\x45\x95\xce\x63\x65\x6b\x58\x3a\xfe\xef\x7c\xe7\xbf\xfe\x3d\xf6\x5c\x7d\x6c\x5e\x06\x09\x1a\xf5\x61\xbb\x20\x93\x09\x5f\x05\x6d\xea\x87"
|
||||
privateExponent = "\x87\xa7\x19\x32\xda\x11\x87\x55\x58\x00\x16\x16\x25\x65\x68\xf8\x24\x3e\xe6\xfa\xe9\x67\x49\x94\xcf\x92\xcc\x33\x99\xe8\x08\x60\x17\x9a\x12\x9f\x24\xdd\xb1\x24\x99\xc7\x3a\xb8\x0a\x7b\x0d\xdd\x35\x07\x79\x17\x0b\x51\x9b\xb3\xc7\x10\x01\x13\xe7\x3f\xf3\x5f"
|
||||
publicExponent = "\x5b\x7b\x88\xc0"
|
||||
|
||||
publicKeyBlob = Stream()
|
||||
publicKeyBlob.writeType(certificate.wPublicKeyBlobType)
|
||||
publicKeyBlob.writeType(certificate.wPublicKeyBlobLen)
|
||||
publicKeyBlob.writeType(certificate.PublicKeyBlob)
|
||||
|
||||
dwVersion = Stream()
|
||||
dwVersion.writeType(UInt32Le(certificate.__class__._TYPE_))
|
||||
|
||||
dwSigAlgId = Stream()
|
||||
dwSigAlgId.writeType(certificate.dwSigAlgId)
|
||||
|
||||
dwKeyAlgId = Stream()
|
||||
dwKeyAlgId.writeType(certificate.dwKeyAlgId)
|
||||
|
||||
md5Digest = md5.new()
|
||||
md5Digest.update(dwVersion.getvalue())
|
||||
md5Digest.update(dwSigAlgId.getvalue())
|
||||
md5Digest.update(dwKeyAlgId.getvalue())
|
||||
md5Digest.update(publicKeyBlob.getvalue())
|
||||
|
||||
message = md5Digest.digest() + "\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01"
|
||||
|
||||
return rsa.sign(message[::-1], rsa.PrivateKey(d = privateExponent[::-1], n = modulus[::-1]))
|
||||
|
||||
def saltedHash(inputData, salt, salt1, salt2):
|
||||
"""
|
||||
@@ -400,7 +366,7 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
|
||||
"""
|
||||
#if update is needed
|
||||
if self._nbDecryptedPacket == 4096:
|
||||
log.info("update decrypt key")
|
||||
log.debug("update decrypt key")
|
||||
self._currentDecrytKey = updateKey( self._initialDecrytKey, self._currentDecrytKey,
|
||||
self.getGCCServerSettings().SC_SECURITY.encryptionMethod.value)
|
||||
self._decryptRc4 = rc4.RC4Key(self._currentDecrytKey)
|
||||
@@ -427,7 +393,7 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
|
||||
@return: {Tuple} (signature, encryptedData)
|
||||
"""
|
||||
if self._nbEncryptedPacket == 4096:
|
||||
log.info("update encrypt key")
|
||||
log.debug("update encrypt key")
|
||||
self._currentEncryptKey = updateKey( self._initialEncryptKey, self._currentEncryptKey,
|
||||
self.getGCCServerSettings().SC_SECURITY.encryptionMethod.value)
|
||||
self._encryptRc4 = rc4.RC4Key(self._currentEncryptKey)
|
||||
@@ -590,6 +556,9 @@ class Client(SecLayer):
|
||||
self._decryptRc4 = rc4.RC4Key(self._currentDecrytKey)
|
||||
self._encryptRc4 = rc4.RC4Key(self._currentEncryptKey)
|
||||
|
||||
#verify certificate
|
||||
if not self.getGCCServerSettings().SC_SECURITY.serverCertificate.certData.verify():
|
||||
log.warning("cannot verify server identity")
|
||||
#send client random encrypted with
|
||||
serverPublicKey = self.getGCCServerSettings().SC_SECURITY.serverCertificate.certData.getPublicKey()
|
||||
message = ClientSecurityExchangePDU()
|
||||
@@ -644,8 +613,8 @@ class Server(SecLayer):
|
||||
certificate = gcc.ProprietaryServerCertificate()
|
||||
certificate.PublicKeyBlob.modulus.value = rsa.int2bytes(self._rsaPublicKey.n)[::-1]
|
||||
certificate.PublicKeyBlob.pubExp.value = self._rsaPublicKey.e
|
||||
certificate.SignatureBlob.value = terminalServicesSign(certificate)[::-1] + "\x00" * 8
|
||||
return certificate
|
||||
certificate.sign()
|
||||
return gcc.ServerCertificate(certificate)
|
||||
|
||||
def recvClientRandom(self, s):
|
||||
"""
|
||||
|
||||
@@ -132,7 +132,7 @@ class X224Layer(LayerAutomata, IStreamSender):
|
||||
"""
|
||||
LayerAutomata.__init__(self, presentation)
|
||||
#client requested selectedProtocol
|
||||
self._requestedProtocol = Protocols.PROTOCOL_RDP
|
||||
self._requestedProtocol = Protocols.PROTOCOL_SSL
|
||||
#server selected selectedProtocol
|
||||
self._selectedProtocol = Protocols.PROTOCOL_SSL
|
||||
|
||||
@@ -258,7 +258,7 @@ class Server(X224Layer):
|
||||
|
||||
#match best security layer available
|
||||
if not self._serverPrivateKeyFileName is None and not self._serverCertificateFileName is None:
|
||||
self._selectedProtocol = self._requestedProtocol & Protocols.PROTOCOL_RDP
|
||||
self._selectedProtocol = self._requestedProtocol & Protocols.PROTOCOL_SSL
|
||||
else:
|
||||
self._selectedProtocol = self._requestedProtocol & Protocols.PROTOCOL_RDP
|
||||
|
||||
|
||||
@@ -52,11 +52,11 @@ def PrivateKey(d, n):
|
||||
n = rsa.transform.bytes2int(n)
|
||||
return { 'd' : d, 'n' : n }
|
||||
|
||||
def int2bytes(i):
|
||||
def int2bytes(i, fill_size=None):
|
||||
"""
|
||||
@summary: wrapper of rsa.transform.int2bytes
|
||||
"""
|
||||
return rsa.transform.int2bytes(i)
|
||||
return rsa.transform.int2bytes(i,fill_size)
|
||||
|
||||
def random(size):
|
||||
"""
|
||||
@@ -71,7 +71,7 @@ def encrypt(message, publicKey):
|
||||
@param message: {str} source message
|
||||
@param publicKey: {rsa.PublicKey}
|
||||
"""
|
||||
return rsa.transform.int2bytes(rsa.core.encrypt_int(rsa.transform.bytes2int(message), publicKey['e'], publicKey['n']))
|
||||
return rsa.transform.int2bytes(rsa.core.encrypt_int(rsa.transform.bytes2int(message), publicKey['e'], publicKey['n']), rsa.common.byte_size(publicKey['n']))
|
||||
|
||||
def decrypt(message, privateKey):
|
||||
"""
|
||||
@@ -87,4 +87,12 @@ def sign(message, privateKey):
|
||||
@param message: {str} message to sign
|
||||
@param privateKey : {rsa.privateKey} key use to sugn
|
||||
"""
|
||||
return rsa.transform.int2bytes(rsa.core.encrypt_int(rsa.transform.bytes2int(message), privateKey['d'], privateKey['n']))
|
||||
return rsa.transform.int2bytes(rsa.core.encrypt_int(rsa.transform.bytes2int(message), privateKey['d'], privateKey['n']), rsa.common.byte_size(privateKey['n']))
|
||||
|
||||
def verify(message, publicKey):
|
||||
"""
|
||||
@summary: return hash
|
||||
@param message: {str} message to verify
|
||||
@param publicKey : {rsa.publicKey} key use to sugn
|
||||
"""
|
||||
return rsa.transform.int2bytes(rsa.core.decrypt_int(rsa.transform.bytes2int(message), publicKey['e'], publicKey['n']))
|
||||
Reference in New Issue
Block a user