Files
rdpy/rdpy/protocol/rdp/tpkt.py
2015-02-20 22:13:50 +01:00

235 lines
8.1 KiB
Python

#
# Copyright (c) 2014-2015 Sylvain Peyrefitte
#
# This file is part of rdpy.
#
# rdpy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
"""
Transport packet layer implementation
Use to build correct size packet and handle slow path and fast path mode
"""
from rdpy.core.layer import RawLayer
from rdpy.core.type import UInt8, UInt16Be, sizeof
from rdpy.core.error import CallPureVirtualFuntion
from nla import cssp, ntlm
class Action(object):
"""
@see: http://msdn.microsoft.com/en-us/library/cc240621.aspx
@see: http://msdn.microsoft.com/en-us/library/cc240589.aspx
"""
FASTPATH_ACTION_FASTPATH = 0x0
FASTPATH_ACTION_X224 = 0x3
class SecFlags(object):
"""
@see: http://msdn.microsoft.com/en-us/library/cc240621.aspx
"""
#hihi 'secure' checksum but private key is public !!!
FASTPATH_OUTPUT_SECURE_CHECKSUM = 0x1
FASTPATH_OUTPUT_ENCRYPTED = 0x2
class IFastPathListener(object):
"""
@summary: Fast path packet listener
Usually X224 layer
"""
def recvFastPath(self, secFlag, fastPathS):
"""
@summary: Call when fast path packet is received
@param secFlag: {SecFlags}
@param fastPathS: {Stream}
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recvFastPath", "IFastPathListener"))
def initFastPath(self, fastPathSender):
"""
@summary: initialize stack
@param fastPathSender: {IFastPathSender}
"""
self.setFastPathSender(fastPathSender)
fastPathSender.setFastPathListener(self)
def setFastPathSender(self, fastPathSender):
"""
@param fastPathSender : {IFastPathSender}
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "setFastPathSender", "IFastPathListener"))
class IFastPathSender(object):
"""
@summary: Fast path send capability
"""
def sendFastPath(self, secFlag, fastPathS):
"""
@summary: Send fastPathS Type as fast path packet
@param secFlag: {integer} Security flag for fastpath packet
@param fastPathS: {Type | Tuple} type transform to stream and send as fastpath
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendFastPath", "IFastPathSender"))
def initFastPath(self, fastPathListener):
"""
@summary: initialize stack
@param fastPathListener: {IFastPathListener}
"""
self.setFastPathListener(fastPathListener)
fastPathListener.setFastPathSender(self)
def setFastPathListener(self, fastPathListener):
"""
@param fastPathListener: {IFastPathListener}
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "setFastPathListener", "IFastPathSender"))
class TPKT(RawLayer, IFastPathSender):
"""
@summary: TPKT layer in RDP protocol stack
represent the Raw Layer in stack (first layer)
This layer only handle size of packet and determine if is a fast path packet
"""
def __init__(self, presentation):
"""
@param presentation: {Layer} presentation layer, in RDP case is x224 layer
"""
RawLayer.__init__(self, presentation)
#length may be coded on more than 1 bytes
self._lastShortLength = UInt8()
#fast path listener
self._fastPathListener = None
#last secure flag
self._secFlag = 0
def setFastPathListener(self, fastPathListener):
"""
@param fastPathListener : {IFastPathListener}
@note: implement IFastPathSender
"""
self._fastPathListener = fastPathListener
def connect(self):
"""
@summary: Call when transport layer connection
is made (inherit from RawLayer)
"""
#header is on two bytes
self.expect(2, self.readHeader)
#no connection automata on this layer
if not self._presentation is None:
self._presentation.connect()
def readHeader(self, data):
"""
@summary: Read header of TPKT packet
@param data: {Stream} received from twisted layer
"""
#first read packet version
version = UInt8()
data.readType(version)
#classic packet
if version.value == Action.FASTPATH_ACTION_X224:
#padding
data.readType(UInt8())
#read end header
self.expect(2, self.readExtendedHeader)
else:
#is fast path packet
self._secFlag = ((version.value >> 6) & 0x3)
data.readType(self._lastShortLength)
if self._lastShortLength.value & 0x80:
#size is 1 byte more
self.expect(1, self.readExtendedFastPathHeader)
return
self.expect(self._lastShortLength.value - 2, self.readFastPath)
def readExtendedHeader(self, data):
"""
@summary: Header may be on 4 bytes
@param data: {Stream} from twisted layer
"""
#next state is read data
size = UInt16Be()
data.readType(size)
self.expect(size.value - 4, self.readData)
def readExtendedFastPathHeader(self, data):
"""
@summary: Fast path header may be on 1 byte more
@param data: {Stream} from twisted layer
"""
leftPart = UInt8()
data.readType(leftPart)
self._lastShortLength.value &= ~0x80
packetSize = (self._lastShortLength.value << 8) + leftPart.value
#next state is fast patn data
self.expect(packetSize - 3, self.readFastPath)
def readFastPath(self, data):
"""
@summary: Fast path data
@param data: {Stream} from twisted layer
"""
self._fastPathListener.recvFastPath(self._secFlag, data)
self.expect(2, self.readHeader)
def readData(self, data):
"""
@summary: Read classic TPKT packet, last state in tpkt automata
@param data: {Stream} with correct size
"""
#next state is pass to
self._presentation.recv(data)
self.expect(2, self.readHeader)
def send(self, message):
"""
@summary: Send encompassed data
@param message: {network.Type} message to send
"""
RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_X224), UInt8(0), UInt16Be(sizeof(message) + 4), message))
def sendFastPath(self, secFlag, fastPathS):
"""
@param fastPathS: {Type | Tuple} type transform to stream and send as fastpath
@param secFlag: {integer} Security flag for fastpath packet
"""
RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_FASTPATH | ((secFlag & 0x3) << 6)), UInt16Be((sizeof(fastPathS) + 3) | 0x8000), fastPathS))
def startTLS(self, sslContext):
"""
@summary: start TLS protocol
@param sslContext: {ssl.ClientContextFactory | ssl.DefaultOpenSSLContextFactory} context use for TLS protocol
"""
self.transport.startTLS(sslContext)
def startNLA(self):
"""
@summary: use to start NLA (NTLM over SSL) protocol
must be called after startTLS function
"""
#send first NTLM packet
self.transport.write(cssp.createBERRequest( [ ntlm.NegotiateMessage() ] ))
def readNTLMChallenge(self, data):
"""
@summary: server NTLM challenge
"""