Add support for salted mac generation, fix issue 17
This commit is contained in:
@@ -179,6 +179,9 @@ class Client(PDULayer):
|
|||||||
|
|
||||||
for cap in pdu.pduMessage.capabilitySets._array:
|
for cap in pdu.pduMessage.capabilitySets._array:
|
||||||
self._serverCapabilities[cap.capabilitySetType] = cap
|
self._serverCapabilities[cap.capabilitySetType] = cap
|
||||||
|
|
||||||
|
#secure checksum cap here maybe protocol (another) design error
|
||||||
|
self._transport._enableSecureCheckSum = bool(self._serverCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability.extraFlags & caps.GeneralExtraFlag.ENC_SALTED_CHECKSUM)
|
||||||
|
|
||||||
self.sendConfirmActivePDU()
|
self.sendConfirmActivePDU()
|
||||||
#send synchronize
|
#send synchronize
|
||||||
@@ -312,7 +315,7 @@ class Client(PDULayer):
|
|||||||
generalCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability
|
generalCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability
|
||||||
generalCapability.osMajorType.value = caps.MajorType.OSMAJORTYPE_WINDOWS
|
generalCapability.osMajorType.value = caps.MajorType.OSMAJORTYPE_WINDOWS
|
||||||
generalCapability.osMinorType.value = caps.MinorType.OSMINORTYPE_WINDOWS_NT
|
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.ENC_SALTED_CHECKSUM
|
||||||
if not self._fastPathSender is None:
|
if not self._fastPathSender is None:
|
||||||
generalCapability.extraFlags.value |= caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED
|
generalCapability.extraFlags.value |= caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED
|
||||||
|
|
||||||
@@ -413,6 +416,9 @@ class Server(PDULayer):
|
|||||||
#find use full flag
|
#find use full flag
|
||||||
self._clientFastPathSupported = bool(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)
|
||||||
|
|
||||||
|
#secure checksum cap here maybe protocol (another) design error
|
||||||
|
self._transport._enableSecureCheckSum = bool(self._clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability.extraFlags & caps.GeneralExtraFlag.ENC_SALTED_CHECKSUM)
|
||||||
|
|
||||||
self.setNextState(self.recvClientSynchronizePDU)
|
self.setNextState(self.recvClientSynchronizePDU)
|
||||||
|
|
||||||
def recvClientSynchronizePDU(self, s):
|
def recvClientSynchronizePDU(self, s):
|
||||||
@@ -525,7 +531,7 @@ class Server(PDULayer):
|
|||||||
generalCapability = self._serverCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability
|
generalCapability = self._serverCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability
|
||||||
generalCapability.osMajorType.value = caps.MajorType.OSMAJORTYPE_WINDOWS
|
generalCapability.osMajorType.value = caps.MajorType.OSMAJORTYPE_WINDOWS
|
||||||
generalCapability.osMinorType.value = caps.MinorType.OSMINORTYPE_WINDOWS_NT
|
generalCapability.osMinorType.value = caps.MinorType.OSMINORTYPE_WINDOWS_NT
|
||||||
generalCapability.extraFlags.value = caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED | caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR | caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED
|
generalCapability.extraFlags.value = caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED | caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR | caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED | caps.GeneralExtraFlag.ENC_SALTED_CHECKSUM
|
||||||
|
|
||||||
inputCapability = self._serverCapabilities[caps.CapsType.CAPSTYPE_INPUT].capability
|
inputCapability = self._serverCapabilities[caps.CapsType.CAPSTYPE_INPUT].capability
|
||||||
inputCapability.inputFlags.value = caps.InputFlags.INPUT_FLAG_SCANCODES | caps.InputFlags.INPUT_FLAG_MOUSEX
|
inputCapability.inputFlags.value = caps.InputFlags.INPUT_FLAG_SCANCODES | caps.InputFlags.INPUT_FLAG_MOUSEX
|
||||||
|
|||||||
@@ -164,12 +164,12 @@ def macData(macSaltKey, data):
|
|||||||
md5Digest = md5.new()
|
md5Digest = md5.new()
|
||||||
|
|
||||||
#encode length
|
#encode length
|
||||||
s = Stream()
|
dataLength = Stream()
|
||||||
s.writeType(UInt32Le(len(data)))
|
dataLength.writeType(UInt32Le(len(data)))
|
||||||
|
|
||||||
sha1Digest.update(macSaltKey)
|
sha1Digest.update(macSaltKey)
|
||||||
sha1Digest.update("\x36" * 40)
|
sha1Digest.update("\x36" * 40)
|
||||||
sha1Digest.update(s.getvalue())
|
sha1Digest.update(dataLength.getvalue())
|
||||||
sha1Digest.update(data)
|
sha1Digest.update(data)
|
||||||
|
|
||||||
sha1Sig = sha1Digest.digest()
|
sha1Sig = sha1Digest.digest()
|
||||||
@@ -180,6 +180,38 @@ def macData(macSaltKey, data):
|
|||||||
|
|
||||||
return md5Digest.digest()
|
return md5Digest.digest()
|
||||||
|
|
||||||
|
def macSaltedData(macSaltKey, data, encryptionCount):
|
||||||
|
"""
|
||||||
|
@see: https://msdn.microsoft.com/en-us/library/cc240789.aspx
|
||||||
|
@param macSaltKey: {str} mac key
|
||||||
|
@param data: {str} data to sign
|
||||||
|
@param encryptionCount: nb encrypted packet
|
||||||
|
@return: {str} signature
|
||||||
|
"""
|
||||||
|
sha1Digest = sha.new()
|
||||||
|
md5Digest = md5.new()
|
||||||
|
|
||||||
|
#encode length
|
||||||
|
dataLengthS = Stream()
|
||||||
|
dataLengthS.writeType(UInt32Le(len(data)))
|
||||||
|
|
||||||
|
encryptionCountS = Stream()
|
||||||
|
encryptionCountS.writeType(UInt32Le(encryptionCount))
|
||||||
|
|
||||||
|
sha1Digest.update(macSaltKey)
|
||||||
|
sha1Digest.update("\x36" * 40)
|
||||||
|
sha1Digest.update(dataLengthS.getvalue())
|
||||||
|
sha1Digest.update(data)
|
||||||
|
sha1Digest.update(encryptionCountS.getvalue())
|
||||||
|
|
||||||
|
sha1Sig = sha1Digest.digest()
|
||||||
|
|
||||||
|
md5Digest.update(macSaltKey)
|
||||||
|
md5Digest.update("\x5c" * 48)
|
||||||
|
md5Digest.update(sha1Sig)
|
||||||
|
|
||||||
|
return md5Digest.digest()
|
||||||
|
|
||||||
def tempKey(initialKey, currentKey):
|
def tempKey(initialKey, currentKey):
|
||||||
"""
|
"""
|
||||||
@see: http://msdn.microsoft.com/en-us/library/cc240792.aspx
|
@see: http://msdn.microsoft.com/en-us/library/cc240792.aspx
|
||||||
@@ -342,6 +374,9 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
|
|||||||
#True if classic encryption is enable
|
#True if classic encryption is enable
|
||||||
self._enableEncryption = False
|
self._enableEncryption = False
|
||||||
|
|
||||||
|
#Enable Secure Mac generation
|
||||||
|
self._enableSecureCheckSum = False
|
||||||
|
|
||||||
#initialise decrypt and encrypt keys
|
#initialise decrypt and encrypt keys
|
||||||
self._macKey = None
|
self._macKey = None
|
||||||
self._initialDecrytKey = None
|
self._initialDecrytKey = None
|
||||||
@@ -358,10 +393,11 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
|
|||||||
self._encryptRc4 = None
|
self._encryptRc4 = None
|
||||||
|
|
||||||
|
|
||||||
def readEncryptedPayload(self, s):
|
def readEncryptedPayload(self, s, saltedMacGeneration):
|
||||||
"""
|
"""
|
||||||
@summary: decrypt basic RDP security payload
|
@summary: decrypt basic RDP security payload
|
||||||
@param s: {Stream} encrypted stream
|
@param s: {Stream} encrypted stream
|
||||||
|
@param saltedMacGeneration: {bool} use salted mac generation
|
||||||
@return: {Stream} decrypted
|
@return: {Stream} decrypted
|
||||||
"""
|
"""
|
||||||
#if update is needed
|
#if update is needed
|
||||||
@@ -378,18 +414,22 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
|
|||||||
decrypted = rc4.crypt(self._decryptRc4, encryptedPayload.value)
|
decrypted = rc4.crypt(self._decryptRc4, encryptedPayload.value)
|
||||||
|
|
||||||
#ckeck signature
|
#ckeck signature
|
||||||
if macData(self._macKey, decrypted)[:8] != signature.value:
|
if not saltedMacGeneration and macData(self._macKey, decrypted)[:8] != signature.value:
|
||||||
raise InvalidExpectedDataException("Bad packet signature")
|
raise InvalidExpectedDataException("bad signature")
|
||||||
|
|
||||||
|
if saltedMacGeneration and macSaltedData(self._macKey, decrypted, self._nbDecryptedPacket)[:8] != signature.value:
|
||||||
|
raise InvalidExpectedDataException("bad signature")
|
||||||
|
|
||||||
#count
|
#count
|
||||||
self._nbDecryptedPacket += 1
|
self._nbDecryptedPacket += 1
|
||||||
|
|
||||||
return Stream(decrypted)
|
return Stream(decrypted)
|
||||||
|
|
||||||
def writeEncryptedPayload(self, data):
|
def writeEncryptedPayload(self, data, saltedMacGeneration):
|
||||||
"""
|
"""
|
||||||
@summary: sign and crypt data
|
@summary: sign and crypt data
|
||||||
@param s: {Stream} raw stream
|
@param data: {Type} raw stream
|
||||||
|
@param saltedMacGeneration: {bool} use salted mac generation
|
||||||
@return: {Tuple} (signature, encryptedData)
|
@return: {Tuple} (signature, encryptedData)
|
||||||
"""
|
"""
|
||||||
if self._nbEncryptedPacket == 4096:
|
if self._nbEncryptedPacket == 4096:
|
||||||
@@ -400,9 +440,14 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
|
|||||||
self._nbEncryptedPacket = 0
|
self._nbEncryptedPacket = 0
|
||||||
|
|
||||||
self._nbEncryptedPacket += 1
|
self._nbEncryptedPacket += 1
|
||||||
|
|
||||||
s = Stream()
|
s = Stream()
|
||||||
s.writeType(data)
|
s.writeType(data)
|
||||||
return (String(macData(self._macKey, s.getvalue())[:8]), String(rc4.crypt(self._encryptRc4, s.getvalue())))
|
|
||||||
|
if saltedMacGeneration:
|
||||||
|
return (String(macSaltedData(self._macKey, s.getvalue(), self._nbEncryptedPacket - 1)[:8]), String(rc4.crypt(self._encryptRc4, s.getvalue())))
|
||||||
|
else:
|
||||||
|
return (String(macData(self._macKey, s.getvalue())[:8]), String(rc4.crypt(self._encryptRc4, s.getvalue())))
|
||||||
|
|
||||||
def recv(self, data):
|
def recv(self, data):
|
||||||
"""
|
"""
|
||||||
@@ -419,7 +464,7 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
|
|||||||
data.readType((securityFlag, securityFlagHi))
|
data.readType((securityFlag, securityFlagHi))
|
||||||
|
|
||||||
if securityFlag.value & SecurityFlag.SEC_ENCRYPT:
|
if securityFlag.value & SecurityFlag.SEC_ENCRYPT:
|
||||||
data = self.readEncryptedPayload(data)
|
data = self.readEncryptedPayload(data, securityFlag.value & SecurityFlag.SEC_SECURE_CHECKSUM)
|
||||||
|
|
||||||
self._presentation.recv(data)
|
self._presentation.recv(data)
|
||||||
|
|
||||||
@@ -433,7 +478,12 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
|
|||||||
self._transport.send(data)
|
self._transport.send(data)
|
||||||
return
|
return
|
||||||
|
|
||||||
self.sendFlagged(SecurityFlag.SEC_ENCRYPT, data)
|
flag = SecurityFlag.SEC_ENCRYPT
|
||||||
|
|
||||||
|
if self._enableSecureCheckSum:
|
||||||
|
flag |= SecurityFlag.SEC_SECURE_CHECKSUM
|
||||||
|
|
||||||
|
self.sendFlagged(flag, data)
|
||||||
|
|
||||||
def sendFlagged(self, flag, data):
|
def sendFlagged(self, flag, data):
|
||||||
"""
|
"""
|
||||||
@@ -444,7 +494,7 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
|
|||||||
@param data: {Type | Tuple}
|
@param data: {Type | Tuple}
|
||||||
"""
|
"""
|
||||||
if flag & SecurityFlag.SEC_ENCRYPT:
|
if flag & SecurityFlag.SEC_ENCRYPT:
|
||||||
data = self.writeEncryptedPayload(data)
|
data = self.writeEncryptedPayload(data, flag & SecurityFlag.SEC_SECURE_CHECKSUM)
|
||||||
self._transport.send((UInt16Le(flag), UInt16Le(), data))
|
self._transport.send((UInt16Le(flag), UInt16Le(), data))
|
||||||
|
|
||||||
def recvFastPath(self, secFlag, fastPathS):
|
def recvFastPath(self, secFlag, fastPathS):
|
||||||
@@ -454,7 +504,7 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
|
|||||||
@param fastPathS: {Stream}
|
@param fastPathS: {Stream}
|
||||||
"""
|
"""
|
||||||
if self._enableEncryption and secFlag & tpkt.SecFlags.FASTPATH_OUTPUT_ENCRYPTED:
|
if self._enableEncryption and secFlag & tpkt.SecFlags.FASTPATH_OUTPUT_ENCRYPTED:
|
||||||
fastPathS = self.readEncryptedPayload(fastPathS)
|
fastPathS = self.readEncryptedPayload(fastPathS, secFlag & tpkt.SecFlags.FASTPATH_OUTPUT_SECURE_CHECKSUM)
|
||||||
|
|
||||||
self._fastPathPresentation.recvFastPath(secFlag, fastPathS)
|
self._fastPathPresentation.recvFastPath(secFlag, fastPathS)
|
||||||
|
|
||||||
@@ -472,7 +522,11 @@ class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastP
|
|||||||
"""
|
"""
|
||||||
if self._enableEncryption:
|
if self._enableEncryption:
|
||||||
secFlag |= tpkt.SecFlags.FASTPATH_OUTPUT_ENCRYPTED
|
secFlag |= tpkt.SecFlags.FASTPATH_OUTPUT_ENCRYPTED
|
||||||
fastPathS = self.writeEncryptedPayload(fastPathS)
|
|
||||||
|
if self._enableSecureCheckSum:
|
||||||
|
secFlag |= tpkt.SecFlags.FASTPATH_OUTPUT_SECURE_CHECKSUM
|
||||||
|
|
||||||
|
fastPathS = self.writeEncryptedPayload(fastPathS, self._enableSecureCheckSum)
|
||||||
|
|
||||||
self._fastPathTransport.sendFastPath(secFlag, fastPathS)
|
self._fastPathTransport.sendFastPath(secFlag, fastPathS)
|
||||||
|
|
||||||
@@ -661,7 +715,7 @@ class Server(SecLayer):
|
|||||||
raise InvalidExpectedDataException("Waiting info packet")
|
raise InvalidExpectedDataException("Waiting info packet")
|
||||||
|
|
||||||
if securityFlag.value & SecurityFlag.SEC_ENCRYPT:
|
if securityFlag.value & SecurityFlag.SEC_ENCRYPT:
|
||||||
s = self.readEncryptedPayload(s)
|
s = self.readEncryptedPayload(s, securityFlag.value & SecurityFlag.SEC_SECURE_CHECKSUM)
|
||||||
|
|
||||||
s.readType(self._info)
|
s.readType(self._info)
|
||||||
#next state send error license
|
#next state send error license
|
||||||
|
|||||||
Reference in New Issue
Block a user