diff --git a/bin/rdpy-rdpclient.py b/bin/rdpy-rdpclient.py index f0a6127..cfbc907 100755 --- a/bin/rdpy-rdpclient.py +++ b/bin/rdpy-rdpclient.py @@ -21,7 +21,7 @@ example of use rdpy as rdp client """ -import sys, os, getopt +import sys, os, getopt, socket from PyQt4 import QtGui, QtCore from rdpy.ui.qt4 import RDPClientQt @@ -77,6 +77,7 @@ class RDPClientQtFactory(rdp.ClientFactory): controller.setPassword(self._passwod) controller.setDomain(self._domain) controller.setKeyboardLayout(self._keyboardLayout) + controller.setHostname(socket.gethostname()) if self._optimized: controller.setPerformanceSession() diff --git a/bin/rdpy-rdpproxy.py b/bin/rdpy-rdpproxy.py index 97950e1..4bde05f 100755 --- a/bin/rdpy-rdpproxy.py +++ b/bin/rdpy-rdpproxy.py @@ -37,7 +37,7 @@ from rdpy.ui import view from twisted.internet import reactor from PyQt4 import QtCore, QtGui -log._LOG_LEVEL = log.Level.INFO +#log._LOG_LEVEL = log.Level.INFO class ProxyServer(rdp.RDPServerObserver): """ diff --git a/rdpy/protocol/rdp/pdu/layer.py b/rdpy/protocol/rdp/pdu/layer.py index c340109..7aa0db1 100644 --- a/rdpy/protocol/rdp/pdu/layer.py +++ b/rdpy/protocol/rdp/pdu/layer.py @@ -136,8 +136,7 @@ class Client(PDULayer, tpkt.IFastPathListener): self._listener = listener #enable or not fast path self._fastPathSender = None - #todo generate hostname - self._licenceManager = lic.LicenseManager(self, self._info.userName.value, "wav-glw-009") + self._licenceManager = lic.LicenseManager(self) def connect(self): """ @@ -592,8 +591,7 @@ class Server(PDULayer, tpkt.IFastPathListener): def sendDemandActivePDU(self): """ - Send server capabilities - server automata PDU + @summary: Send server capabilities server automata PDU """ #init general capability generalCapability = self._serverCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability diff --git a/rdpy/protocol/rdp/pdu/lic.py b/rdpy/protocol/rdp/pdu/lic.py index 2a81bef..557c1d9 100644 --- a/rdpy/protocol/rdp/pdu/lic.py +++ b/rdpy/protocol/rdp/pdu/lic.py @@ -90,6 +90,7 @@ class Preambule(object): """ PREAMBLE_VERSION_2_0 = 0x2 PREAMBLE_VERSION_3_0 = 0x3 + EXTENDED_ERROR_MSG_SUPPORTED = 0x80 class LicenseBinaryBlob(CompositeType): """ @@ -208,13 +209,13 @@ class ClientPLatformChallengeResponse(CompositeType): def __init__(self): CompositeType.__init__(self) - self.encryptedPlatformChallengeResponse = LicenseBinaryBlob(BinaryBlobType.BB_ENCRYPTED_DATA_BLOB) - self.encryptedHWID = LicenseBinaryBlob(BinaryBlobType.BB_ENCRYPTED_DATA_BLOB) + self.encryptedPlatformChallengeResponse = LicenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB) + self.encryptedHWID = LicenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB) self.MACData = String(readLen = UInt8(16)) class LicPacket(CompositeType): """ - A license packet + @summary: A license packet """ def __init__(self, message = None): CompositeType.__init__(self) @@ -225,7 +226,7 @@ class LicPacket(CompositeType): def LicensingMessageFactory(): """ - factory for message nego + @summary: factory for message nego Use in read mode """ for c in [LicensingErrorMessage, ServerLicenseRequest, ClientNewLicenseRequest, ServerPlatformChallenge, ClientPLatformChallengeResponse]: @@ -249,32 +250,33 @@ def createValidClientLicensingErrorMessage(): message = LicensingErrorMessage() message.dwErrorCode.value = ErrorCode.STATUS_VALID_CLIENT message.dwStateTransition.value = StateTransition.ST_NO_TRANSITION - return LicPacket(message = message) + return LicPacket(message) class LicenseManager(object): """ @summary: handle license automata @see: http://msdn.microsoft.com/en-us/library/cc241890.aspx """ - def __init__(self, transport, username, hostname): + def __init__(self, transport): """ @param transport: layer use to send packet """ + self._preMasterSecret = "\x00" * 64 self._clientRandom = "\x00" * 32 self._serverRandom = None self._serverEncryptedChallenge = None self._transport = transport - self._username = username - self._hostname = hostname + self._username = "" + self._hostname = "" def generateKeys(self): """ @summary: generate key for license session """ - self._masterSecret = sec.generateMicrosoftKey("\x00" * 64, self._clientRandom, self._serverRandom) - self._sessionKeyBlob = sec.generateMicrosoftKey(self._masterSecret, self._serverRandom, self._clientRandom) - self._macSalt = self._sessionKeyBlob[:16] - self._licenseKey = sec.md5_16_32_32(self._sessionKeyBlob[16:], self._clientRandom, self._serverRandom) + masterSecret = sec.generateMicrosoftKey(self._preMasterSecret, self._clientRandom, self._serverRandom) + sessionKeyBlob = sec.generateMicrosoftKey(masterSecret, self._serverRandom, self._clientRandom) + self._macSalt = sessionKeyBlob[:16] + self._licenseKey = sec.finalHash(sessionKeyBlob[16:32], self._clientRandom, self._serverRandom) def recv(self, s): """ @@ -296,7 +298,11 @@ class LicenseManager(object): elif licPacket.bMsgtype.value == MessageType.PLATFORM_CHALLENGE: self._serverEncryptedChallenge = licPacket.licensingMessage.encryptedPlatformChallenge.blobData.value self.sendClientChallengeResponse() - + + #yes get a new license + elif licPacket.bMsgtype.value == MessageType.NEW_LICENSE: + return True + else: raise InvalidExpectedDataException("Not a valid license packet") @@ -309,25 +315,27 @@ class LicenseManager(object): """ message = ClientNewLicenseRequest() message.clientRandom.value = self._clientRandom - message.encryptedPreMasterSecret.blobData = String("\x00" * (64 + 8)) + message.encryptedPreMasterSecret.blobData = String(self._preMasterSecret + "\x00" * 8) message.ClientMachineName.blobData = String(self._hostname + "\x00") message.ClientUserName.blobData = String(self._username + "\x00") self._transport.sendLicensePacket(LicPacket(message)) def sendClientChallengeResponse(self): - #it should be TEST in unicode format + """ + @summary: generate valid challenge response + """ + #decrypt server challenge + #it should be TEST word in unicode format serverChallenge = rc4.crypt(self._licenseKey, self._serverEncryptedChallenge) #generate hwid s = Stream() - s.writeType((UInt32Le(2), String(self._username + self._hostname + "\x00" * 20))) + s.writeType((UInt32Le(2), String(self._hostname + "\x00" * 16))) hwid = s.getvalue()[:20] - signature = sec.macData(self._macSalt, serverChallenge + hwid) - message = ClientPLatformChallengeResponse() message.encryptedPlatformChallengeResponse.blobData.value = self._serverEncryptedChallenge message.encryptedHWID.blobData.value = rc4.crypt(self._licenseKey, hwid) - message.MACData.value = signature + message.MACData.value = sec.macData(self._macSalt, serverChallenge + hwid) self._transport.sendLicensePacket(LicPacket(message)) \ No newline at end of file diff --git a/rdpy/protocol/rdp/rdp.py b/rdpy/protocol/rdp/rdp.py index 1b72263..f8c09d0 100644 --- a/rdpy/protocol/rdp/rdp.py +++ b/rdpy/protocol/rdp/rdp.py @@ -89,6 +89,7 @@ class RDPClientController(pdu.layer.PDUClientListener): """ #username in PDU info packet self._pduLayer._info.userName.value = username + self._pduLayer._licenceManager._username = username def setPassword(self, password): """ @@ -120,6 +121,13 @@ class RDPClientController(pdu.layer.PDUClientListener): self._mcsLayer._clientSettings.getBlock(gcc.MessageType.CS_CORE).kbdLayout.value = gcc.KeyboardLayout.FRENCH elif layout == "us": self._mcsLayer._clientSettings.getBlock(gcc.MessageType.CS_CORE).kbdLayout.value = gcc.KeyboardLayout.US + + def setHostname(self, hostname): + """ + @summary: set hostname of machine + """ + self._mcsLayer._clientSettings.getBlock(gcc.MessageType.CS_CORE).clientName.value = hostname[:15] + "\x00" * (15 - len(hostname)) + self._pduLayer._licenceManager._hostname = hostname def addClientObserver(self, observer): """ diff --git a/rdpy/protocol/rdp/sec.py b/rdpy/protocol/rdp/sec.py index a601901..d5b94e5 100644 --- a/rdpy/protocol/rdp/sec.py +++ b/rdpy/protocol/rdp/sec.py @@ -48,18 +48,18 @@ def saltedHash(inputData, salt, salt1, salt2): return md5Digest.digest() -def md5_16_32_32(in0, in1, in2): +def finalHash(key, random1, random2): """ @summary: MD5(in0[:16] + in1[:32] + in2[:32]) - @param in0: in 16 - @param in1: in 32 - @param in2: in 32 + @param key: in 16 + @param random1: in 32 + @param random2: in 32 @return MD5(in0[:16] + in1[:32] + in2[:32]) """ md5Digest = md5.new() - md5Digest.update(in0[:16]) - md5Digest.update(in1[:32]) - md5Digest.update(in2[:32]) + md5Digest.update(key) + md5Digest.update(random1) + md5Digest.update(random2) return md5Digest.digest() def generateMicrosoftKey(secret, random1, random2): @@ -72,6 +72,9 @@ def generateMicrosoftKey(secret, random1, random2): return saltedHash("A", secret, random1, random2) + saltedHash("BB", secret, random1, random2) + saltedHash("CCC", secret, random1, random2) def macData(macSaltKey, data): + """ + @see: http://msdn.microsoft.com/en-us/library/cc241995.aspx + """ sha1Digest = sha.new() md5Digest = md5.new()