cssp protocol proxy
This commit is contained in:
@@ -183,7 +183,6 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
|
|||||||
#len of next packet pass to next state function
|
#len of next packet pass to next state function
|
||||||
self._expectedLen = 0
|
self._expectedLen = 0
|
||||||
self._factory = None
|
self._factory = None
|
||||||
self._immediateCallback = None
|
|
||||||
|
|
||||||
def setFactory(self, factory):
|
def setFactory(self, factory):
|
||||||
"""
|
"""
|
||||||
@@ -242,28 +241,6 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
|
|||||||
self._expectedLen = expectedLen
|
self._expectedLen = expectedLen
|
||||||
#default callback is recv from LayerAutomata
|
#default callback is recv from LayerAutomata
|
||||||
self.setNextState(callback)
|
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):
|
def send(self, message):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -303,9 +303,12 @@ class LicenseManager(object):
|
|||||||
"""
|
"""
|
||||||
#get server information
|
#get server information
|
||||||
serverRandom = licenseRequest.serverRandom.value
|
serverRandom = licenseRequest.serverRandom.value
|
||||||
s = Stream(licenseRequest.serverCertificate.blobData.value)
|
if self._transport.getGCCServerSettings().SC_SECURITY.serverCertificate._is_readed:
|
||||||
serverCertificate = gcc.ServerCertificate()
|
serverCertificate = self._transport.getGCCServerSettings().SC_SECURITY.serverCertificate
|
||||||
s.readType(serverCertificate)
|
else:
|
||||||
|
s = Stream(licenseRequest.serverCertificate.blobData.value)
|
||||||
|
serverCertificate = gcc.ServerCertificate()
|
||||||
|
s.readType(serverCertificate)
|
||||||
|
|
||||||
#generate crypto values
|
#generate crypto values
|
||||||
clientRandom = rsa.random(256)
|
clientRandom = rsa.random(256)
|
||||||
|
|||||||
@@ -24,7 +24,10 @@
|
|||||||
|
|
||||||
from pyasn1.type import namedtype, univ, tag
|
from pyasn1.type import namedtype, univ, tag
|
||||||
from pyasn1.codec.der import encoder, decoder
|
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):
|
class NegoToken(univ.Sequence):
|
||||||
componentType = namedtype.NamedTypes(
|
componentType = namedtype.NamedTypes(
|
||||||
@@ -101,7 +104,7 @@ def encodeDERTRequest(negoTypes = [], pubKeyAuth = None):
|
|||||||
"""
|
"""
|
||||||
@summary: create TSRequest from list of Type
|
@summary: create TSRequest from list of Type
|
||||||
@param negoTypes: {list(Type)}
|
@param negoTypes: {list(Type)}
|
||||||
@return: {String}
|
@return: {str}
|
||||||
"""
|
"""
|
||||||
negoData = NegoData().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))
|
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:
|
if not pubKeyAuth is None:
|
||||||
request.setComponentByName("pubKeyAuth", univ.OctetString(pubKeyAuth).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3)))
|
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):
|
def decodeDERTRequest(s):
|
||||||
"""
|
"""
|
||||||
@summary: Decode the stream as
|
@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):
|
def getNegoTokens(tRequest):
|
||||||
negoData = tRequest.getComponentByName("negoTokens")
|
negoData = tRequest.getComponentByName("negoTokens")
|
||||||
return [Stream(negoData.getComponentByPosition(i).getComponentByPosition(0).asOctets()) for i in range(len(negoData))]
|
return [Stream(negoData.getComponentByPosition(i).getComponentByPosition(0).asOctets()) for i in range(len(negoData))]
|
||||||
|
|
||||||
def getPubKeyAuth(tRequest):
|
def getPubKeyAuth(tRequest):
|
||||||
return tRequest.getComponentByName("pubKeyAuth").asOctets()
|
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]))))
|
||||||
@@ -683,9 +683,9 @@ if __name__ == "__main__":
|
|||||||
ClientChallenge = temp[16:24]
|
ClientChallenge = temp[16:24]
|
||||||
EncryptedRandomSessionKey = authenticate.getEncryptedRandomSession()
|
EncryptedRandomSessionKey = authenticate.getEncryptedRandomSession()
|
||||||
|
|
||||||
domain = "dodo"
|
domain = "siradel"
|
||||||
user = "uouo"
|
user = "speyrefitte"
|
||||||
password = "popo"
|
password = "spe+99@12"
|
||||||
ResponseKeyNT = NTOWFv2(password, user, domain)
|
ResponseKeyNT = NTOWFv2(password, user, domain)
|
||||||
ResponseKeyLM = LMOWFv2(password, user, domain)
|
ResponseKeyLM = LMOWFv2(password, user, domain)
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import pdu.caps
|
|||||||
import rdpy.core.log as log
|
import rdpy.core.log as log
|
||||||
import tpkt, x224, sec
|
import tpkt, x224, sec
|
||||||
from t125 import mcs, gcc
|
from t125 import mcs, gcc
|
||||||
|
from nla import cssp, ntlm
|
||||||
|
|
||||||
class RDPClientController(pdu.layer.PDUClientListener):
|
class RDPClientController(pdu.layer.PDUClientListener):
|
||||||
"""
|
"""
|
||||||
@@ -526,7 +527,8 @@ class ClientFactory(layer.RawLayerClientFactory):
|
|||||||
"""
|
"""
|
||||||
controller = RDPClientController()
|
controller = RDPClientController()
|
||||||
self.buildObserver(controller, addr)
|
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):
|
def buildObserver(self, controller, addr):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -114,7 +114,6 @@ class TPKT(RawLayer, IFastPathSender):
|
|||||||
self._fastPathListener = None
|
self._fastPathListener = None
|
||||||
#last secure flag
|
#last secure flag
|
||||||
self._secFlag = 0
|
self._secFlag = 0
|
||||||
self._ntlm = ntlm.NTLMv2("dodo", "uouo", "popo")
|
|
||||||
|
|
||||||
def setFastPathListener(self, fastPathListener):
|
def setFastPathListener(self, fastPathListener):
|
||||||
"""
|
"""
|
||||||
@@ -224,18 +223,4 @@ class TPKT(RawLayer, IFastPathSender):
|
|||||||
@summary: use to start NLA (NTLM over SSL) protocol
|
@summary: use to start NLA (NTLM over SSL) protocol
|
||||||
must be called after startTLS function
|
must be called after startTLS function
|
||||||
"""
|
"""
|
||||||
#import hexdump
|
self.transport.startNLA()
|
||||||
#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()
|
|
||||||
@@ -150,8 +150,14 @@ def extractRSAKey(certificate):
|
|||||||
|
|
||||||
binaryTuple = certificate.getComponentByName('tbsCertificate').getComponentByName('subjectPublicKeyInfo').getComponentByName('subjectPublicKey')
|
binaryTuple = certificate.getComponentByName('tbsCertificate').getComponentByName('subjectPublicKeyInfo').getComponentByName('subjectPublicKey')
|
||||||
l = int("".join([str(i) for i in binaryTuple]), 2)
|
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
|
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'))
|
||||||
|
|
||||||
Reference in New Issue
Block a user