diff --git a/rdpy/core/layer.py b/rdpy/core/layer.py index bc0cf5f..b57d7d3 100644 --- a/rdpy/core/layer.py +++ b/rdpy/core/layer.py @@ -183,7 +183,6 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender): #len of next packet pass to next state function self._expectedLen = 0 self._factory = None - self._immediateCallback = None def setFactory(self, factory): """ @@ -242,28 +241,6 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender): self._expectedLen = expectedLen #default callback is recv from LayerAutomata self.setNextState(callback) - - def dataReceivedAll(self, data): - """ - @summary: by pass automata received - @warning: ignore rest in buffer - @param data: {str} received from twisted - """ - self._immediateCallback(Stream(data)) - - def expectImmediately(self, callback): - """ - @summary: call immediately when available data is received - @param callback: {func} callback called - """ - self.dataReceived = lambda data:self.__class__.dataReceivedAll(self, data) - self._immediateCallback = callback - - def restartAutomata(self): - """ - @summary: restart automata - """ - self.dataReceived = lambda data:self.__class__.dataReceived(self, data) def send(self, message): """ diff --git a/rdpy/protocol/rdp/lic.py b/rdpy/protocol/rdp/lic.py index 281762f..3acdb74 100644 --- a/rdpy/protocol/rdp/lic.py +++ b/rdpy/protocol/rdp/lic.py @@ -303,9 +303,12 @@ class LicenseManager(object): """ #get server information serverRandom = licenseRequest.serverRandom.value - s = Stream(licenseRequest.serverCertificate.blobData.value) - serverCertificate = gcc.ServerCertificate() - s.readType(serverCertificate) + if self._transport.getGCCServerSettings().SC_SECURITY.serverCertificate._is_readed: + serverCertificate = self._transport.getGCCServerSettings().SC_SECURITY.serverCertificate + else: + s = Stream(licenseRequest.serverCertificate.blobData.value) + serverCertificate = gcc.ServerCertificate() + s.readType(serverCertificate) #generate crypto values clientRandom = rsa.random(256) diff --git a/rdpy/protocol/rdp/nla/cssp.py b/rdpy/protocol/rdp/nla/cssp.py index 229a664..c99c646 100644 --- a/rdpy/protocol/rdp/nla/cssp.py +++ b/rdpy/protocol/rdp/nla/cssp.py @@ -24,7 +24,10 @@ from pyasn1.type import namedtype, univ, tag from pyasn1.codec.der import encoder, decoder -from rdpy.core.type import Stream, String +from rdpy.core.type import Stream +from rdpy.security import x509 +from twisted.internet import protocol +from OpenSSL import crypto class NegoToken(univ.Sequence): componentType = namedtype.NamedTypes( @@ -101,7 +104,7 @@ def encodeDERTRequest(negoTypes = [], pubKeyAuth = None): """ @summary: create TSRequest from list of Type @param negoTypes: {list(Type)} - @return: {String} + @return: {str} """ negoData = NegoData().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)) @@ -121,18 +124,94 @@ def encodeDERTRequest(negoTypes = [], pubKeyAuth = None): if not pubKeyAuth is None: request.setComponentByName("pubKeyAuth", univ.OctetString(pubKeyAuth).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))) - return String(encoder.encode(request)) + return encoder.encode(request) def decodeDERTRequest(s): """ @summary: Decode the stream as - @param s: ([{Stream}], {str} pubKeyAuth) + @param s: {str} """ - return decoder.decode(s.getvalue(), asn1Spec=TSRequest())[0] + return decoder.decode(s, asn1Spec=TSRequest())[0] def getNegoTokens(tRequest): negoData = tRequest.getComponentByName("negoTokens") return [Stream(negoData.getComponentByPosition(i).getComponentByPosition(0).asOctets()) for i in range(len(negoData))] def getPubKeyAuth(tRequest): - return tRequest.getComponentByName("pubKeyAuth").asOctets() \ No newline at end of file + return tRequest.getComponentByName("pubKeyAuth").asOctets() + +class CSSP(protocol.Protocol): + """ + @summary: Handle CSSP connection + Proxy class for authentication + """ + def __init__(self, layer, authenticationProtocol): + """ + @param layer: {type.Layer.RawLayer} + @param authenticationProtocol: {sspi.IAuthenticationProtocol} + """ + self._layer = layer + self._authenticationProtocol = authenticationProtocol + + def setFactory(self, factory): + """ + @summary: Call by RawLayer Factory + @param param: RawLayerClientFactory or RawLayerFactory + """ + self._layer.setFactory(factory) + + def dataReceived(self, data): + """ + @summary: Inherit from twisted.protocol class + main event of received data + @param data: string data receive from twisted + """ + self._layer.dataReceived(data) + + def connectionMade(self): + """ + @summary: install proxy + """ + self._layer.transport = self + self._layer.connectionMade() + + def write(self, data): + """ + @summary: write data on transport layer + @param data: {str} + """ + self.transport.write(data) + + 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: start NLA authentication + """ + #send negotiate message + self.transport.write(encodeDERTRequest( negoTypes = [ self._authenticationProtocol.getNegotiateMessage() ] )) + #next state is receive a challenge + self.dataReceived = self.recvChallenge + + def recvChallenge(self, data): + """ + @summary: second state in cssp automata + @param {str}: all data available on buffer + """ + #get back public key + toto = self.transport.protocol._tlsConnection.get_peer_certificate().get_pubkey() + lolo = crypto.dump_privatekey(crypto.FILETYPE_ASN1, toto) + modulus, exponent = x509.extractRSAKey2(lolo) + import hexdump + print lolo + hexdump.hexdump(lolo) + request = decodeDERTRequest(data) + message, interface = self._authenticationProtocol.getAuthenticateMessage(getNegoTokens(request)[0]) + #send authenticate message with public key encoded + import ntlm + self.transport.write(encodeDERTRequest( negoTypes = [ message ], pubKeyAuth = interface.GSS_WrapEx("".join([chr(i) for i in ntlm.pubKeyHex])))) \ No newline at end of file diff --git a/rdpy/protocol/rdp/nla/ntlm.py b/rdpy/protocol/rdp/nla/ntlm.py index 04be11e..1b01e59 100644 --- a/rdpy/protocol/rdp/nla/ntlm.py +++ b/rdpy/protocol/rdp/nla/ntlm.py @@ -683,9 +683,9 @@ if __name__ == "__main__": ClientChallenge = temp[16:24] EncryptedRandomSessionKey = authenticate.getEncryptedRandomSession() - domain = "dodo" - user = "uouo" - password = "popo" + domain = "siradel" + user = "speyrefitte" + password = "spe+99@12" ResponseKeyNT = NTOWFv2(password, user, domain) ResponseKeyLM = LMOWFv2(password, user, domain) diff --git a/rdpy/protocol/rdp/rdp.py b/rdpy/protocol/rdp/rdp.py index 67c1f36..fa9c495 100644 --- a/rdpy/protocol/rdp/rdp.py +++ b/rdpy/protocol/rdp/rdp.py @@ -29,6 +29,7 @@ import pdu.caps import rdpy.core.log as log import tpkt, x224, sec from t125 import mcs, gcc +from nla import cssp, ntlm class RDPClientController(pdu.layer.PDUClientListener): """ @@ -526,7 +527,8 @@ class ClientFactory(layer.RawLayerClientFactory): """ controller = RDPClientController() self.buildObserver(controller, addr) - return controller.getProtocol() + #Add cssp proxy in case of nla protocol + return cssp.CSSP(controller.getProtocol(), ntlm.NTLMv2("toto", "coco", "lolo")) def buildObserver(self, controller, addr): """ diff --git a/rdpy/protocol/rdp/tpkt.py b/rdpy/protocol/rdp/tpkt.py index f44f216..a37fa85 100644 --- a/rdpy/protocol/rdp/tpkt.py +++ b/rdpy/protocol/rdp/tpkt.py @@ -114,7 +114,6 @@ class TPKT(RawLayer, IFastPathSender): self._fastPathListener = None #last secure flag self._secFlag = 0 - self._ntlm = ntlm.NTLMv2("dodo", "uouo", "popo") def setFastPathListener(self, fastPathListener): """ @@ -224,18 +223,4 @@ class TPKT(RawLayer, IFastPathSender): @summary: use to start NLA (NTLM over SSL) protocol must be called after startTLS function """ - #import hexdump - #hexdump.hexdump(self.transport.protocol._tlsConnection.getpeercert()) - #send NTLM negotiate message packet - RawLayer.send(self, cssp.encodeDERTRequest( negoTypes = [ self._ntlm.getNegotiateMessage() ] )) - self.expectImmediately(self.readNTLMChallenge) - - def readNTLMChallenge(self, data): - """ - @summary: server NTLM challenge - @param data: {Stream} - """ - request = cssp.decodeDERTRequest(data) - message, interface = self._ntlm.getAuthenticateMessage(cssp.getNegoTokens(request)[0]) - RawLayer.send(self, cssp.encodeDERTRequest( negoTypes = [ message ], pubKeyAuth = interface.GSS_WrapEx("".join([chr(i) for i in ntlm.pubKeyHex])))) - self.restartAutomata() \ No newline at end of file + self.transport.startNLA() \ No newline at end of file diff --git a/rdpy/security/x509.py b/rdpy/security/x509.py index 881bc67..7e38c92 100644 --- a/rdpy/security/x509.py +++ b/rdpy/security/x509.py @@ -150,8 +150,14 @@ def extractRSAKey(certificate): binaryTuple = certificate.getComponentByName('tbsCertificate').getComponentByName('subjectPublicKeyInfo').getComponentByName('subjectPublicKey') l = int("".join([str(i) for i in binaryTuple]), 2) - rsaKey = decoder.decode(hex(l)[2:-1].decode('hex'), asn1Spec=RSAPublicKey())[0] + return extractRSAKeyFromASN1(hex(l)[2:-1].decode('hex')) + +def extractRSAKeyFromASN1(subjectPublicKey): + rsaKey = decoder.decode(subjectPublicKey, asn1Spec=RSAPublicKey())[0] return rsaKey.getComponentByName('modulus')._value , rsaKey.getComponentByName('publicExponent')._value - - + +def extractRSAKey2(key): + binaryTuple = decoder.decode(key, asn1Spec=univ.BitString())[0] + l = int("".join([str(i) for i in binaryTuple]), 2) + return extractRSAKeyFromASN1(hex(l)[2:-1].decode('hex')) \ No newline at end of file