move info packet to security layer
This commit is contained in:
@@ -27,50 +27,6 @@ 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):
|
||||
"""
|
||||
Data PDU type primary index
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
@@ -47,6 +47,50 @@ class SecurityFlag(object):
|
||||
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):
|
||||
"""
|
||||
@summary: Generate particular signature from combination of sha1 and md5
|
||||
@@ -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
|
||||
@@ -158,6 +206,49 @@ class ClientSecurityExchangePDU(CompositeType):
|
||||
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):
|
||||
"""
|
||||
@summary: Basic RDP security manager
|
||||
@@ -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:
|
||||
@@ -212,5 +280,33 @@ class SecLayer(LayerAutomata, IStreamSender):
|
||||
self._presentation.recv(data)
|
||||
return
|
||||
|
||||
def sendInfoPkt(self, data):
|
||||
self._transport.send()
|
||||
def sendFlag(self, flag, data):
|
||||
if self._enableEncryption:
|
||||
flag |= SecurityFlag.SEC_ENCRYPT
|
||||
self._transport.send((UInt16Le(flag), UInt16Le(), data))
|
||||
|
||||
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()
|
||||
Reference in New Issue
Block a user