NLA Security Layer is AVAILABLE

This commit is contained in:
speyrefitte
2015-03-06 18:19:42 +01:00
parent b57b3d7398
commit 0abf18d130
10 changed files with 274 additions and 264 deletions

View File

@@ -115,7 +115,7 @@ class RDPClientQtFactory(rdp.ClientFactory):
self._nego = security == "nego" self._nego = security == "nego"
self._recodedPath = recodedPath self._recodedPath = recodedPath
if self._nego: if self._nego:
self._security = "nla" self._security = rdp.SecurityLevel.RDP_LEVEL_NLA
else: else:
self._security = security self._security = security
self._w = None self._w = None
@@ -163,7 +163,7 @@ class RDPClientQtFactory(rdp.ClientFactory):
#stop nego #stop nego
log.info("due to security nego error back to standard RDP security layer") log.info("due to security nego error back to standard RDP security layer")
self._nego = False self._nego = False
self._security = "rdp" self._security = rdp.SecurityLevel.RDP_LEVEL_RDP
self._client._widget.hide() self._client._widget.hide()
connector.connect() connector.connect()
return return

View File

@@ -35,7 +35,7 @@ from rdpy.core import log, error, rss
from rdpy.protocol.rdp import rdp from rdpy.protocol.rdp import rdp
from twisted.internet import reactor from twisted.internet import reactor
log._LOG_LEVEL = log.Level.INFO log._LOG_LEVEL = log.Level.DEBUG
class ProxyServer(rdp.RDPServerObserver): class ProxyServer(rdp.RDPServerObserver):
""" """
@@ -265,7 +265,7 @@ if __name__ == '__main__':
privateKeyFilePath = None privateKeyFilePath = None
certificateFilePath = None certificateFilePath = None
ouputDirectory = None ouputDirectory = None
clientSecurity = "ssl" clientSecurity = rdp.SecurityLevel.RDP_LEVEL_SSL
try: try:
opts, args = getopt.getopt(sys.argv[1:], "hl:k:c:o:r") opts, args = getopt.getopt(sys.argv[1:], "hl:k:c:o:r")
@@ -284,7 +284,7 @@ if __name__ == '__main__':
elif opt == "-o": elif opt == "-o":
ouputDirectory = arg ouputDirectory = arg
elif opt == "-r": elif opt == "-r":
clientSecurity = "rdp" clientSecurity = rdp.SecurityLevel.RDP_LEVEL_RDP
if ouputDirectory is None or not os.path.dirname(ouputDirectory): if ouputDirectory is None or not os.path.dirname(ouputDirectory):
log.error("%s is an invalid output directory"%ouputDirectory) log.error("%s is an invalid output directory"%ouputDirectory)

View File

@@ -222,13 +222,19 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
""" """
self._factory.connectionLost(self, reason) self._factory.connectionLost(self, reason)
def getDescriptor(self):
"""
@return: the twited file descriptor
"""
return self.transport
def close(self): def close(self):
""" """
@summary: Close raw layer @summary: Close raw layer
Use File descriptor directly to not use TLS close Use File descriptor directly to not use TLS close
Because is bugged Because is bugged
""" """
FileDescriptor.loseConnection(self.transport) FileDescriptor.loseConnection(self.getDescriptor())
def expect(self, expectedLen, callback = None): def expect(self, expectedLen, callback = None):
""" """

View File

