move info packet to security layer

This commit is contained in:
citronneur
2014-12-08 23:05:58 +01:00
parent ccf0156150
commit 551af0aa7a
3 changed files with 127 additions and 126 deletions

View File

@@ -26,50 +26,6 @@ from rdpy.network.type import CompositeType, String, UInt8, UInt16Le, UInt32Le,
from rdpy.base.error import InvalidExpectedDataException
import rdpy.base.log as log
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):
"""
@@ -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).",
}
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):
"""

View File

@@ -78,9 +78,6 @@ class PDULayer(LayerAutomata):
"""
def __init__(self):
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
self._serverCapabilities = {
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:
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):
"""
@summary: send license packet

View File

@@ -22,7 +22,7 @@ Some use full methods for security in RDP
"""
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
class SecurityFlag(object):
@@ -46,6 +46,50 @@ class SecurityFlag(object):
SEC_AUTODETECT_RSP = 0x2000
SEC_HEARTBEAT = 0x4000
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):
"""
@@ -140,6 +184,11 @@ def bin2bn(b):
return l
def bn2bin(b):
"""
@summary: convert Big number to binary
@param b: bignumber (long)
@return: binary stream
"""
s = bytearray()
i = (b.bit_length() + 7) / 8
while i > 0:
@@ -147,7 +196,6 @@ def bn2bin(b):
i -= 1
return s
class ClientSecurityExchangePDU(CompositeType):
"""
@summary: contain client random for basic security
@@ -157,6 +205,49 @@ class ClientSecurityExchangePDU(CompositeType):
CompositeType.__init__(self)
self.length = UInt32Le(lambda:(sizeof(self) - 4))
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):
"""
@@ -165,30 +256,10 @@ class SecLayer(LayerAutomata, IStreamSender):
"""
def __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
def connect(self):
"""
@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()
self._decryt = None
self._encrypt = None
def generateKeys(self):
"""
@@ -197,10 +268,7 @@ class SecLayer(LayerAutomata, IStreamSender):
preMasterSecret = self._clientRandom[:24] + self._serverRandom[:24]
masterSecret = generateMicrosoftKeyABBCCC(preMasterSecret, self._clientRandom, self._serverRandom)
self._sessionKey = generateMicrosoftKeyXYYZZZ(masterSecret, self._clientRandom, self._serverRandom)
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):
if not self._enableEncryption:
@@ -211,6 +279,34 @@ class SecLayer(LayerAutomata, IStreamSender):
if not self._enableEncryption:
self._presentation.recv(data)
return
def sendFlag(self, flag, data):
if self._enableEncryption:
flag |= SecurityFlag.SEC_ENCRYPT
self._transport.send((UInt16Le(flag), UInt16Le(), data))
def sendInfoPkt(self, data):
self._transport.send()
class SecClient(SecLayer):
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()