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

@@ -5,40 +5,43 @@
import struct
from copy import deepcopy
from StringIO import StringIO
from error import InvalidValue, InvalidType
from error import InvalidValue, InvalidSize
from rdpy.protocol.network.error import InvalidExpectedDataException
def sizeof(element):
'''
byte size of type
@param element: Type or Tuple(Type | Tuple,)
@return: size of element in byte
@raise InvalidType: if type is different than tuple of Type inheritance
'''
if isinstance(element, tuple):
size = 0
for i in element:
size += sizeof(i)
return size
elif isinstance(element, Type):
elif isinstance(element, Type) and element._conditional():
return element.__sizeof__()
raise InvalidType("invalid type for sizeof")
return 0
class Type(object):
'''
root type
'''
def __init__(self, write_if = lambda:True, read_if = lambda:True):
self._write_if = write_if
self._read_if = read_if
def __init__(self, conditional = lambda:True, optional = False, constant = False):
self._conditional = conditional
self._optional = optional
self._constant = constant
self._is_writed = False
self._is_readed = False
def write(self, s):
'''
interface definition of write function
@param s: Stream which will be written
'''
if not self._write_if():
self._is_writed = self._conditional()
if not self._is_writed:
return
self.__write__(s)
@@ -46,11 +49,15 @@ class Type(object):
'''
interface definition of read value
@param s: Stream
@return: Type read from Stream s
'''
if not self._read_if():
self._is_readed = self._conditional()
if not self._is_readed:
return
old = deepcopy(self)
self.__read__(s)
#check constant value
if self._constant and old != self:
raise InvalidExpectedDataException("const value expected")
def __sizeof__(self):
'''
@@ -59,15 +66,14 @@ class Type(object):
'''
pass
class ValueType(Type):
class CallableValue(object):
'''
type that wrap an inner type
acces with value getter and setter
value can be a callable which is call
at each access of value
'''
def __init__(self, value, write_if = lambda:True, read_if = lambda:True):
Type.__init__(self, write_if = write_if, read_if = read_if)
def __init__(self, value):
self._value = None
self.value = value
@@ -102,16 +108,15 @@ class ValueType(Type):
def value(self, value):
'''
setter of value after check it
@param value: new value encompass in simpletype object
@raise InvalidValue: if value doesn't respect type range
@param value: new value encompass in valuetype object
'''
self.__setValue__(value)
class SimpleType(ValueType):
class SimpleType(Type, CallableValue):
'''
simple type
'''
def __init__(self, structFormat, typeSize, signed, value, write_if = lambda:True, read_if = lambda:True):
def __init__(self, structFormat, typeSize, signed, value, conditional = lambda:True, optional = False, constant = False):
'''
constructor of simple type
@param structFormat: letter that represent type in struct package
@@ -122,7 +127,8 @@ class SimpleType(ValueType):
self._signed = signed
self._typeSize = typeSize
self._structFormat = structFormat
ValueType.__init__(self, value, write_if = write_if, read_if = read_if)
Type.__init__(self, conditional = conditional, optional = optional, constant = constant)
CallableValue.__init__(self, value)
def __getValue__(self):
'''
@@ -130,7 +136,7 @@ class SimpleType(ValueType):
@return: inner value(python type value)
@raise InvalidValue: if value doesn't respect type range
'''
value = ValueType.__getValue__(self)
value = CallableValue.__getValue__(self)
if not self.isInRange(value):
raise InvalidValue("value is out of range for %s"%self.__class__)
@@ -149,7 +155,7 @@ class SimpleType(ValueType):
if not callable(value) and not self.isInRange(value):
raise InvalidValue("value is out of range for %s"%self.__class__)
ValueType.__setValue__(self, value)
CallableValue.__setValue__(self, value)
def __cmp__(self, other):
@@ -299,11 +305,11 @@ class CompositeType(Type):
keep ordering declaration of simple type
in list and transparent for other type
'''
def __init__(self, write_if = lambda:True, read_if = lambda:True):
def __init__(self, conditional = lambda:True, optional = False, constant = False):
'''
init list of simple value
'''
Type.__init__(self, write_if = write_if, read_if = read_if)
Type.__init__(self, conditional = conditional, optional = optional, constant = constant)
#list of ordoned type
self._typeName = []
@@ -369,15 +375,15 @@ class UInt8(SimpleType):
'''
unsigned byte
'''
def __init__(self, value = 0, write_if = lambda:True, read_if = lambda:True):
SimpleType.__init__(self, "B", 1, False, value, write_if = write_if, read_if = read_if)
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
SimpleType.__init__(self, "B", 1, False, value, conditional = conditional, optional = optional, constant = constant)
class SInt8(SimpleType):
'''
signed byte
'''
def __init__(self, value = 0, write_if = lambda:True, read_if = lambda:True):
SimpleType.__init__(self, "b", 1, True, value, write_if = write_if, read_if = read_if)
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
SimpleType.__init__(self, "b", 1, True, value, conditional = conditional, optional = optional, constant = constant)
class UInt16Be(SimpleType):
@@ -386,8 +392,8 @@ class UInt16Be(SimpleType):
@attention: inner value is in machine representation
Big endian is just for read or write in stream
'''
def __init__(self, value = 0, write_if = lambda:True, read_if = lambda:True):
SimpleType.__init__(self, ">H", 2, False, value, write_if = write_if, read_if = read_if)
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
SimpleType.__init__(self, ">H", 2, False, value, conditional = conditional, optional = optional, constant = constant)
class UInt16Le(SimpleType):
'''
@@ -395,8 +401,8 @@ class UInt16Le(SimpleType):
@attention: inner value is in machine representation
Big endian is just for read or write in stream
'''
def __init__(self, value = 0, write_if = lambda:True, read_if = lambda:True):
SimpleType.__init__(self, "<H", 2, False, value, write_if = write_if, read_if = read_if)
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
SimpleType.__init__(self, "<H", 2, False, value, conditional = conditional, optional = optional, constant = constant)
class UInt32Be(SimpleType):
'''
@@ -404,8 +410,8 @@ class UInt32Be(SimpleType):
@attention: inner value is in machine representation
Big endian is just for read or write in stream
'''
def __init__(self, value = 0, write_if = lambda:True, read_if = lambda:True):
SimpleType.__init__(self, ">I", 4, False, value, write_if = write_if, read_if = read_if)
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
SimpleType.__init__(self, ">I", 4, False, value, conditional = conditional, optional = optional, constant = constant)
class UInt32Le(SimpleType):
'''
@@ -413,8 +419,8 @@ class UInt32Le(SimpleType):
@attention: inner value is in machine representation
Big endian is just for read or write in stream
'''
def __init__(self, value = 0, write_if = lambda:True, read_if = lambda:True):
SimpleType.__init__(self, "<I", 4, False, value, write_if = write_if, read_if = read_if)
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
SimpleType.__init__(self, "<I", 4, False, value, conditional = conditional, optional = optional, constant = constant)
class SInt32Le(SimpleType):
'''
@@ -422,8 +428,8 @@ class SInt32Le(SimpleType):
@attention: inner value is in machine representation
Big endian is just for read or write in stream
'''
def __init__(self, value = 0, write_if = lambda:True, read_if = lambda:True):
SimpleType.__init__(self, "<I", 4, True, value, write_if = write_if, read_if = read_if)
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
SimpleType.__init__(self, "<I", 4, True, value, conditional = conditional, optional = optional, constant = constant)
class SInt32Be(SimpleType):
'''
@@ -431,8 +437,8 @@ class SInt32Be(SimpleType):
@attention: inner value is in machine representation
Big endian is just for read or write in stream
'''
def __init__(self, value = 0, write_if = lambda:True, read_if = lambda:True):
SimpleType.__init__(self, ">I", 4, True, value, write_if = write_if, read_if = read_if)
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
SimpleType.__init__(self, ">I", 4, True, value, conditional = conditional, optional = optional, constant = constant)
class UInt24Be(SimpleType):
'''
@@ -440,8 +446,8 @@ class UInt24Be(SimpleType):
@attention: inner value is in machine representation
Big endian is just for read or write in stream
'''
def __init__(self, value = 0, write_if = lambda:True, read_if = lambda:True):
SimpleType.__init__(self, ">I", 3, False, value, write_if = write_if, read_if = read_if)
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
SimpleType.__init__(self, ">I", 3, False, value, conditional = conditional, optional = optional, constant = constant)
def __write__(self, s):
'''
@@ -455,8 +461,8 @@ class UInt24Le(SimpleType):
@attention: inner value is in machine representation
Big endian is just for read or write in stream
'''
def __init__(self, value = 0, write_if = lambda:True, read_if = lambda:True):
SimpleType.__init__(self, "<I", 3, False, value, write_if = write_if, read_if = read_if)
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
SimpleType.__init__(self, "<I", 3, False, value, conditional = conditional, optional = optional, constant = constant)
def __write__(self, s):
'''
@@ -466,16 +472,17 @@ class UInt24Le(SimpleType):
#don't write first byte
s.write(struct.pack("<I", self.value)[1:])
class String(ValueType):
class String(Type, CallableValue):
'''
String network type
'''
def __init__(self, value = "", write_if = lambda:True, read_if = lambda:True):
def __init__(self, value = "", conditional = lambda:True, optional = False, constant = False):
'''
constructor with new string
@param value: python string use for inner value
'''
ValueType.__init__(self, value, write_if = write_if, read_if = read_if)
Type.__init__(self, conditional = conditional, optional = optional, constant = constant)
CallableValue.__init__(self, value)
def __eq__(self, other):
'''
@@ -572,6 +579,8 @@ class Stream(StringIO):
or iterate over tuple elements
@param value: (tuple | Type) object
'''
if sizeof(value) > self.dataLen() and not value._optional:
raise InvalidSize("stream is too short to read non optional value")
#read each tuple
if isinstance(value, tuple):
for element in value:

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