@@ -23,11 +23,16 @@
""" """
from pyasn1.type import namedtype, univ, tag from pyasn1.type import namedtype, univ, tag
from pyasn1.codec.der import encoder, decoder import pyasn1.codec.der.encoder as der_encoder
import pyasn1.codec.der.decoder as der_decoder
import pyasn1.codec.ber.encoder as ber_encoder
from rdpy.core.type import Stream from rdpy.core.type import Stream
from rdpy.security import x509
from twisted.internet import protocol from twisted.internet import protocol
from OpenSSL import crypto from OpenSSL import crypto
from Crypto.Util import asn1
from rdpy.security import x509
from rdpy.core import error
class NegoToken(univ.Sequence): class NegoToken(univ.Sequence):
componentType = namedtype.NamedTypes( componentType = namedtype.NamedTypes(
@@ -100,11 +105,13 @@ class TSSmartCardCreds(univ.Sequence):
namedtype.OptionalNamedType('domainHint', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))) namedtype.OptionalNamedType('domainHint', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3)))
) )
def encodeDERTRequest(negoTypes = [], pubKeyAuth = None): def encodeDERTRequest(negoTypes = [], authInfo = None, 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: {str} @param authInfo: {str} authentication info TSCredentials encrypted with authentication protocol
@param pubKeyAuth: {str} public key encrypted with authentication protocol
@return: {str} TRequest der encoded
""" """
negoData = NegoData().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)) negoData = NegoData().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))
@@ -120,18 +127,24 @@ def encodeDERTRequest(negoTypes = [], pubKeyAuth = None):
request = TSRequest() request = TSRequest()
request.setComponentByName("version", univ.Integer(2).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))) request.setComponentByName("version", univ.Integer(2).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
request.setComponentByName("negoTokens", negoData)
if i > 0:
request.setComponentByName("negoTokens", negoData)
if not authInfo is None:
request.setComponentByName("authInfo", univ.OctetString(authInfo).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)))
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 encoder.encode(request) return der_encoder.encode(request)
def decodeDERTRequest(s): def decodeDERTRequest(s):
""" """
@summary: Decode the stream as @summary: Decode the stream as
@param s: {str} @param s: {str}
""" """
return decoder.decode(s, asn1Spec=TSRequest())[0] return der_decoder.decode(s, asn1Spec=TSRequest())[0]
def getNegoTokens(tRequest): def getNegoTokens(tRequest):
negoData = tRequest.getComponentByName("negoTokens") negoData = tRequest.getComponentByName("negoTokens")
@@ -140,6 +153,18 @@ def getNegoTokens(tRequest):
def getPubKeyAuth(tRequest): def getPubKeyAuth(tRequest):
return tRequest.getComponentByName("pubKeyAuth").asOctets() return tRequest.getComponentByName("pubKeyAuth").asOctets()
def encodeDERTCredentials(domain, username, password):
passwordCred = TSPasswordCreds()
passwordCred.setComponentByName("domainName", univ.OctetString(domain).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
passwordCred.setComponentByName("userName", univ.OctetString(username).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
passwordCred.setComponentByName("password", univ.OctetString(password).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)))
credentials = TSCredentials()
credentials.setComponentByName("credType", univ.Integer(1).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
credentials.setComponentByName("credentials", univ.OctetString(der_encoder.encode(passwordCred)).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
return der_encoder.encode(credentials)
class CSSP(protocol.Protocol): class CSSP(protocol.Protocol):
""" """
@summary: Handle CSSP connection @summary: Handle CSSP connection
@@ -152,6 +177,10 @@ class CSSP(protocol.Protocol):
""" """
self._layer = layer self._layer = layer
self._authenticationProtocol = authenticationProtocol self._authenticationProtocol = authenticationProtocol
#IGenericSecurityService
self._interface = None
#function call at the end of nego
self._callback = None
def setFactory(self, factory): def setFactory(self, factory):
""" """
@@ -173,6 +202,7 @@ class CSSP(protocol.Protocol):
@summary: install proxy @summary: install proxy
""" """
self._layer.transport = self self._layer.transport = self
self._layer.getDescriptor = lambda:self.transport
self._layer.connectionMade() self._layer.connectionMade()
def write(self, data): def write(self, data):
@@ -189,10 +219,14 @@ class CSSP(protocol.Protocol):
""" """
self.transport.startTLS(sslContext) self.transport.startTLS(sslContext)
def startNLA(self): def startNLA(self, sslContext, callback = None):
""" """
@summary: start NLA authentication @summary: start NLA authentication
@param sslContext: {ssl.ClientContextFactory | ssl.DefaultOpenSSLContextFactory} context use for TLS protocol
@param callback: {function} function call when cssp layer is read
""" """
self._callback = callback
self.startTLS(sslContext)
#send negotiate message #send negotiate message
self.transport.write(encodeDERTRequest( negoTypes = [ self._authenticationProtocol.getNegotiateMessage() ] )) self.transport.write(encodeDERTRequest( negoTypes = [ self._authenticationProtocol.getNegotiateMessage() ] ))
#next state is receive a challenge #next state is receive a challenge
@@ -201,17 +235,41 @@ class CSSP(protocol.Protocol):
def recvChallenge(self, data): def recvChallenge(self, data):
""" """
@summary: second state in cssp automata @summary: second state in cssp automata
@param {str}: all data available on buffer @param data : {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) request = decodeDERTRequest(data)
message, interface = self._authenticationProtocol.getAuthenticateMessage(getNegoTokens(request)[0]) message, self._interface = self._authenticationProtocol.getAuthenticateMessage(getNegoTokens(request)[0])
#get back public key
#convert from der to ber...
pubKeyDer = crypto.dump_privatekey(crypto.FILETYPE_ASN1, self.transport.protocol._tlsConnection.get_peer_certificate().get_pubkey())
pubKey = asn1.DerSequence()
pubKey.decode(pubKeyDer)
rsa = x509.RSAPublicKey()
rsa.setComponentByName("modulus", univ.Integer(pubKey[1]))
rsa.setComponentByName("publicExponent", univ.Integer(pubKey[2]))
self._pubKeyBer = ber_encoder.encode(rsa)
#send authenticate message with public key encoded #send authenticate message with public key encoded
import ntlm self.transport.write(encodeDERTRequest( negoTypes = [ message ], pubKeyAuth = self._interface.GSS_WrapEx(self._pubKeyBer)))
self.transport.write(encodeDERTRequest( negoTypes = [ message ], pubKeyAuth = interface.GSS_WrapEx("".join([chr(i) for i in ntlm.pubKeyHex])))) #next step is received public key incremented by one
self.dataReceived = self.recvPubKeyInc
def recvPubKeyInc(self, data):
"""
@summary: the server send the pubKeyBer + 1
@param data : {str} all data available on buffer
"""
request = decodeDERTRequest(data)
pubKeyInc = self._interface.GSS_UnWrapEx(getPubKeyAuth(request))
#check pubKeyInc = self._pubKeyBer + 1
if not self._pubKeyBer[:-1] == pubKeyInc[:-1] and ord(self._pubKeyBer[-1]) + 1 == pubKeyInc[-1]:
raise error.InvalidExpectedDataException("CSSP : Invalid public key increment")
domain, user, password = self._authenticationProtocol.getEncodedCredentials()
#send credentials
self.transport.write(encodeDERTRequest( authInfo = self._interface.GSS_WrapEx(encodeDERTCredentials(domain, user, password))))
#reset state back to normal state
self.dataReceived = lambda x: self.__class__.dataReceived(self, x)
if not self._callback is None:
self._callback()

View File

@@ -28,7 +28,7 @@ import rdpy.security.pyDes as pyDes
import rdpy.security.rc4 as rc4 import rdpy.security.rc4 as rc4
from rdpy.security.rsa_wrapper import random from rdpy.security.rsa_wrapper import random
from rdpy.core.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt24Le, UInt32Le, sizeof, Stream from rdpy.core.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt24Le, UInt32Le, sizeof, Stream
from rdpy.core import filetimes from rdpy.core import filetimes, error
class MajorVersion(object): class MajorVersion(object):
""" """
@@ -80,6 +80,22 @@ class Negotiate(object):
NTLM_NEGOTIATE_OEM = 0x00000002 NTLM_NEGOTIATE_OEM = 0x00000002
NTLMSSP_NEGOTIATE_UNICODE = 0x00000001 NTLMSSP_NEGOTIATE_UNICODE = 0x00000001
class AvId(object):
"""
@see: https://msdn.microsoft.com/en-us/library/cc236646.aspx
"""
MsvAvEOL = 0x0000
MsvAvNbComputerName = 0x0001
MsvAvNbDomainName = 0x0002
MsvAvDnsComputerName = 0x0003
MsvAvDnsDomainName = 0x0004
MsvAvDnsTreeName = 0x0005
MsvAvFlags = 0x0006
MsvAvTimestamp = 0x0007
MsvAvSingleHost = 0x0008
MsvAvTargetName = 0x0009
MsvChannelBindings = 0x000A
def getPayLoadField(message, length, bufferOffset): def getPayLoadField(message, length, bufferOffset):
if length == 0: if length == 0:
return None return None
@@ -101,6 +117,16 @@ class Version(CompositeType):
self.Reserved = UInt24Le() self.Reserved = UInt24Le()
self.NTLMRevisionCurrent = UInt8(NTLMRevision.NTLMSSP_REVISION_W2K3) self.NTLMRevisionCurrent = UInt8(NTLMRevision.NTLMSSP_REVISION_W2K3)
class AvPair(CompositeType):
"""
@see: https://msdn.microsoft.com/en-us/library/cc236646.aspx
"""
def __init__(self):
CompositeType.__init__(self)
self.AvId = UInt16Le()
self.AvLen = UInt16Le(lambda:sizeof(self.Value))
self.Value = String(readLen = self.AvLen)
class MessageSignatureEx(CompositeType): class MessageSignatureEx(CompositeType):
""" """
@summary: Signature for message @summary: Signature for message
@@ -109,7 +135,7 @@ class MessageSignatureEx(CompositeType):
def __init__(self): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.Version = UInt32Le(0x00000001, constant = True) self.Version = UInt32Le(0x00000001, constant = True)
self.Checksum = String(readLen = CallableValue(16)) self.Checksum = String(readLen = CallableValue(8))
self.SeqNum = UInt32Le() self.SeqNum = UInt32Le()
class NegotiateMessage(CompositeType): class NegotiateMessage(CompositeType):
@@ -166,7 +192,22 @@ class ChallengeMessage(CompositeType):
return getPayLoadField(self, self.TargetNameLen.value, self.TargetNameBufferOffset.value) return getPayLoadField(self, self.TargetNameLen.value, self.TargetNameBufferOffset.value)
def getTargetInfo(self): def getTargetInfo(self):
return getPayLoadField(self, self.TargetInfoLen.value - 4, self.TargetInfoBufferOffset.value) return getPayLoadField(self, self.TargetInfoLen.value, self.TargetInfoBufferOffset.value)
def getTargetInfoAsAvPairArray(self):
"""
@summary: Parse Target info field to retrieve array of AvPair
@return: {map(AvId, str)}
"""
result = {}
s = Stream(self.getTargetInfo())
while(True):
avPair = AvPair()
s.readType(avPair)
if avPair.AvId.value == AvId.MsvAvEOL:
return result
result[avPair.AvId.value] = avPair.Value.value
class AuthenticateMessage(CompositeType): class AuthenticateMessage(CompositeType):
""" """
@@ -205,7 +246,7 @@ class AuthenticateMessage(CompositeType):
self.NegotiateFlags = UInt32Le() self.NegotiateFlags = UInt32Le()
self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION)) self.Version = Version(conditional = lambda:(self.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_VERSION))
#self.MIC = String("\x00" * 16, readLen = CallableValue(16)) self.MIC = String("\x00" * 16, readLen = CallableValue(16))
self.Payload = String() self.Payload = String()
def getUserName(self): def getUserName(self):
@@ -223,7 +264,7 @@ class AuthenticateMessage(CompositeType):
def getEncryptedRandomSession(self): def getEncryptedRandomSession(self):
return getPayLoadField(self, self.EncryptedRandomSessionLen.value, self.EncryptedRandomSessionBufferOffset.value) return getPayLoadField(self, self.EncryptedRandomSessionLen.value, self.EncryptedRandomSessionBufferOffset.value)
def createAuthenticationMessage(domain, user, NtChallengeResponse, LmChallengeResponse, EncryptedRandomSessionKey): def createAuthenticationMessage(NegFlag, domain, user, NtChallengeResponse, LmChallengeResponse, EncryptedRandomSessionKey, Workstation):
""" """
@summary: Create an Authenticate Message @summary: Create an Authenticate Message
@param domain: {str} domain microsoft @param domain: {str} domain microsoft
@@ -233,6 +274,7 @@ def createAuthenticationMessage(domain, user, NtChallengeResponse, LmChallengeRe
@param EncryptedRandomSessionKey: {str} EncryptedRandomSessionKey @param EncryptedRandomSessionKey: {str} EncryptedRandomSessionKey
""" """
message = AuthenticateMessage() message = AuthenticateMessage()
message.NegotiateFlags.value = NegFlag
#fill message #fill message
offset = sizeof(message) offset = sizeof(message)
@@ -246,6 +288,11 @@ def createAuthenticationMessage(domain, user, NtChallengeResponse, LmChallengeRe
message.Payload.value += user message.Payload.value += user
offset += len(user) offset += len(user)
message.WorkstationLen.value = len(Workstation)
message.WorkstationBufferOffset.value = offset
message.Payload.value += Workstation
offset += len(Workstation)
message.LmChallengeResponseLen.value = len(LmChallengeResponse) message.LmChallengeResponseLen.value = len(LmChallengeResponse)
message.LmChallengeResponseBufferOffset.value = offset message.LmChallengeResponseBufferOffset.value = offset
message.Payload.value += LmChallengeResponse message.Payload.value += LmChallengeResponse
@@ -399,7 +446,7 @@ def ComputeResponsev2(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChall
Responserversion = "\x01" Responserversion = "\x01"
HiResponserversion = "\x01" HiResponserversion = "\x01"
temp = Responserversion + HiResponserversion + Z(6) + Time + ClientChallenge + Z(4) + ServerName + Z(4) temp = Responserversion + HiResponserversion + Z(6) + Time + ClientChallenge + Z(4) + ServerName
NTProofStr = HMAC_MD5(ResponseKeyNT, ServerChallenge + temp) NTProofStr = HMAC_MD5(ResponseKeyNT, ServerChallenge + temp)
NtChallengeResponse = NTProofStr + temp NtChallengeResponse = NTProofStr + temp
LmChallengeResponse = HMAC_MD5(ResponseKeyLM, ServerChallenge + ClientChallenge) + ClientChallenge LmChallengeResponse = HMAC_MD5(ResponseKeyLM, ServerChallenge + ClientChallenge) + ClientChallenge
@@ -427,6 +474,19 @@ def MAC(handle, SigningKey, SeqNum, Message):
signature.Checksum.value = rc4.crypt(handle, HMAC_MD5(SigningKey, s.getvalue() + Message)[:8]) signature.Checksum.value = rc4.crypt(handle, HMAC_MD5(SigningKey, s.getvalue() + Message)[:8])
return signature return signature
def MIC(ExportedSessionKey, negotiateMessage, challengeMessage, authenticateMessage):
"""
@summary: Compute MIC signature
@param negotiateMessage: {NegotiateMessage}
@param challengeMessage: {ChallengeMessage}
@param authenticateMessage: {AuthenticateMessage}
@return: {str} signature
@see: https://msdn.microsoft.com/en-us/library/cc236676.aspx
"""
s = Stream()
s.writeType((negotiateMessage, challengeMessage, authenticateMessage))
return HMAC_MD5(ExportedSessionKey, s.getvalue())
class NTLMv2(sspi.IAuthenticationProtocol): class NTLMv2(sspi.IAuthenticationProtocol):
""" """
@@ -435,16 +495,23 @@ class NTLMv2(sspi.IAuthenticationProtocol):
def __init__(self, domain, user, password): def __init__(self, domain, user, password):
self._domain = domain self._domain = domain
self._user = user self._user = user
self._password = password
self._enableUnicode = False
#https://msdn.microsoft.com/en-us/library/cc236700.aspx #https://msdn.microsoft.com/en-us/library/cc236700.aspx
self._ResponseKeyNT = NTOWFv2(password, user, domain) self._ResponseKeyNT = NTOWFv2(password, user, domain)
self._ResponseKeyLM = LMOWFv2(password, user, domain) self._ResponseKeyLM = LMOWFv2(password, user, domain)
#For MIC computation
self._negotiateMessage = None
self._challengeMessage = None
self._authenticateMessage = None
def getNegotiateMessage(self): def getNegotiateMessage(self):
""" """
@summary: generate first handshake messgae @summary: generate first handshake messgae
""" """
message = NegotiateMessage() self._negotiateMessage = NegotiateMessage()
message.NegotiateFlags.value = (Negotiate.NTLMSSP_NEGOTIATE_KEY_EXCH | self._negotiateMessage.NegotiateFlags.value = (Negotiate.NTLMSSP_NEGOTIATE_KEY_EXCH |
Negotiate.NTLMSSP_NEGOTIATE_128 | Negotiate.NTLMSSP_NEGOTIATE_128 |
Negotiate.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | Negotiate.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY |
Negotiate.NTLMSSP_NEGOTIATE_ALWAYS_SIGN | Negotiate.NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
@@ -453,7 +520,7 @@ class NTLMv2(sspi.IAuthenticationProtocol):
Negotiate.NTLMSSP_NEGOTIATE_SIGN | Negotiate.NTLMSSP_NEGOTIATE_SIGN |
Negotiate.NTLMSSP_REQUEST_TARGET | Negotiate.NTLMSSP_REQUEST_TARGET |
Negotiate.NTLMSSP_NEGOTIATE_UNICODE) Negotiate.NTLMSSP_NEGOTIATE_UNICODE)
return message return self._negotiateMessage
def getAuthenticateMessage(self, s): def getAuthenticateMessage(self, s):
""" """
@@ -462,13 +529,21 @@ class NTLMv2(sspi.IAuthenticationProtocol):
@return: {(AuthenticateMessage, NTLMv2SecurityInterface)} Last handshake message and security interface use to encrypt @return: {(AuthenticateMessage, NTLMv2SecurityInterface)} Last handshake message and security interface use to encrypt
@see: https://msdn.microsoft.com/en-us/library/cc236676.aspx @see: https://msdn.microsoft.com/en-us/library/cc236676.aspx
""" """
challenge = ChallengeMessage() self._challengeMessage = ChallengeMessage()
s.readType(challenge) s.readType(self._challengeMessage)
ServerChallenge = challenge.ServerChallenge.value ServerChallenge = self._challengeMessage.ServerChallenge.value
ClientChallenge = random(64) ClientChallenge = random(64)
Timestamp = CurrentFileTimes()
ServerName = challenge.getTargetInfo() computeMIC = False
ServerName = self._challengeMessage.getTargetInfo()
infos = self._challengeMessage.getTargetInfoAsAvPairArray()
if infos.has_key(AvId.MsvAvTimestamp):
Timestamp = infos[AvId.MsvAvTimestamp]
computeMIC = True
else:
Timestamp = CurrentFileTimes()
NtChallengeResponse, LmChallengeResponse, SessionBaseKey = ComputeResponsev2(self._ResponseKeyNT, self._ResponseKeyLM, ServerChallenge, ClientChallenge, Timestamp, ServerName) NtChallengeResponse, LmChallengeResponse, SessionBaseKey = ComputeResponsev2(self._ResponseKeyNT, self._ResponseKeyLM, ServerChallenge, ClientChallenge, Timestamp, ServerName)
KeyExchangeKey = KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge) KeyExchangeKey = KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge)
@@ -476,9 +551,15 @@ class NTLMv2(sspi.IAuthenticationProtocol):
EncryptedRandomSessionKey = RC4K(KeyExchangeKey, ExportedSessionKey) EncryptedRandomSessionKey = RC4K(KeyExchangeKey, ExportedSessionKey)
domain, user = self._domain, self._user domain, user = self._domain, self._user
if challenge.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_UNICODE: if self._challengeMessage.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_UNICODE:
self._enableUnicode = True
domain, user = UNICODE(domain), UNICODE(user) domain, user = UNICODE(domain), UNICODE(user)
message = createAuthenticationMessage(domain, user, NtChallengeResponse, LmChallengeResponse, EncryptedRandomSessionKey) self._authenticateMessage = createAuthenticationMessage(self._challengeMessage.NegotiateFlags.value, domain, user, NtChallengeResponse, LmChallengeResponse, EncryptedRandomSessionKey, "")
if computeMIC:
self._authenticateMessage.MIC.value = MIC(ExportedSessionKey, self._negotiateMessage, self._challengeMessage, self._authenticateMessage)
else:
self._authenticateMessage.MIC._conditional = lambda:False
ClientSigningKey = SIGNKEY(ExportedSessionKey, True) ClientSigningKey = SIGNKEY(ExportedSessionKey, True)
ServerSigningKey = SIGNKEY(ExportedSessionKey, False) ServerSigningKey = SIGNKEY(ExportedSessionKey, False)
@@ -487,7 +568,17 @@ class NTLMv2(sspi.IAuthenticationProtocol):
interface = NTLMv2SecurityInterface(rc4.RC4Key(ClientSealingKey), rc4.RC4Key(ServerSealingKey), ClientSigningKey, ServerSigningKey) interface = NTLMv2SecurityInterface(rc4.RC4Key(ClientSealingKey), rc4.RC4Key(ServerSealingKey), ClientSigningKey, ServerSigningKey)
return message, interface return self._authenticateMessage, interface
def getEncodedCredentials(self):
"""
@summary: return encoded credentials accorded with authentication protocol nego
@return: (domain, username, password)
"""
if self._enableUnicode:
return UNICODE(self._domain), UNICODE(self._user), UNICODE(self._password)
else:
return self._domain, self._user, self._password
class NTLMv2SecurityInterface(sspi.IGenericSecurityService): class NTLMv2SecurityInterface(sspi.IGenericSecurityService):
@@ -519,196 +610,26 @@ class NTLMv2SecurityInterface(sspi.IGenericSecurityService):
s = Stream() s = Stream()
s.writeType(signature) s.writeType(signature)
return s.getvalue() + encryptedData return s.getvalue() + encryptedData
pubKeyHex = [
0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0x9E,
0x95, 0xB5, 0x41, 0x03, 0xC5, 0x33, 0xEA, 0x29,
0x65, 0x2B, 0x65, 0xEF, 0x30, 0x71, 0xDD, 0x73,
0xBB, 0x30, 0x3B, 0xEC, 0xCA, 0x72, 0xCF, 0xBD,
0xE0, 0xF8, 0x21, 0xFF, 0xA6, 0x97, 0x76, 0xA1,
0x08, 0xB5, 0xD2, 0xC6, 0x95, 0x81, 0xD2, 0xBA,
0x71, 0x10, 0x4A, 0xAC, 0x25, 0x34, 0x37, 0xA0,
0xC3, 0x57, 0xF0, 0xEA, 0x1F, 0x8C, 0x84, 0xEB,
0x7B, 0xE6, 0x6C, 0x50, 0x26, 0x1F, 0xB7, 0x41,
0x0A, 0x58, 0xD3, 0x80, 0x87, 0x3D, 0x0B, 0x41,
0xD9, 0xBC, 0x54, 0x3A, 0x0F, 0x77, 0x14, 0x79,
0xF5, 0xB9, 0xA4, 0x38, 0xEB, 0x13, 0x08, 0x35,
0xAE, 0xBF, 0xB3, 0x17, 0x5A, 0xE2, 0x58, 0x89,
0x39, 0xC4, 0x22, 0x7F, 0x16, 0x57, 0x90, 0x08,
0xAF, 0x91, 0x3B, 0x95, 0xC8, 0x53, 0xD0, 0xC0,
0x8E, 0x19, 0x8A, 0xF3, 0x10, 0xBC, 0xC8, 0xC7,
0x42, 0xFB, 0x12, 0xDE, 0x2D, 0x5E, 0x83, 0x02,
0x03, 0x01, 0x00, 0x01 ]
peer0_0 = [
0x30, 0x2f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0xa1,
0x28, 0x30, 0x26, 0x30, 0x24, 0xa0, 0x22, 0x04,
0x20, 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50,
0x00, 0x01, 0x00, 0x00, 0x00, 0x35, 0x82, 0x08,
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00 ]
peer1_0 = [
0x30, 0x82, 0x01, 0x09, 0xa0, 0x03, 0x02, 0x01,
0x02, 0xa1, 0x82, 0x01, 0x00, 0x30, 0x81, 0xfd,
0x30, 0x81, 0xfa, 0xa0, 0x81, 0xf7, 0x04, 0x81,
0xf4, 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50,
0x00, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e,
0x00, 0x38, 0x00, 0x00, 0x00, 0x35, 0x82, 0x89,
0x62, 0x0a, 0xee, 0xd7, 0xc3, 0xeb, 0x8e, 0x34,
0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xae, 0x00, 0xae, 0x00, 0x46, 0x00, 0x00,
0x00, 0x06, 0x01, 0xb1, 0x1d, 0x00, 0x00, 0x00,
0x0f, 0x53, 0x00, 0x49, 0x00, 0x52, 0x00, 0x41,
0x00, 0x44, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x02,
0x00, 0x0e, 0x00, 0x53, 0x00, 0x49, 0x00, 0x52,
0x00, 0x41, 0x00, 0x44, 0x00, 0x45, 0x00, 0x4c,
0x00, 0x01, 0x00, 0x16, 0x00, 0x57, 0x00, 0x41,
0x00, 0x56, 0x00, 0x2d, 0x00, 0x47, 0x00, 0x4c,
0x00, 0x57, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x30,
0x00, 0x39, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x53,
0x00, 0x69, 0x00, 0x72, 0x00, 0x61, 0x00, 0x64,
0x00, 0x65, 0x00, 0x6c, 0x00, 0x2e, 0x00, 0x6c,
0x00, 0x6f, 0x00, 0x63, 0x00, 0x61, 0x00, 0x6c,
0x00, 0x03, 0x00, 0x32, 0x00, 0x77, 0x00, 0x61,
0x00, 0x76, 0x00, 0x2d, 0x00, 0x67, 0x00, 0x6c,
0x00, 0x77, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x30,
0x00, 0x39, 0x00, 0x2e, 0x00, 0x53, 0x00, 0x69,
0x00, 0x72, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65,
0x00, 0x6c, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f,
0x00, 0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x05,
0x00, 0x1a, 0x00, 0x53, 0x00, 0x69, 0x00, 0x72,
0x00, 0x61, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6c,
0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63,
0x00, 0x61, 0x00, 0x6c, 0x00, 0x07, 0x00, 0x08,
0x00, 0xe5, 0x40, 0x3c, 0xa6, 0x68, 0x57, 0xd0,
0x01, 0x00, 0x00, 0x00, 0x00 ]
peer0_1 = [
0x30, 0x82, 0x02, 0x21, 0xa0, 0x03, 0x02, 0x01,
0x02, 0xa1, 0x82, 0x01, 0x76, 0x30, 0x82, 0x01,
0x72, 0x30, 0x82, 0x01, 0x6e, 0xa0, 0x82, 0x01,
0x6a, 0x04, 0x82, 0x01, 0x66, 0x4e, 0x54, 0x4c,
0x4d, 0x53, 0x53, 0x50, 0x00, 0x03, 0x00, 0x00,
0x00, 0x18, 0x00, 0x18, 0x00, 0x64, 0x00, 0x00,
0x00, 0xda, 0x00, 0xda, 0x00, 0x7c, 0x00, 0x00,
0x00, 0x0e, 0x00, 0x0e, 0x00, 0x40, 0x00, 0x00,
0x00, 0x16, 0x00, 0x16, 0x00, 0x4e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x00, 0x10, 0x00, 0x56, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x69,
0x00, 0x72, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65,
0x00, 0x6c, 0x00, 0x73, 0x00, 0x70, 0x00, 0x65,
0x00, 0x79, 0x00, 0x72, 0x00, 0x65, 0x00, 0x66,
0x00, 0x69, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65,
0x00, 0x8a, 0x01, 0x34, 0xd8, 0x57, 0x6e, 0x14,
0x2b, 0xda, 0xc6, 0x91, 0x02, 0x49, 0xbb, 0xc4,
0x00, 0x19, 0x6c, 0x60, 0x26, 0x16, 0xdb, 0x37,
0x8f, 0x98, 0xe1, 0x04, 0xf8, 0x36, 0x6a, 0x96,
0xa2, 0xa1, 0x9a, 0xf9, 0x5f, 0x1f, 0x04, 0x63,
0x69, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x38, 0x8d, 0x10, 0x08, 0x71, 0x57, 0xd0,
0x01, 0x19, 0x6c, 0x60, 0x26, 0x16, 0xdb, 0x37,
0x8f, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x0e,
0x00, 0x53, 0x00, 0x49, 0x00, 0x52, 0x00, 0x41,
0x00, 0x44, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x01,
0x00, 0x16, 0x00, 0x57, 0x00, 0x41, 0x00, 0x56,
0x00, 0x2d, 0x00, 0x47, 0x00, 0x4c, 0x00, 0x57,
0x00, 0x2d, 0x00, 0x30, 0x00, 0x30, 0x00, 0x39,
0x00, 0x04, 0x00, 0x1a, 0x00, 0x53, 0x00, 0x69,
0x00, 0x72, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65,
0x00, 0x6c, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f,
0x00, 0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x03,
0x00, 0x32, 0x00, 0x77, 0x00, 0x61, 0x00, 0x76,
0x00, 0x2d, 0x00, 0x67, 0x00, 0x6c, 0x00, 0x77,
0x00, 0x2d, 0x00, 0x30, 0x00, 0x30, 0x00, 0x39,
0x00, 0x2e, 0x00, 0x53, 0x00, 0x69, 0x00, 0x72,
0x00, 0x61, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6c,
0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63,
0x00, 0x61, 0x00, 0x6c, 0x00, 0x05, 0x00, 0x1a,
0x00, 0x53, 0x00, 0x69, 0x00, 0x72, 0x00, 0x61,
0x00, 0x64, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x2e,
0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x61,
0x00, 0x6c, 0x00, 0x07, 0x00, 0x08, 0x00, 0xe5,
0x40, 0x3c, 0xa6, 0x68, 0x57, 0xd0, 0x01, 0x00,
0x00, 0x00, 0x00, 0x59, 0x49, 0x84, 0x63, 0xf2,
0x84, 0x53, 0x18, 0xea, 0xa4, 0xc3, 0xb6, 0x97,
0x0d, 0x3e, 0x38, 0xa3, 0x81, 0x9f, 0x04, 0x81,
0x9c, 0x01, 0x00, 0x00, 0x00, 0xc9, 0x56, 0x22,
0x84, 0x7d, 0xba, 0xa2, 0xe6, 0x00, 0x00, 0x00,
0x00, 0x1c, 0x6d, 0x39, 0xe1, 0x5a, 0x31, 0x5d,
0xf5, 0x01, 0xa6, 0xea, 0x4b, 0xaf, 0x83, 0x13,
0xdc, 0x8a, 0x45, 0xb3, 0x76, 0xc6, 0x3d, 0xbf,
0x73, 0x4c, 0x93, 0xe6, 0x75, 0x8b, 0x42, 0x21,
0xea, 0xe6, 0x0c, 0xfa, 0x3c, 0xd0, 0x7c, 0x8d,
0xd6, 0x2a, 0x97, 0x7a, 0x49, 0xb5, 0x7d, 0xeb,
0xc2, 0x94, 0xc0, 0x84, 0xb4, 0xef, 0x7f, 0x1e,
0xa3, 0xa3, 0x3f, 0x61, 0x7c, 0x1c, 0xd9, 0x82,
0xc6, 0x0b, 0x6c, 0x85, 0x15, 0xb0, 0x47, 0x25,
0xe9, 0x0a, 0x88, 0x58, 0x3c, 0x6d, 0x8e, 0x60,
0x2a, 0xbc, 0x04, 0x57, 0x7f, 0x5b, 0x03, 0x7c,
0x7a, 0x8f, 0x1b, 0x7b, 0xe3, 0x67, 0xb6, 0x02,
0xa4, 0xc0, 0xdd, 0x9e, 0x97, 0x4c, 0xd8, 0x86,
0x5c, 0x9a, 0x45, 0x0d, 0x85, 0x4b, 0x46, 0x87,
0xde, 0xcf, 0x31, 0x72, 0xe3, 0xd7, 0x5d, 0x0b,
0x67, 0x1b, 0xa1, 0xde, 0x24, 0x87, 0xdf, 0xd9,
0xb2, 0x18, 0xfd, 0x5a, 0x29, 0xbb, 0x35, 0xe0,
0x3d, 0x9f, 0x85, 0xf7, 0x36 ]
if __name__ == "__main__":
import cssp, hexdump
negotiate_data_request = cssp.decodeDERTRequest(Stream("".join([chr(i) for i in peer0_0])))
challenge_data_request = cssp.decodeDERTRequest(Stream("".join([chr(i) for i in peer1_0])))
authenticate_data_request = cssp.decodeDERTRequest(Stream("".join([chr(i) for i in peer0_1])))
negotiate_data = cssp.getNegoTokens(negotiate_data_request)[0] def GSS_UnWrapEx(self, data):
challenge_data = cssp.getNegoTokens(challenge_data_request)[0] """
authenticate_data = cssp.getNegoTokens(authenticate_data_request)[0] @summary: decrypt data with key exchange in Authentication protocol
@param data: {str}
negotiate = NegotiateMessage() """
negotiate_data.readType(negotiate) signature = MessageSignatureEx()
message = String()
challenge = ChallengeMessage() s = Stream(data)
challenge_data.readType(challenge) s.readType((signature, message))
ServerChallenge = challenge.ServerChallenge.value
ServerName = challenge.getTargetInfo()
authenticate = AuthenticateMessage()
authenticate_data.readType(authenticate)
NtChallengeResponseTemp = authenticate.getNtChallengeResponse()
NTProofStr = NtChallengeResponseTemp[:16]
temp = NtChallengeResponseTemp[16:]
Timestamp = temp[8:16]
ClientChallenge = temp[16:24]
EncryptedRandomSessionKey = authenticate.getEncryptedRandomSession()
domain = ""
user = ""
password = ""
ResponseKeyNT = NTOWFv2(password, user, domain)
ResponseKeyLM = LMOWFv2(password, user, domain)
NtChallengeResponse, LmChallengeResponse, SessionBaseKey = ComputeResponsev2(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChallenge, Timestamp, ServerName) #decrypt message
KeyExchangeKey = KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge) plaintextMessage = rc4.crypt(self._decryptHandle, message.value)
ExportedSessionKey = RC4K(KeyExchangeKey, EncryptedRandomSessionKey) checksum = rc4.crypt(self._decryptHandle, signature.Checksum.value)
domain, user = domain, user #recompute checksum
if challenge.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_UNICODE: t = Stream()
domain, user = UNICODE(domain), UNICODE(user) t.writeType(signature.SeqNum)
message = createAuthenticationMessage(domain, user, NtChallengeResponse, LmChallengeResponse, EncryptedRandomSessionKey) verify = HMAC_MD5(self._verifyKey, t.getvalue() + plaintextMessage)[:8]
if verify != checksum:
ClientSigningKey = SIGNKEY(ExportedSessionKey, True) raise error.InvalidExpectedDataException("NTLMv2SecurityInterface : Invalid checksum")
ServerSigningKey = SIGNKEY(ExportedSessionKey, False)
ClientSealingKey = SEALKEY(ExportedSessionKey, True) return plaintextMessage
ServerSealingKey = SEALKEY(ExportedSessionKey, False)
interface = NTLMv2SecurityInterface(rc4.RC4Key(ClientSealingKey), rc4.RC4Key(ServerSealingKey), ClientSigningKey, ServerSigningKey)
EncryptedPubKeySrc = cssp.getPubKeyAuth(authenticate_data_request)
EncryptedPubKeyDst = interface.GSS_WrapEx("".join([chr(i) for i in pubKeyHex]))
print "EncryptedPubKeySrc"
hexdump.hexdump(EncryptedPubKeySrc)
print "EncryptedPubKeyDst"
hexdump.hexdump(EncryptedPubKeyDst)

