add context value + conditional type and constant type

This commit is contained in:
speyrefitte
2013-12-06 16:53:41 +01:00
parent 65d1ef89f5
commit e32def4f50
4 changed files with 189 additions and 124 deletions

View File

@@ -7,15 +7,23 @@ from rdpy.protocol.network.type import CompositeType, UniString, UInt16Le, UInt1
from rdpy.utils.const import ConstAttributes, TypeAttributes
from rdpy.protocol.network.error import InvalidExpectedDataException
import gcc
@ConstAttributes
@TypeAttributes(UInt16Le)
class SecurityFlag(object):
'''
microsoft security flags
'''
SEC_INFO_PKT = 0x0040
SEC_LICENSE_PKT = 0x0080
@ConstAttributes
@TypeAttributes(UInt32Le)
class InfoFlag(object):
'''
client capabilities informations
'''
INFO_MOUSE = 0x00000001
INFO_DISABLECTRLALTDEL = 0x00000002
INFO_AUTOLOGON = 0x00000008
@@ -39,6 +47,9 @@ class InfoFlag(object):
@ConstAttributes
@TypeAttributes(UInt32Le)
class PerfFlag(object):
'''
network performances flag
'''
PERF_DISABLE_WALLPAPER = 0x00000001
PERF_DISABLE_FULLWINDOWDRAG = 0x00000002
PERF_DISABLE_MENUANIMATIONS = 0x00000004
@@ -55,29 +66,58 @@ class AfInet(object):
AF_INET6 = 0x0017
class RDPInfo(CompositeType):
def __init__(self):
'''
client informations
contains credentials (very important packet)
'''
def __init__(self, initForWrite, extendedInfoConditional):
CompositeType.__init__(self)
#code page
self.codePage = UInt32Le()
self.flag = InfoFlag.INFO_MOUSE | InfoFlag.INFO_UNICODE | InfoFlag.INFO_LOGONERRORS | InfoFlag.INFO_LOGONNOTIFY | InfoFlag.INFO_ENABLEWINDOWSKEY | InfoFlag.INFO_DISABLECTRLALTDEL
self.cbDomain = UInt16Le(lambda:sizeof(self.domain) - 2)
self.cbUserName = UInt16Le(lambda:sizeof(self.userName) - 2)
self.cbPassword = UInt16Le(lambda:sizeof(self.password) - 2)
#support flag
self.flag = InfoFlag.INFO_MOUSE | InfoFlag.INFO_UNICODE | InfoFlag.INFO_LOGONERRORS | InfoFlag.INFO_LOGONNOTIFY | InfoFlag.INFO_ENABLEWINDOWSKEY | InfoFlag.INFO_DISABLECTRLALTDEL
#length of domain unistring less 2 byte null terminate
self.cbDomain = UInt16Le(lambda:sizeof(self.domain) - 2)
#length of username unistring less 2 byte null terminate
self.cbUserName = UInt16Le(lambda:sizeof(self.userName) - 2)
#length of password unistring less 2 byte null terminate
self.cbPassword = UInt16Le(lambda:sizeof(self.password) - 2)
#length of alternateshell unistring less 2 byte null terminate
self.cbAlternateShell = UInt16Le(lambda:sizeof(self.alternateShell) - 2)
#length of working directory unistring less 2 byte null terminate
self.cbWorkingDir = UInt16Le(lambda:sizeof(self.workingDir) - 2)
self.domain = UniString("coco")
self.userName = UniString("lolo")
self.password = UniString("toto")
self.alternateShell = UniString()
self.workingDir = UniString()
#to avoid recurcive loop init differ from reading and writing
#microsoft domain
self.domain = UniString("" if initForWrite else lambda:"\x00" * self.cbDomain.value)
#session username
self.userName = UniString("" if initForWrite else lambda:"\x00" * self.cbUserName.value)
#associate password
self.password = UniString("" if initForWrite else lambda:"\x00" * self.cbPassword.value)
#shell execute at start of session
self.alternateShell = UniString("" if initForWrite else lambda:"\x00" * self.cbAlternateShell.value)
#working directory for session
self.workingDir = UniString("" if initForWrite else lambda:"\x00" * self.cbWorkingDir.value)
#more client informations
self.extendedInfo = RDPExtendedInfo(initForWrite, conditional = extendedInfoConditional)
class RDPExtendedInfo(CompositeType):
def __init__(self):
CompositeType.__init__(self)
'''
add more client informations
use for performance flag!!!
'''
def __init__(self, initForWrite, conditional):
CompositeType.__init__(self, conditional = conditional)
#is an ip v4 or v6 adresse
self.clientAddressFamily = AfInet.AF_INET
#len of adress field
self.cbClientAddress = UInt16Le(lambda:sizeof(self.clientAddress))
self.clientAddress = UniString("192.168.135.10")
#adress of client
self.clientAddress = UniString("" if initForWrite else lambda:"\x00" * self.cbClientAddress.value)
#len of client directory
self.cbClientDir = UInt16Le(lambda:sizeof(self.clientDir))
self.clientDir = UniString("c:\\")
#self client directory
self.clientDir = UniString("" if initForWrite else lambda:"\x00" * self.cbClientDir.value)
#TODO make tiomezone
#self.performanceFlags = PerfFlag.PERF_DISABLE_WALLPAPER | PerfFlag.PERF_DISABLE_MENUANIMATIONS | PerfFlag.PERF_DISABLE_CURSOR_SHADOW
class GDL(LayerAutomata):
@@ -94,8 +134,7 @@ class GDL(LayerAutomata):
#set by mcs layer channel init
self._channelId = UInt16Be()
#logon info send from client to server
self._info = RDPInfo()
self._extendedInfo = RDPExtendedInfo()
self._info = RDPInfo(initForWrite = True, extendedInfoConditional = lambda:self._transport._serverSettings.core.rdpVersion == gcc.Version.RDP_VERSION_5_PLUS)
def connect(self):
'''
@@ -111,7 +150,7 @@ class GDL(LayerAutomata):
send a logon info packet for RDP version 5 protocol
'''
#always send extended info because rdpy only accept rdp version 5 and more
self._transport.send(self._channelId, (SecurityFlag.SEC_INFO_PKT, UInt16Le(), self._info, self._extendedInfo))
self._transport.send(self._channelId, (SecurityFlag.SEC_INFO_PKT, UInt16Le(), self._info))
def recvLicenceInfo(self, data):
securityFlag = UInt16Le()

