From b0949e6f3c16afdb285cee58c8e51a8d0c15201f Mon Sep 17 00:00:00 2001 From: speyrefitte Date: Tue, 22 Oct 2013 18:28:32 +0200 Subject: [PATCH] implement gcc connect sequence --- rdpy/main.py | 4 +- rdpy/protocol/rdp/ber.py | 18 ++--- rdpy/protocol/rdp/gcc.py | 156 ++++++++++++++++++++++++++++++++++---- rdpy/protocol/rdp/mcs.py | 58 ++++++++++++++ rdpy/protocol/rdp/per.py | 6 +- rdpy/protocol/rdp/tpdu.py | 24 ++++-- rdpy/protocol/rfb/rfb.py | 3 +- 7 files changed, 235 insertions(+), 34 deletions(-) diff --git a/rdpy/main.py b/rdpy/main.py index 72270ae..b3809d8 100644 --- a/rdpy/main.py +++ b/rdpy/main.py @@ -7,7 +7,7 @@ import sys from PyQt4 import QtGui from rdpy.display.qt import adaptor, widget from rdpy.protocol.rfb import rfb, factory -from rdpy.protocol.rdp import tpkt, tpdu +from rdpy.protocol.rdp import tpkt, tpdu, mcs from twisted.internet import ssl from OpenSSL import SSL @@ -32,6 +32,6 @@ if __name__ == '__main__': from twisted.internet import reactor #reactor.connectTCP("127.0.0.1", 5901, factory.RfbFactory(protocol)) #reactor.connectTCP("192.168.135.160", 3389, factory.RfbFactory(tpkt.TPKT(tpdu.TPDU()))) - reactor.connectTCP("192.168.122.184", 3389, factory.RfbFactory(tpkt.TPKT(tpdu.TPDU()))) + reactor.connectTCP("192.168.56.1", 3389, factory.RfbFactory(tpkt.TPKT(tpdu.TPDU(mcs.MCS())))) reactor.run() sys.exit(app.exec_()) \ No newline at end of file diff --git a/rdpy/protocol/rdp/ber.py b/rdpy/protocol/rdp/ber.py index 3257d26..ef91baf 100644 --- a/rdpy/protocol/rdp/ber.py +++ b/rdpy/protocol/rdp/ber.py @@ -121,7 +121,7 @@ def readApplicationTag(s, tag): def writeApplicationTag(tag, size): ''' return struct that represent ber application tag - @param tag: tag class attribute + @param tag: UINt8 @param size: size to rest of packet ''' if tag > UInt8(30): @@ -187,15 +187,15 @@ def readInteger(s): def writeInteger(value): ''' write integer value - @param param: UInt32Be + @param param: int or python long @return ber interger structure ''' - if value < UInt32Be(0xff): - return (writeUniversalTag(Tag.BER_TAG_INTEGER, False), writeLength(1), UInt8(value.value)) - elif value < UInt32Be(0xff80): - return (writeUniversalTag(Tag.BER_TAG_INTEGER, False), writeLength(2), UInt16Be(value.value)) + if value < 0xff: + return (writeUniversalTag(Tag.BER_TAG_INTEGER, False), writeLength(1), UInt8(value)) + elif value < 0xff80: + return (writeUniversalTag(Tag.BER_TAG_INTEGER, False), writeLength(2), UInt16Be(value)) else: - return (writeUniversalTag(Tag.BER_TAG_INTEGER, False), writeLength(4), UInt32Be(value.value)) + return (writeUniversalTag(Tag.BER_TAG_INTEGER, False), writeLength(4), UInt32Be(value)) def readOctetString(s): ''' @@ -211,10 +211,10 @@ def readOctetString(s): def writeOctetstring(value): ''' write string in ber representation - @param value: String + @param value: string @return: string ber structure ''' - return (writeUniversalTag(Tag.BER_TAG_OCTET_STRING, False), writeLength(len(value.value)), value) + return (writeUniversalTag(Tag.BER_TAG_OCTET_STRING, False), writeLength(len(value)), String(value)) def readEnumerated(s): ''' diff --git a/rdpy/protocol/rdp/gcc.py b/rdpy/protocol/rdp/gcc.py index 875b5ca..720dd59 100644 --- a/rdpy/protocol/rdp/gcc.py +++ b/rdpy/protocol/rdp/gcc.py @@ -1,9 +1,11 @@ ''' @author sylvain @summary gcc language +@contact: http://msdn.microsoft.com/en-us/library/cc240510.aspx ''' from rdpy.utils.const import ConstAttributes -from rdpy.protocol.network.type import UInt32Le, UInt16Le, String, CompositeType +from rdpy.protocol.network.type import UInt8, UInt32Le, UInt16Le, String, Stream, CompositeType, sizeof +import per @ConstAttributes @@ -32,15 +34,60 @@ class ColorDepth(object): RNS_UD_COLOR_16BPP_555 = UInt16Le(0xCA02) RNS_UD_COLOR_16BPP_565 = UInt16Le(0xCA03) RNS_UD_COLOR_24BPP = UInt16Le(0xCA04) + +@ConstAttributes +class HighColor(object): + ''' + high color of client + ''' + HIGH_COLOR_4BPP = UInt16Le(0x0004) + HIGH_COLOR_8BPP = UInt16Le(0x0008) + HIGH_COLOR_15BPP = UInt16Le(0x000f) + HIGH_COLOR_16BPP = UInt16Le(0x0010) + HIGH_COLOR_24BPP = UInt16Le(0x0018) -RNS_UD_24BPP_SUPPORT = 0x0001 -RNS_UD_16BPP_SUPPORT = 0x0002 -RNS_UD_15BPP_SUPPORT = 0x0004 -RNS_UD_32BPP_SUPPORT = 0x0008 +@ConstAttributes +class Support(object): + ''' + support depth flag + ''' + RNS_UD_24BPP_SUPPORT = UInt16Le(0x0001) + RNS_UD_16BPP_SUPPORT = UInt16Le(0x0002) + RNS_UD_15BPP_SUPPORT = UInt16Le(0x0004) + RNS_UD_32BPP_SUPPORT = UInt16Le(0x0008) -RNS_UD_SAS_DEL = 0xAA03 +@ConstAttributes +class CapabilityFlags(object): + ''' + @contact: http://msdn.microsoft.com/en-us/library/cc240510.aspx + for more details on each flags click above + ''' + RNS_UD_CS_SUPPORT_ERRINFO_PDU = UInt16Le(0x0001) + RNS_UD_CS_WANT_32BPP_SESSION = UInt16Le(0x0002) + RNS_UD_CS_SUPPORT_STATUSINFO_PDU = UInt16Le(0x0004) + RNS_UD_CS_STRONG_ASYMMETRIC_KEYS = UInt16Le(0x0008) + RN_UD_CS_UNUSED = UInt16Le(0x0010) + RNS_UD_CS_VALID_CONNECTION_TYPE = UInt16Le(0x0020) + RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU = UInt16Le(0x0040) + RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT = UInt16Le(0x0080) + RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL = UInt16Le(0x0100) + RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE = UInt16Le(0x0200) + RNS_UD_CS_SUPPORT_HEARTBEAT_PDU = UInt16Le(0x0400) -RNS_UD_CS_SUPPORT_ERRINFO_PDU = 0x0001 +@ConstAttributes +class ConnectionType(object): + ''' + this information is correct if + RNS_UD_CS_VALID_CONNECTION_TYPE flag is set on capabilityFlag + @contact: http://msdn.microsoft.com/en-us/library/cc240510.aspx + ''' + CONNECTION_TYPE_MODEM = UInt8(0x01) + CONNECTION_TYPE_BROADBAND_LOW = UInt8(0x02) + CONNECTION_TYPE_SATELLITE = UInt8(0x03) + CONNECTION_TYPE_BROADBAND_HIGH = UInt8(0x04) + CONNECTION_TYPE_WAN = UInt8(0x05) + CONNECTION_TYPE_LAN = UInt8(0x06) + CONNECTION_TYPE_AUTODETECT = UInt8(0x07) @ConstAttributes class Version(object): @@ -63,17 +110,22 @@ class ClientCoreSettings(CompositeType): self.padding1 = (UInt16Le(), UInt16Le()) self.kbdLayout = UInt32Le(0x409) self.clientBuild = UInt32Le(2100) - self.clientName = "rdpy" + self.clientName = String("\x00"*64) self.padding2 = UInt16Le() self.keyboardType = UInt32Le(4) self.keyboardSubType = UInt32Le(0) self.keyboardFnKeys = UInt32Le(12) self.padding3 = String("\x00"*64) self.postBeta2ColorDepth = ColorDepth.RNS_UD_COLOR_24BPP - self.padding4 = (UInt16Le(), UInt32Le()) - self.highColorDepth = UInt16Le(24) - self.padding5 = (UInt16Le(), UInt16Le()) - self.padding3 = String("\x00"*64) + self.clientProductId = UInt16Le() + self.serialNumber = UInt32Le() + self.highColorDepth = HighColor.HIGH_COLOR_24BPP + self.supportedColorDepths = Support.RNS_UD_32BPP_SUPPORT + self.earlyCapabilityFlags = UInt16Le() + self.clientDigProductId = String("\x00"*64) + self.connectionType = UInt8() + self.pad1octet = UInt8() + self.serverSelectedProtocol = UInt32Le() class ServerCoreSettings(CompositeType): ''' @@ -81,4 +133,82 @@ class ServerCoreSettings(CompositeType): ''' def __init__(self): CompositeType.__init__(self) - self.rdpVersion = Version.RDP_VERSION_5_PLUS \ No newline at end of file + self.rdpVersion = Version.RDP_VERSION_5_PLUS + +class Channel(object): + ''' + channels structure share between + client and server + ''' + def __init__(self): + #name of channel + self.name = "" + #unknown + self.options = 0 + #id of channel + self.channelId = 0 + #True if channel is connect + self.connect = False + +class ClientSettings(object): + ''' + class which group all client settings supported by RDPY + ''' + def __init__(self): + self.core = ClientCoreSettings() + #list of Channel read network gcc packet + self.networkChannels = [] + +t124_02_98_oid = ( 0, 0, 20, 124, 0, 1 ) +h221_cs_key = "Duca"; +h221_sc_key = "McDn"; + +def writeConferenceCreateRequest(settings): + ''' + write conference create request structure + @param settings: ClientSettings + @return: struct that represent + ''' + userData = writeClientDataBlocks(settings) + userDataStream = Stream() + userDataStream.writeType(userData) + + return (per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid), + per.writeLength(len(userDataStream.getvalue()) + 14), per.writeChoice(0), + per.writeSelection(0x08), per.writeNumericString("1", 1), per.writePadding(1), + per.writeNumberOfSet(1), per.writeChoice(0xc0), + per.writeOctetStream(h221_cs_key, 4), per.writeOctetStream(userDataStream.getvalue())) + + +def writeClientDataBlocks(settings): + ''' + write all blocks for client + and return gcc valid structure + @param settings: ClientSettings + ''' + return (writeClientCoreData(settings.core), writeClientNetworkData(settings.networkChannels)) + +def writeClientCoreData(core): + ''' + write client settings in GCC language + @param settings: ClientSettings structure + @return: structure that represent client data blocks + ''' + return (ClientToServerMessage.CS_CORE, UInt16Le(sizeof(core) + 4), core) + +def writeClientNetworkData(channels): + ''' + write network packet whith channels infos + @param channels: list of Channel + @return: gcc network packet + ''' + if len(channels) == 0: + return () + result = [] + result.append(UInt32Le(len(channels))) + for channel in channels: + result.append((String(channel.name[0:8]), UInt32Le(channel.options))) + + resultPacket = tuple(result) + return (ClientToServerMessage.CS_NET, UInt16Le(sizeof(resultPacket) + 4), resultPacket) + \ No newline at end of file diff --git a/rdpy/protocol/rdp/mcs.py b/rdpy/protocol/rdp/mcs.py index 9185bbd..9d74859 100644 --- a/rdpy/protocol/rdp/mcs.py +++ b/rdpy/protocol/rdp/mcs.py @@ -2,7 +2,32 @@ @author: sylvain ''' +from rdpy.utils.const import ConstAttributes from rdpy.protocol.network.layer import LayerAutomata +from rdpy.protocol.network.type import sizeof, Stream, UInt8 +from rdpy.protocol.rdp.ber import writeLength + +import ber, gcc + +@ConstAttributes +class Message(object): + ''' + message type + ''' + MCS_TYPE_CONNECT_INITIAL = UInt8(0x65) + MCS_TYPE_CONNECT_RESPONSE = UInt8(0x66) + MCS_EDRQ = UInt8(1) + MCS_DPUM = UInt8(8) + MCS_AURQ = UInt8(10) + MCS_AUCF = UInt8(11) + MCS_CJRQ = UInt8(14) + MCS_CJCF = UInt8(15) + MCS_SDRQ = UInt8(25) + MCS_SDIN = UInt8(26) + +class Channel: + MCS_GLOBAL_CHANNEL = 1003 + MCS_USERCHANNEL_BASE = 1001 class MCS(LayerAutomata): ''' @@ -14,13 +39,46 @@ class MCS(LayerAutomata): def __init__(self, presentation = None): ''' ctor call base class ctor + @param presentation: presentation layer ''' LayerAutomata.__init__(self, presentation) + self._clientSettings = gcc.ClientSettings() def connect(self): ''' connection send for client mode a write connect initial packet ''' + self._clientSettings.core.serverSelectedProtocol = self._transport._protocol + self.sendConnectInitial() + + def sendConnectInitial(self): + ''' + send connect initial packet + ''' + ccReq = gcc.writeConferenceCreateRequest(self._clientSettings) + ccReqStream = Stream() + ccReqStream.writeType(ccReq) + + tmp = (ber.writeOctetstring("\x01"), ber.writeOctetstring("\x01"), ber.writeBoolean(True), + self.writeDomainParams(34, 2, 0, 0xffff), + self.writeDomainParams(0xffff, 0xfc17, 0xffff, 0xffff), + ber.writeOctetstring(ccReqStream.getvalue())) + self._transport.send((ber.writeApplicationTag(Message.MCS_TYPE_CONNECT_INITIAL, sizeof(tmp)), tmp)) + + def writeDomainParams(self, maxChannels, maxUsers, maxTokens, maxPduSize): + ''' + write a special domain param structure + use in connection sequence + @param maxChannels: number of mcs channel use + @param maxUsers: number of mcs user used (1) + @param maxTokens: unknown + @param maxPduSize: unknown + @return: domain param structure + ''' + domainParam = (ber.writeInteger(maxChannels), ber.writeInteger(maxUsers), ber.writeInteger(maxTokens), + ber.writeInteger(1), ber.writeInteger(0), ber.writeInteger(1), + ber.writeInteger(maxPduSize), ber.writeInteger(2)) + return (ber.writeUniversalTag(ber.Tag.BER_TAG_SEQUENCE, True), writeLength(sizeof(domainParam)), domainParam) \ No newline at end of file diff --git a/rdpy/protocol/rdp/per.py b/rdpy/protocol/rdp/per.py index f093c97..77aee58 100644 --- a/rdpy/protocol/rdp/per.py +++ b/rdpy/protocol/rdp/per.py @@ -209,9 +209,9 @@ def writeNumericString(nStr, minValue): result = [] for i in range(0, length, 2): - c1 = ord(str[i]) + c1 = ord(nStr[i]) if i + 1 < length: - c2 = ord(str[i + 1]) + c2 = ord(nStr[i + 1]) else: c2 = 0x30 c1 = (c1 - 0x30) % 10 @@ -258,7 +258,7 @@ def readOctetStream(s, octetStream, minValue): return True -def writeOctetStream(oStr, minValue): +def writeOctetStream(oStr, minValue = 0): ''' write string as octet stream with per header @param oStr: octet stream to convert diff --git a/rdpy/protocol/rdp/tpdu.py b/rdpy/protocol/rdp/tpdu.py index ee3f3e2..d744cf6 100644 --- a/rdpy/protocol/rdp/tpdu.py +++ b/rdpy/protocol/rdp/tpdu.py @@ -60,12 +60,13 @@ class Negotiation(CompositeType): class TPDU(LayerAutomata): ''' - classdocs + TPDU layer management + there is an connection automata ''' - def __init__(self, presentation = None): ''' Constructor + @param presentation: MCS layer ''' LayerAutomata.__init__(self, presentation) @@ -83,6 +84,9 @@ class TPDU(LayerAutomata): def recvConnectionConfirm(self, data): ''' recv connection confirm message + next state is recvData + call connect on presentation layer if all is good + @param data: Stream that contain connection confirm ''' header = TPDUConnectHeader() data.readType(header) @@ -91,13 +95,23 @@ class TPDU(LayerAutomata): #check presence of negotiation response if data.dataLen() == 8: self.readNeg(data) + else: + raise NegotiationFailure("server doesn't support SSL negotiation on RDP") + + self.setNextState(self.recvData) + #connection is done send to presentation + LayerAutomata.connect(self) + + def recvData(self, data): + print "TPDU data" def sendConnectionRequest(self): ''' write connection request message + next state is recvConnectionConfirm ''' - neqReq = Negotiation(self._protocol) - self._transport.send((TPDUConnectHeader(MessageType.X224_TPDU_CONNECTION_REQUEST, sizeof(neqReq)), NegociationType.TYPE_RDP_NEG_REQ, neqReq)) + neqReq = (NegociationType.TYPE_RDP_NEG_REQ, Negotiation(self._protocol)) + self._transport.send((TPDUConnectHeader(MessageType.X224_TPDU_CONNECTION_REQUEST, sizeof(neqReq)), neqReq)) self.setNextState(self.recvConnectionConfirm) def send(self, message): @@ -109,7 +123,7 @@ class TPDU(LayerAutomata): def readNeg(self, data): ''' - read neagotiation response + read negotiation response ''' code = UInt8() data.readType(code) diff --git a/rdpy/protocol/rfb/rfb.py b/rdpy/protocol/rfb/rfb.py index fe6b979..4a3f7b7 100644 --- a/rdpy/protocol/rfb/rfb.py +++ b/rdpy/protocol/rfb/rfb.py @@ -4,8 +4,7 @@ from rdpy.protocol.network.type import String, UInt8, UInt16Be, UInt32Be from rdpy.protocol.network.layer import RawLayer -from message import ServerInit, PixelFormat, FrameBufferUpdateRequest, Rectangle, KeyEvent, PointerEvent, ClientCutText -from message import ProtocolVersion, SecurityType, Encoding, ClientToServerMessages +from message import * class Rfb(RawLayer): '''