View File

@@ -42,6 +42,13 @@ class IAuthenticationProtocol(object):
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "getAuthenticateMessage", "IAuthenticationProtocol")) raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "getAuthenticateMessage", "IAuthenticationProtocol"))
def getEncodedCredentials(self):
"""
@summary: return encoded credentials accorded with authentication protocol nego
@return: (domain, username, password)
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "getEncodedCredentials", "IAuthenticationProtocol"))
class IGenericSecurityService(object): class IGenericSecurityService(object):
""" """
@summary: use by application from authentification protocol @summary: use by application from authentification protocol
@@ -49,7 +56,14 @@ class IGenericSecurityService(object):
""" """
def GSS_WrapEx(self, data): def GSS_WrapEx(self, data):
""" """
@summary: encrypt data with key exchage in Authentication protocol @summary: encrypt data with key exchange in Authentication protocol
@param data: {str} @param data: {str}
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "GSS_WrapEx", "IGenericSecurityService")) raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "GSS_WrapEx", "IGenericSecurityService"))
def GSS_UnWrapEx(self, data):
"""
@summary: decrypt data with key exchange in Authentication protocol
@param data: {str}
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "GSS_UnWrapEx", "IGenericSecurityService"))

View File

@@ -31,6 +31,14 @@ import tpkt, x224, sec
from t125 import mcs, gcc from t125 import mcs, gcc
from nla import cssp, ntlm from nla import cssp, ntlm
class SecurityLevel(object):
"""
@summary: RDP security level
"""
RDP_LEVEL_RDP = 0
RDP_LEVEL_SSL = 1
RDP_LEVEL_NLA = 2
class RDPClientController(pdu.layer.PDUClientListener): class RDPClientController(pdu.layer.PDUClientListener):
""" """
Manage RDP stack as client Manage RDP stack as client
@@ -59,7 +67,8 @@ class RDPClientController(pdu.layer.PDUClientListener):
@return: return Protocol layer for twisted @return: return Protocol layer for twisted
In case of RDP TPKT is the Raw layer In case of RDP TPKT is the Raw layer
""" """
return self._tpktLayer #build a cssp wrapper in case of nla authentication
return cssp.CSSP(self._tpktLayer, ntlm.NTLMv2(self._secLayer._info.domain.value, self._secLayer._info.userName.value, self._secLayer._info.password.value))
def getColorDepth(self): def getColorDepth(self):
""" """
@@ -139,13 +148,13 @@ class RDPClientController(pdu.layer.PDUClientListener):
def setSecurityLevel(self, level): def setSecurityLevel(self, level):
""" """
@summary: Request basic security @summary: Request basic security
@param level: {str} (ssl | rdp | nla) @param level: {SecurityLevel}
""" """
if level == "rdp": if level == SecurityLevel.RDP_LEVEL_RDP:
self._x224Layer._requestedProtocol = x224.Protocols.PROTOCOL_RDP self._x224Layer._requestedProtocol = x224.Protocols.PROTOCOL_RDP
elif level == "ssl": elif level == SecurityLevel.RDP_LEVEL_SSL:
self._x224Layer._requestedProtocol = x224.Protocols.PROTOCOL_SSL self._x224Layer._requestedProtocol = x224.Protocols.PROTOCOL_SSL
elif level == "nla": elif level == SecurityLevel.RDP_LEVEL_NLA:
self._x224Layer._requestedProtocol = x224.Protocols.PROTOCOL_SSL | x224.Protocols.PROTOCOL_HYBRID self._x224Layer._requestedProtocol = x224.Protocols.PROTOCOL_SSL | x224.Protocols.PROTOCOL_HYBRID
def addClientObserver(self, observer): def addClientObserver(self, observer):
@@ -351,6 +360,7 @@ class RDPServerController(pdu.layer.PDUServerListener):
self._x224Layer = x224.Server(self._mcsLayer, privateKeyFileName, certificateFileName, False) self._x224Layer = x224.Server(self._mcsLayer, privateKeyFileName, certificateFileName, False)
#transport packet (protocol layer) #transport packet (protocol layer)
self._tpktLayer = tpkt.TPKT(self._x224Layer) self._tpktLayer = tpkt.TPKT(self._x224Layer)
#fastpath stack #fastpath stack
self._pduLayer.initFastPath(self._secLayer) self._pduLayer.initFastPath(self._secLayer)
self._secLayer.initFastPath(self._tpktLayer) self._secLayer.initFastPath(self._tpktLayer)
@@ -527,8 +537,7 @@ class ClientFactory(layer.RawLayerClientFactory):
""" """
controller = RDPClientController() controller = RDPClientController()
self.buildObserver(controller, addr) self.buildObserver(controller, addr)
#Add cssp proxy in case of nla protocol return controller.getProtocol()
return cssp.CSSP(controller.getProtocol(), ntlm.NTLMv2("toto", "coco", "lolo"))
def buildObserver(self, controller, addr): def buildObserver(self, controller, addr):
""" """