25
rdpy/protocol/rdp/lic.py Normal file
View File

@@ -0,0 +1,25 @@
'''
@author: sylvain
'''
from rdpy.protocol.network.type import CompositeType, UInt8, UInt16Le, sizeof
from rdpy.utils.const import ConstAttributes, TypeAttributes
@ConstAttributes
@TypeAttributes(UInt8)
class MessageType(object):
LICENSE_REQUEST = 0x01
PLATFORM_CHALLENGE = 0x02
NEW_LICENSE = 0x03
UPGRADE_LICENSE = 0x04
LICENSE_INFO = 0x12
NEW_LICENSE_REQUEST = 0x13
PLATFORM_CHALLENGE_RESPONSE = 0x15
ERROR_ALERT = 0xFF
class LicPacket(CompositeType):
def __init__(self):
#preambule
self.bMsgtype = UInt8()
self.flag = UInt8()
self.wMsgSize = UInt16Le(lambda: sizeof(self))

View File

@@ -3,7 +3,7 @@
'''
from rdpy.protocol.network.layer import LayerAutomata
from rdpy.protocol.network.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof
from rdpy.protocol.network.error import InvalidExpectedDataException, NegotiationFailure
from rdpy.protocol.network.error import InvalidExpectedDataException
from rdpy.utils.const import ConstAttributes, TypeAttributes
@ConstAttributes
@@ -39,15 +39,30 @@ class Protocols(object):
PROTOCOL_HYBRID = 0x00000002
PROTOCOL_HYBRID_EX = 0x00000008
class TPDUConnectHeader(CompositeType):
@ConstAttributes
@TypeAttributes(UInt32Le)
class NegotiationFailureCode(object):
'''
protocol negotiation failure code
'''
SSL_REQUIRED_BY_SERVER = 0x00000001
SSL_NOT_ALLOWED_BY_SERVER = 0x00000002
SSL_CERT_NOT_ON_SERVER = 0x00000003
INCONSISTENT_FLAGS = 0x00000004
HYBRID_REQUIRED_BY_SERVER = 0x00000005
SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006
class TPDUConnectMessage(CompositeType):
'''
header of TPDU connection messages
'''
def __init__(self, code = MessageType.X224_TPDU_CONNECTION_REQUEST, messageSize = 0):
def __init__(self):
CompositeType.__init__(self)
self.len = UInt8(messageSize + 6)
self.code = code
self.len = UInt8(lambda:sizeof(self) - 1)
self.code = UInt8()
self.padding = (UInt16Be(), UInt16Be(), UInt8())
#read if there is enought data
self.protocolNeg = Negotiation(optional = True)
class TPDUDataHeader(CompositeType):
'''
@@ -55,20 +70,22 @@ class TPDUDataHeader(CompositeType):
'''
def __init__(self):
CompositeType.__init__(self)
self.header = UInt8(2)
self.header = UInt8(2, constant = True)
self.messageType = MessageType.X224_TPDU_DATA
self.separator = UInt8(0x80)
self.separator = UInt8(0x80, constant = True)
class Negotiation(CompositeType):
'''
negociation request message
'''
def __init__(self, protocol = Protocols.PROTOCOL_SSL):
CompositeType.__init__(self)
def __init__(self, optional = False):
CompositeType.__init__(self, optional = optional)
self.code = UInt8()
self.flag = UInt8(0)
#always 8
self.len = UInt16Le(0x0008)
self.protocol = protocol
self.len = UInt16Le(0x0008, constant = True)
self.selectedProtocol = UInt32Le(conditional = lambda: self.code == NegociationType.TYPE_RDP_NEG_RSP)
self.failureCode = UInt32Le(conditional = lambda: self.code == NegociationType.TYPE_RDP_NEG_FAILURE)
class TPDU(LayerAutomata):
'''
@@ -81,11 +98,11 @@ class TPDU(LayerAutomata):
@param presentation: MCS layer
'''
LayerAutomata.__init__(self, presentation)
#default protocol is SSl because is the only supported
#default selectedProtocol is SSl because is the only supported
#in this version of RDPY
#client requested protocol
#client requested selectedProtocol
self._requestedProtocol = Protocols.PROTOCOL_SSL
#server selected protocol
#server selected selectedProtocol
self._selectedProtocol = Protocols.PROTOCOL_SSL
def connect(self):
@@ -102,15 +119,24 @@ class TPDU(LayerAutomata):
call connect on presentation layer if all is good
@param data: Stream that contain connection confirm
'''
header = TPDUConnectHeader()
data.readType(header)
if header.code != MessageType.X224_TPDU_CONNECTION_CONFIRM:
raise InvalidExpectedDataException("invalid TPDU header code X224_TPDU_CONNECTION_CONFIRM != %d"%header.code)
message = TPDUConnectMessage()
data.readType(message)
if message.code != MessageType.X224_TPDU_CONNECTION_CONFIRM:
raise InvalidExpectedDataException("invalid TPDU header code X224_TPDU_CONNECTION_CONFIRM != %d"%message.code)
#check presence of negotiation response
if data.dataLen() == 8:
self.readNeg(data)
else:
raise NegotiationFailure("server doesn't support SSL")
if not message.protocolNeg._is_readed:
raise InvalidExpectedDataException("server must support negotiation protocol to use SSL")
if message.protocolNeg.failureCode._is_readed:
raise InvalidExpectedDataException("negotiation failure code %x"%message.protocolNeg.failureCode.value)
self._selectedProtocol = message.protocolNeg.selectedProtocol
if self._selectedProtocol != Protocols.PROTOCOL_SSL:
raise InvalidExpectedDataException("only ssl protocol is supported in RDPY version")
#_transport is TPKT and transport is TCP layer of twisted
self._transport.transport.startTLS(ClientTLSContext())
self.setNextState(self.recvData)
#connection is done send to presentation
@@ -136,8 +162,11 @@ class TPDU(LayerAutomata):
write connection request message
next state is recvConnectionConfirm
'''
neqReq = (NegociationType.TYPE_RDP_NEG_REQ, Negotiation(self._requestedProtocol))
self._transport.send((TPDUConnectHeader(MessageType.X224_TPDU_CONNECTION_REQUEST, sizeof(neqReq)), neqReq))
message = TPDUConnectMessage()
message.code = MessageType.X224_TPDU_CONNECTION_REQUEST
message.protocolNeg.code = NegociationType.TYPE_RDP_NEG_REQ
message.protocolNeg.selectedProtocol = self._requestedProtocol
self._transport.send(message)
self.setNextState(self.recvConnectionConfirm)
def send(self, message):
@@ -146,43 +175,6 @@ class TPDU(LayerAutomata):
add TPDU header
'''
self._transport.send((TPDUDataHeader(), message))
def readNeg(self, data):
'''
read negotiation response
'''
code = UInt8()
data.readType(code)
if code == NegociationType.TYPE_RDP_NEG_FAILURE:
self.readNegFailure(data)
elif code == NegociationType.TYPE_RDP_NEG_RSP:
self.readNegResp(data)
else:
raise InvalidExpectedDataException("bad protocol negotiation response code")
def readNegFailure(self, data):
'''
read negotiation failure packet
'''
print "Negotiation failure"
def readNegResp(self, data):
'''
read negotiation response packet
'''
negResp = Negotiation()
data.readType(negResp)
if negResp.len != UInt16Le(0x0008):
raise InvalidExpectedDataException("invalid size of negotiation response")
self._selectedProtocol = negResp.protocol
if self._selectedProtocol == self._requestedProtocol and self._selectedProtocol == Protocols.PROTOCOL_SSL:
#_transport is TPKT and transport is TCP layer of twisted
self._transport.transport.startTLS(ClientTLSContext())
else:
raise NegotiationFailure("protocol negociation failure")
#open ssl needed