move info packet to security layer
This commit is contained in:
@@ -26,50 +26,6 @@ from rdpy.network.type import CompositeType, String, UInt8, UInt16Le, UInt32Le,
|
|||||||
from rdpy.base.error import InvalidExpectedDataException
|
from rdpy.base.error import InvalidExpectedDataException
|
||||||
import rdpy.base.log as log
|
import rdpy.base.log as log
|
||||||
import caps, order
|
import caps, order
|
||||||
|
|
||||||
class InfoFlag(object):
|
|
||||||
"""
|
|
||||||
Client capabilities informations
|
|
||||||
"""
|
|
||||||
INFO_MOUSE = 0x00000001
|
|
||||||
INFO_DISABLECTRLALTDEL = 0x00000002
|
|
||||||
INFO_AUTOLOGON = 0x00000008
|
|
||||||
INFO_UNICODE = 0x00000010
|
|
||||||
INFO_MAXIMIZESHELL = 0x00000020
|
|
||||||
INFO_LOGONNOTIFY = 0x00000040
|
|
||||||
INFO_COMPRESSION = 0x00000080
|
|
||||||
INFO_ENABLEWINDOWSKEY = 0x00000100
|
|
||||||
INFO_REMOTECONSOLEAUDIO = 0x00002000
|
|
||||||
INFO_FORCE_ENCRYPTED_CS_PDU = 0x00004000
|
|
||||||
INFO_RAIL = 0x00008000
|
|
||||||
INFO_LOGONERRORS = 0x00010000
|
|
||||||
INFO_MOUSE_HAS_WHEEL = 0x00020000
|
|
||||||
INFO_PASSWORD_IS_SC_PIN = 0x00040000
|
|
||||||
INFO_NOAUDIOPLAYBACK = 0x00080000
|
|
||||||
INFO_USING_SAVED_CREDS = 0x00100000
|
|
||||||
INFO_AUDIOCAPTURE = 0x00200000
|
|
||||||
INFO_VIDEO_DISABLE = 0x00400000
|
|
||||||
INFO_CompressionTypeMask = 0x00001E00
|
|
||||||
|
|
||||||
class PerfFlag(object):
|
|
||||||
"""
|
|
||||||
Network performances flag
|
|
||||||
"""
|
|
||||||
PERF_DISABLE_WALLPAPER = 0x00000001
|
|
||||||
PERF_DISABLE_FULLWINDOWDRAG = 0x00000002
|
|
||||||
PERF_DISABLE_MENUANIMATIONS = 0x00000004
|
|
||||||
PERF_DISABLE_THEMING = 0x00000008
|
|
||||||
PERF_DISABLE_CURSOR_SHADOW = 0x00000020
|
|
||||||
PERF_DISABLE_CURSORSETTINGS = 0x00000040
|
|
||||||
PERF_ENABLE_FONT_SMOOTHING = 0x00000080
|
|
||||||
PERF_ENABLE_DESKTOP_COMPOSITION = 0x00000100
|
|
||||||
|
|
||||||
class AfInet(object):
|
|
||||||
"""
|
|
||||||
IPv4 or IPv6 adress style
|
|
||||||
"""
|
|
||||||
AF_INET = 0x00002
|
|
||||||
AF_INET6 = 0x0017
|
|
||||||
|
|
||||||
class PDUType(object):
|
class PDUType(object):
|
||||||
"""
|
"""
|
||||||
@@ -457,48 +413,7 @@ class ErrorInfo(object):
|
|||||||
ERRINFO_VCDATATOOLONG : "The size of a received Virtual Channel PDU (section 2.2.6.1) exceeds the chunking size specified in the Virtual Channel Capability Set (section 2.2.7.1.10).",
|
ERRINFO_VCDATATOOLONG : "The size of a received Virtual Channel PDU (section 2.2.6.1) exceeds the chunking size specified in the Virtual Channel Capability Set (section 2.2.7.1.10).",
|
||||||
}
|
}
|
||||||
|
|
||||||
class RDPInfo(CompositeType):
|
|
||||||
"""
|
|
||||||
Client informations
|
|
||||||
Contains credentials (very important packet)
|
|
||||||
@see: http://msdn.microsoft.com/en-us/library/cc240475.aspx
|
|
||||||
"""
|
|
||||||
def __init__(self, extendedInfoConditional):
|
|
||||||
CompositeType.__init__(self)
|
|
||||||
#code page
|
|
||||||
self.codePage = UInt32Le()
|
|
||||||
#support flag
|
|
||||||
self.flag = UInt32Le(InfoFlag.INFO_MOUSE | InfoFlag.INFO_UNICODE | InfoFlag.INFO_LOGONNOTIFY | InfoFlag.INFO_LOGONERRORS)
|
|
||||||
self.cbDomain = UInt16Le(lambda:sizeof(self.domain) - 2)
|
|
||||||
self.cbUserName = UInt16Le(lambda:sizeof(self.userName) - 2)
|
|
||||||
self.cbPassword = UInt16Le(lambda:sizeof(self.password) - 2)
|
|
||||||
self.cbAlternateShell = UInt16Le(lambda:sizeof(self.alternateShell) - 2)
|
|
||||||
self.cbWorkingDir = UInt16Le(lambda:sizeof(self.workingDir) - 2)
|
|
||||||
#microsoft domain
|
|
||||||
self.domain = String(readLen = UInt16Le(lambda:self.cbDomain.value + 2), unicode = True)
|
|
||||||
self.userName = String(readLen = UInt16Le(lambda:self.cbUserName.value + 2), unicode = True)
|
|
||||||
self.password = String(readLen = UInt16Le(lambda:self.cbPassword.value + 2), unicode = True)
|
|
||||||
#shell execute at start of session
|
|
||||||
self.alternateShell = String(readLen = UInt16Le(lambda:self.cbAlternateShell.value + 2), unicode = True)
|
|
||||||
#working directory for session
|
|
||||||
self.workingDir = String(readLen = UInt16Le(lambda:self.cbWorkingDir.value + 2), unicode = True)
|
|
||||||
self.extendedInfo = RDPExtendedInfo(conditional = extendedInfoConditional)
|
|
||||||
|
|
||||||
class RDPExtendedInfo(CompositeType):
|
|
||||||
"""
|
|
||||||
Add more client informations
|
|
||||||
"""
|
|
||||||
def __init__(self, conditional):
|
|
||||||
CompositeType.__init__(self, conditional = conditional)
|
|
||||||
self.clientAddressFamily = UInt16Le(AfInet.AF_INET)
|
|
||||||
self.cbClientAddress = UInt16Le(lambda:sizeof(self.clientAddress))
|
|
||||||
self.clientAddress = String(readLen = self.cbClientAddress, unicode = True)
|
|
||||||
self.cbClientDir = UInt16Le(lambda:sizeof(self.clientDir))
|
|
||||||
self.clientDir = String(readLen = self.cbClientDir, unicode = True)
|
|
||||||
#TODO make tiomezone
|
|
||||||
self.clientTimeZone = String("\x00" * 172)
|
|
||||||
self.clientSessionId = UInt32Le()
|
|
||||||
self.performanceFlags = UInt32Le()
|
|
||||||
|
|
||||||
class ShareControlHeader(CompositeType):
|
class ShareControlHeader(CompositeType):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -78,9 +78,6 @@ class PDULayer(LayerAutomata):
|
|||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
LayerAutomata.__init__(self, None)
|
LayerAutomata.__init__(self, None)
|
||||||
|
|
||||||
#logon info send from client to server
|
|
||||||
self._info = data.RDPInfo(extendedInfoConditional = lambda:(self._transport.getGCCServerSettings().getBlock(gcc.MessageType.SC_CORE).rdpVersion.value == gcc.Version.RDP_VERSION_5_PLUS))
|
|
||||||
#server capabilities
|
#server capabilities
|
||||||
self._serverCapabilities = {
|
self._serverCapabilities = {
|
||||||
caps.CapsType.CAPSTYPE_GENERAL : caps.Capability(caps.GeneralCapability()),
|
caps.CapsType.CAPSTYPE_GENERAL : caps.Capability(caps.GeneralCapability()),
|
||||||
@@ -328,13 +325,6 @@ class Client(PDULayer, tpkt.IFastPathListener):
|
|||||||
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)
|
||||||
|
|
||||||
def sendInfoPkt(self):
|
|
||||||
"""
|
|
||||||
@summary: Send a logon info packet
|
|
||||||
client automata data
|
|
||||||
"""
|
|
||||||
self._transport.send((UInt16Le(data.SecurityFlag.SEC_INFO_PKT), UInt16Le(), self._info))
|
|
||||||
|
|
||||||
def sendLicensePacket(self, licPkt):
|
def sendLicensePacket(self, licPkt):
|
||||||
"""
|
"""
|
||||||
@summary: send license packet
|
@summary: send license packet
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ Some use full methods for security in RDP
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import sha, md5, rsa, gcc, rc4
|
import sha, md5, rsa, gcc, rc4
|
||||||
from rdpy.network.type import CompositeType, Stream, UInt32Le, String, sizeof
|
from rdpy.network.type import CompositeType, Stream, UInt32Le, UInt16Le, String, sizeof
|
||||||
from rdpy.network.layer import LayerAutomata, IStreamSender
|
from rdpy.network.layer import LayerAutomata, IStreamSender
|
||||||
|
|
||||||
class SecurityFlag(object):
|
class SecurityFlag(object):
|
||||||
@@ -46,6 +46,50 @@ class SecurityFlag(object):
|
|||||||
SEC_AUTODETECT_RSP = 0x2000
|
SEC_AUTODETECT_RSP = 0x2000
|
||||||
SEC_HEARTBEAT = 0x4000
|
SEC_HEARTBEAT = 0x4000
|
||||||
SEC_FLAGSHI_VALID = 0x8000
|
SEC_FLAGSHI_VALID = 0x8000
|
||||||
|
|
||||||
|
class InfoFlag(object):
|
||||||
|
"""
|
||||||
|
Client capabilities informations
|
||||||
|
"""
|
||||||
|
INFO_MOUSE = 0x00000001
|
||||||
|
INFO_DISABLECTRLALTDEL = 0x00000002
|
||||||
|
INFO_AUTOLOGON = 0x00000008
|
||||||
|
INFO_UNICODE = 0x00000010
|
||||||
|
INFO_MAXIMIZESHELL = 0x00000020
|
||||||
|
INFO_LOGONNOTIFY = 0x00000040
|
||||||
|
INFO_COMPRESSION = 0x00000080
|
||||||
|
INFO_ENABLEWINDOWSKEY = 0x00000100
|
||||||
|
INFO_REMOTECONSOLEAUDIO = 0x00002000
|
||||||
|
INFO_FORCE_ENCRYPTED_CS_PDU = 0x00004000
|
||||||
|
INFO_RAIL = 0x00008000
|
||||||
|
INFO_LOGONERRORS = 0x00010000
|
||||||
|
INFO_MOUSE_HAS_WHEEL = 0x00020000
|
||||||
|
INFO_PASSWORD_IS_SC_PIN = 0x00040000
|
||||||
|
INFO_NOAUDIOPLAYBACK = 0x00080000
|
||||||
|
INFO_USING_SAVED_CREDS = 0x00100000
|
||||||
|
INFO_AUDIOCAPTURE = 0x00200000
|
||||||
|
INFO_VIDEO_DISABLE = 0x00400000
|
||||||
|
INFO_CompressionTypeMask = 0x00001E00
|
||||||
|
|
||||||
|
class PerfFlag(object):
|
||||||
|
"""
|
||||||
|
Network performances flag
|
||||||
|
"""
|
||||||
|
PERF_DISABLE_WALLPAPER = 0x00000001
|
||||||
|
PERF_DISABLE_FULLWINDOWDRAG = 0x00000002
|
||||||
|
PERF_DISABLE_MENUANIMATIONS = 0x00000004
|
||||||
|
PERF_DISABLE_THEMING = 0x00000008
|
||||||
|
PERF_DISABLE_CURSOR_SHADOW = 0x00000020
|
||||||
|
PERF_DISABLE_CURSORSETTINGS = 0x00000040
|
||||||
|
PERF_ENABLE_FONT_SMOOTHING = 0x00000080
|
||||||
|
PERF_ENABLE_DESKTOP_COMPOSITION = 0x00000100
|
||||||
|
|
||||||
|
class AfInet(object):
|
||||||
|
"""
|
||||||
|
IPv4 or IPv6 address style
|
||||||
|
"""
|
||||||
|
AF_INET = 0x00002
|
||||||
|
AF_INET6 = 0x0017
|
||||||
|
|
||||||
def saltedHash(inputData, salt, salt1, salt2):
|
def saltedHash(inputData, salt, salt1, salt2):
|
||||||
"""
|
"""
|
||||||
@@ -140,6 +184,11 @@ def bin2bn(b):
|
|||||||
return l
|
return l
|
||||||
|
|
||||||
def bn2bin(b):
|
def bn2bin(b):
|
||||||
|
"""
|
||||||
|
@summary: convert Big number to binary
|
||||||
|
@param b: bignumber (long)
|
||||||
|
@return: binary stream
|
||||||
|
"""
|
||||||
s = bytearray()
|
s = bytearray()
|
||||||
i = (b.bit_length() + 7) / 8
|
i = (b.bit_length() + 7) / 8
|
||||||
while i > 0:
|
while i > 0:
|
||||||
@@ -147,7 +196,6 @@ def bn2bin(b):
|
|||||||
i -= 1
|
i -= 1
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
class ClientSecurityExchangePDU(CompositeType):
|
class ClientSecurityExchangePDU(CompositeType):
|
||||||
"""
|
"""
|
||||||
@summary: contain client random for basic security
|
@summary: contain client random for basic security
|
||||||
@@ -157,6 +205,49 @@ class ClientSecurityExchangePDU(CompositeType):
|
|||||||
CompositeType.__init__(self)
|
CompositeType.__init__(self)
|
||||||
self.length = UInt32Le(lambda:(sizeof(self) - 4))
|
self.length = UInt32Le(lambda:(sizeof(self) - 4))
|
||||||
self.encryptedClientRandom = String(readLen = self.length)
|
self.encryptedClientRandom = String(readLen = self.length)
|
||||||
|
|
||||||
|
class RDPInfo(CompositeType):
|
||||||
|
"""
|
||||||
|
Client informations
|
||||||
|
Contains credentials (very important packet)
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240475.aspx
|
||||||
|
"""
|
||||||
|
def __init__(self, extendedInfoConditional):
|
||||||
|
CompositeType.__init__(self)
|
||||||
|
#code page
|
||||||
|
self.codePage = UInt32Le()
|
||||||
|
#support flag
|
||||||
|
self.flag = UInt32Le(InfoFlag.INFO_MOUSE | InfoFlag.INFO_UNICODE | InfoFlag.INFO_LOGONNOTIFY | InfoFlag.INFO_LOGONERRORS)
|
||||||
|
self.cbDomain = UInt16Le(lambda:sizeof(self.domain) - 2)
|
||||||
|
self.cbUserName = UInt16Le(lambda:sizeof(self.userName) - 2)
|
||||||
|
self.cbPassword = UInt16Le(lambda:sizeof(self.password) - 2)
|
||||||
|
self.cbAlternateShell = UInt16Le(lambda:sizeof(self.alternateShell) - 2)
|
||||||
|
self.cbWorkingDir = UInt16Le(lambda:sizeof(self.workingDir) - 2)
|
||||||
|
#microsoft domain
|
||||||
|
self.domain = String(readLen = UInt16Le(lambda:self.cbDomain.value + 2), unicode = True)
|
||||||
|
self.userName = String(readLen = UInt16Le(lambda:self.cbUserName.value + 2), unicode = True)
|
||||||
|
self.password = String(readLen = UInt16Le(lambda:self.cbPassword.value + 2), unicode = True)
|
||||||
|
#shell execute at start of session
|
||||||
|
self.alternateShell = String(readLen = UInt16Le(lambda:self.cbAlternateShell.value + 2), unicode = True)
|
||||||
|
#working directory for session
|
||||||
|
self.workingDir = String(readLen = UInt16Le(lambda:self.cbWorkingDir.value + 2), unicode = True)
|
||||||
|
self.extendedInfo = RDPExtendedInfo(conditional = extendedInfoConditional)
|
||||||
|
|
||||||
|
class RDPExtendedInfo(CompositeType):
|
||||||
|
"""
|
||||||
|
Add more client informations
|
||||||
|
"""
|
||||||
|
def __init__(self, conditional):
|
||||||
|
CompositeType.__init__(self, conditional = conditional)
|
||||||
|
self.clientAddressFamily = UInt16Le(AfInet.AF_INET)
|
||||||
|
self.cbClientAddress = UInt16Le(lambda:sizeof(self.clientAddress))
|
||||||
|
self.clientAddress = String(readLen = self.cbClientAddress, unicode = True)
|
||||||
|
self.cbClientDir = UInt16Le(lambda:sizeof(self.clientDir))
|
||||||
|
self.clientDir = String(readLen = self.cbClientDir, unicode = True)
|
||||||
|
#TODO make tiomezone
|
||||||
|
self.clientTimeZone = String("\x00" * 172)
|
||||||
|
self.clientSessionId = UInt32Le()
|
||||||
|
self.performanceFlags = UInt32Le()
|
||||||
|
|
||||||
class SecLayer(LayerAutomata, IStreamSender):
|
class SecLayer(LayerAutomata, IStreamSender):
|
||||||
"""
|
"""
|
||||||
@@ -165,30 +256,10 @@ class SecLayer(LayerAutomata, IStreamSender):
|
|||||||
"""
|
"""
|
||||||
def __init__(self, presentation):
|
def __init__(self, presentation):
|
||||||
LayerAutomata.__init__(self, presentation)
|
LayerAutomata.__init__(self, presentation)
|
||||||
|
self._info = RDPInfo(extendedInfoConditional = lambda:(self._transport.getGCCServerSettings().getBlock(gcc.MessageType.SC_CORE).rdpVersion.value == gcc.Version.RDP_VERSION_5_PLUS))
|
||||||
self._enableEncryption = False
|
self._enableEncryption = False
|
||||||
|
self._decryt = None
|
||||||
def connect(self):
|
self._encrypt = None
|
||||||
"""
|
|
||||||
@summary: send client random
|
|
||||||
"""
|
|
||||||
self._enableEncryption = (self._transport.getGCCClientSettings.getBlock(gcc.MessageType.CS_CORE).serverSelectedProtocol == 0)
|
|
||||||
if not self._enableEncryption:
|
|
||||||
self._presentation.connect()
|
|
||||||
return
|
|
||||||
|
|
||||||
#generate client random
|
|
||||||
self._clientRandom = rsa.randnum.read_random_bits(128)
|
|
||||||
self._serverRandom = self._transport.getGCCServerSettings().getBlock(gcc.MessageType.SC_SECURITY).serverRandom.value
|
|
||||||
self.generateKeys()
|
|
||||||
|
|
||||||
#send client random encrypted with
|
|
||||||
certificate = self._transport.getGCCServerSettings().getBlock(gcc.MessageType.SC_SECURITY).serverCertificate.certData
|
|
||||||
serverPublicKey = rsa.PublicKey(bin2bn(certificate.PublicKeyBlob.modulus.value), certificate.PublicKeyBlob.pubExp.value)
|
|
||||||
|
|
||||||
message = ClientSecurityExchangePDU()
|
|
||||||
message.encryptedClientRandom.value = rsa.encrypt(self._clientRandom, serverPublicKey)
|
|
||||||
self._transport.send(message)
|
|
||||||
self._presentation.connect()
|
|
||||||
|
|
||||||
def generateKeys(self):
|
def generateKeys(self):
|
||||||
"""
|
"""
|
||||||
@@ -197,10 +268,7 @@ class SecLayer(LayerAutomata, IStreamSender):
|
|||||||
preMasterSecret = self._clientRandom[:24] + self._serverRandom[:24]
|
preMasterSecret = self._clientRandom[:24] + self._serverRandom[:24]
|
||||||
masterSecret = generateMicrosoftKeyABBCCC(preMasterSecret, self._clientRandom, self._serverRandom)
|
masterSecret = generateMicrosoftKeyABBCCC(preMasterSecret, self._clientRandom, self._serverRandom)
|
||||||
self._sessionKey = generateMicrosoftKeyXYYZZZ(masterSecret, self._clientRandom, self._serverRandom)
|
self._sessionKey = generateMicrosoftKeyXYYZZZ(masterSecret, self._clientRandom, self._serverRandom)
|
||||||
|
|
||||||
self._macKey128 = self._sessionKey[:16]
|
self._macKey128 = self._sessionKey[:16]
|
||||||
self._decrypt = finalHash(self._sessionKey[16:32], self._clientRandom, self._serverRandom)
|
|
||||||
self._encrypt = finalHash(self._sessionKey[32:48], self._clientRandom, self._serverRandom)
|
|
||||||
|
|
||||||
def recv(self, data):
|
def recv(self, data):
|
||||||
if not self._enableEncryption:
|
if not self._enableEncryption:
|
||||||
@@ -211,6 +279,34 @@ class SecLayer(LayerAutomata, IStreamSender):
|
|||||||
if not self._enableEncryption:
|
if not self._enableEncryption:
|
||||||
self._presentation.recv(data)
|
self._presentation.recv(data)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def sendFlag(self, flag, data):
|
||||||
|
if self._enableEncryption:
|
||||||
|
flag |= SecurityFlag.SEC_ENCRYPT
|
||||||
|
self._transport.send((UInt16Le(flag), UInt16Le(), data))
|
||||||
|
|
||||||
def sendInfoPkt(self, data):
|
class SecClient(SecLayer):
|
||||||
self._transport.send()
|
def connect(self):
|
||||||
|
"""
|
||||||
|
@summary: send client random
|
||||||
|
"""
|
||||||
|
if self._transport.getGCCClientSettings.getBlock(gcc.MessageType.CS_CORE).serverSelectedProtocol == 0:
|
||||||
|
#generate client random
|
||||||
|
self._clientRandom = rsa.randnum.read_random_bits(128)
|
||||||
|
self._serverRandom = self._transport.getGCCServerSettings().getBlock(gcc.MessageType.SC_SECURITY).serverRandom.value
|
||||||
|
self.generateKeys()
|
||||||
|
|
||||||
|
self._decrypt = finalHash(self._sessionKey[16:32], self._clientRandom, self._serverRandom)
|
||||||
|
self._encrypt = finalHash(self._sessionKey[32:48], self._clientRandom, self._serverRandom)
|
||||||
|
|
||||||
|
#send client random encrypted with
|
||||||
|
certificate = self._transport.getGCCServerSettings().getBlock(gcc.MessageType.SC_SECURITY).serverCertificate.certData
|
||||||
|
serverPublicKey = rsa.PublicKey(bin2bn(certificate.PublicKeyBlob.modulus.value), certificate.PublicKeyBlob.pubExp.value)
|
||||||
|
|
||||||
|
message = ClientSecurityExchangePDU()
|
||||||
|
message.encryptedClientRandom.value = rsa.encrypt(self._clientRandom, serverPublicKey)
|
||||||
|
self.send(SecurityFlag.SEC_EXCHANGE_PKT, message)
|
||||||
|
self._enableEncryption = True
|
||||||
|
|
||||||
|
self.send(SecurityFlag.SEC_INFO_PKT, self._info)
|
||||||
|
self._presentation.connect()
|
||||||
Reference in New Issue
Block a user