View File

@@ -26,8 +26,6 @@ from rdpy.core.layer import RawLayer
from rdpy.core.type import UInt8, UInt16Be, sizeof from rdpy.core.type import UInt8, UInt16Be, sizeof
from rdpy.core.error import CallPureVirtualFuntion from rdpy.core.error import CallPureVirtualFuntion
from nla import cssp, ntlm
class Action(object): class Action(object):
""" """
@see: http://msdn.microsoft.com/en-us/library/cc240621.aspx @see: http://msdn.microsoft.com/en-us/library/cc240621.aspx
@@ -218,9 +216,9 @@ class TPKT(RawLayer, IFastPathSender):
""" """
self.transport.startTLS(sslContext) self.transport.startTLS(sslContext)
def startNLA(self): def startNLA(self, sslContext, callback):
""" """
@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
""" """
self.transport.startNLA() self.transport.startNLA(sslContext, callback)

View File

@@ -208,19 +208,29 @@ class Client(X224Layer):
if self._selectedProtocol in [ Protocols.PROTOCOL_HYBRID_EX ]: if self._selectedProtocol in [ Protocols.PROTOCOL_HYBRID_EX ]:
raise InvalidExpectedDataException("RDPY doesn't support PROTOCOL_HYBRID_EX security Layer") raise InvalidExpectedDataException("RDPY doesn't support PROTOCOL_HYBRID_EX security Layer")
if self._selectedProtocol in [ Protocols.PROTOCOL_SSL, Protocols.PROTOCOL_HYBRID ]: #now i'm ready to receive data
log.debug("*" * 10 + " select SSL layer " + "*" * 10) self.setNextState(self.recvData)
self._transport.startTLS(ClientTLSContext())
if self._selectedProtocol == Protocols.PROTOCOL_HYBRID: if self._selectedProtocol == Protocols.PROTOCOL_RDP:
log.debug("*" * 10 + " select NLA layer " + "*" * 10) log.warning("*" * 43)
self._transport.startNLA() log.warning("*" * 10 + " RDP Security selected " + "*" * 10)
else: log.warning("*" * 43)
#now i'm ready to receive data
self.setNextState(self.recvData)
#connection is done send to presentation #connection is done send to presentation
self._presentation.connect() self._presentation.connect()
elif self._selectedProtocol == Protocols.PROTOCOL_SSL:
log.info("*" * 43)
log.info("*" * 10 + " SSL Security selected " + "*" * 10)
log.info("*" * 43)
self._transport.startTLS(ClientTLSContext())
#connection is done send to presentation
self._presentation.connect()
elif self._selectedProtocol == Protocols.PROTOCOL_HYBRID:
log.info("*" * 43)
log.info("*" + " " * 10 + "NLA Security selected" + " " * 10 + "*")
log.info("*" * 43)
self._transport.startNLA(ClientTLSContext(), lambda:self._presentation.connect())
class Server(X224Layer): class Server(X224Layer):
""" """

View File

@@ -154,10 +154,4 @@ def extractRSAKey(certificate):
def extractRSAKeyFromASN1(subjectPublicKey): def extractRSAKeyFromASN1(subjectPublicKey):
rsaKey = decoder.decode(subjectPublicKey, asn1Spec=RSAPublicKey())[0] 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'))