almost finish ntlmv2...
This commit is contained in:
98
rdpy/core/filetimes.py
Normal file
98
rdpy/core/filetimes.py
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# Copyright (c) 2009, David Buxton <david@gasmark6.com>
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are
|
||||||
|
# met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||||
|
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
"""Tools to convert between Python datetime instances and Microsoft times.
|
||||||
|
"""
|
||||||
|
from datetime import datetime, timedelta, tzinfo
|
||||||
|
from calendar import timegm
|
||||||
|
|
||||||
|
|
||||||
|
# http://support.microsoft.com/kb/167296
|
||||||
|
# How To Convert a UNIX time_t to a Win32 FILETIME or SYSTEMTIME
|
||||||
|
EPOCH_AS_FILETIME = 116444736000000000 # January 1, 1970 as MS file time
|
||||||
|
HUNDREDS_OF_NANOSECONDS = 10000000
|
||||||
|
|
||||||
|
|
||||||
|
ZERO = timedelta(0)
|
||||||
|
HOUR = timedelta(hours=1)
|
||||||
|
|
||||||
|
|
||||||
|
class UTC(tzinfo):
|
||||||
|
"""UTC"""
|
||||||
|
def utcoffset(self, dt):
|
||||||
|
return ZERO
|
||||||
|
|
||||||
|
def tzname(self, dt):
|
||||||
|
return "UTC"
|
||||||
|
|
||||||
|
def dst(self, dt):
|
||||||
|
return ZERO
|
||||||
|
|
||||||
|
|
||||||
|
utc = UTC()
|
||||||
|
|
||||||
|
|
||||||
|
def dt_to_filetime(dt):
|
||||||
|
"""Converts a datetime to Microsoft filetime format. If the object is
|
||||||
|
time zone-naive, it is forced to UTC before conversion.
|
||||||
|
|
||||||
|
>>> "%.0f" % dt_to_filetime(datetime(2009, 7, 25, 23, 0))
|
||||||
|
'128930364000000000'
|
||||||
|
|
||||||
|
>>> "%.0f" % dt_to_filetime(datetime(1970, 1, 1, 0, 0, tzinfo=utc))
|
||||||
|
'116444736000000000'
|
||||||
|
|
||||||
|
>>> "%.0f" % dt_to_filetime(datetime(1970, 1, 1, 0, 0))
|
||||||
|
'116444736000000000'
|
||||||
|
|
||||||
|
>>> dt_to_filetime(datetime(2009, 7, 25, 23, 0, 0, 100))
|
||||||
|
128930364000001000
|
||||||
|
"""
|
||||||
|
if (dt.tzinfo is None) or (dt.tzinfo.utcoffset(dt) is None):
|
||||||
|
dt = dt.replace(tzinfo=utc)
|
||||||
|
ft = EPOCH_AS_FILETIME + (timegm(dt.timetuple()) * HUNDREDS_OF_NANOSECONDS)
|
||||||
|
return ft + (dt.microsecond * 10)
|
||||||
|
|
||||||
|
|
||||||
|
def filetime_to_dt(ft):
|
||||||
|
"""Converts a Microsoft filetime number to a Python datetime. The new
|
||||||
|
datetime object is time zone-naive but is equivalent to tzinfo=utc.
|
||||||
|
|
||||||
|
>>> filetime_to_dt(116444736000000000)
|
||||||
|
datetime.datetime(1970, 1, 1, 0, 0)
|
||||||
|
|
||||||
|
>>> filetime_to_dt(128930364000000000)
|
||||||
|
datetime.datetime(2009, 7, 25, 23, 0)
|
||||||
|
|
||||||
|
>>> filetime_to_dt(128930364000001000)
|
||||||
|
datetime.datetime(2009, 7, 25, 23, 0, 0, 100)
|
||||||
|
"""
|
||||||
|
# Get seconds and remainder in terms of Unix epoch
|
||||||
|
(s, ns100) = divmod(ft - EPOCH_AS_FILETIME, HUNDREDS_OF_NANOSECONDS)
|
||||||
|
# Convert to datetime object
|
||||||
|
dt = datetime.utcfromtimestamp(s)
|
||||||
|
# Add remainder in as microseconds. Python 3.2 requires an integer
|
||||||
|
dt = dt.replace(microsecond=(ns100 // 10))
|
||||||
|
return dt
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ 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):
|
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)}
|
||||||
@@ -118,6 +118,9 @@ def encodeDERTRequest(negoTypes):
|
|||||||
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)
|
request.setComponentByName("negoTokens", negoData)
|
||||||
|
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 String(encoder.encode(request))
|
||||||
|
|
||||||
def decodeDERTRequest(s):
|
def decodeDERTRequest(s):
|
||||||
|
|||||||
@@ -22,11 +22,13 @@
|
|||||||
@see: https://msdn.microsoft.com/en-us/library/cc236621.aspx
|
@see: https://msdn.microsoft.com/en-us/library/cc236621.aspx
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import hashlib, hmac
|
import hashlib, hmac, struct, datetime
|
||||||
|
import sspi
|
||||||
import rdpy.security.pyDes as pyDes
|
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
|
from rdpy.core.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt24Le, UInt32Le, sizeof, Stream
|
||||||
|
from rdpy.core import filetimes
|
||||||
|
|
||||||
class MajorVersion(object):
|
class MajorVersion(object):
|
||||||
"""
|
"""
|
||||||
@@ -98,6 +100,17 @@ class Version(CompositeType):
|
|||||||
self.ProductBuild = UInt16Le(6002)
|
self.ProductBuild = UInt16Le(6002)
|
||||||
self.Reserved = UInt24Le()
|
self.Reserved = UInt24Le()
|
||||||
self.NTLMRevisionCurrent = UInt8(NTLMRevision.NTLMSSP_REVISION_W2K3)
|
self.NTLMRevisionCurrent = UInt8(NTLMRevision.NTLMSSP_REVISION_W2K3)
|
||||||
|
|
||||||
|
class MessageSignatureEx(CompositeType):
|
||||||
|
"""
|
||||||
|
@summary: Signature for message
|
||||||
|
@see: https://msdn.microsoft.com/en-us/library/cc422952.aspx
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
CompositeType.__init__(self)
|
||||||
|
self.Version = UInt32Le(0x00000001, constant = True)
|
||||||
|
self.Checksum = String(readLen = CallableValue(16))
|
||||||
|
self.SeqNum = UInt32Le()
|
||||||
|
|
||||||
class NegotiateMessage(CompositeType):
|
class NegotiateMessage(CompositeType):
|
||||||
"""
|
"""
|
||||||
@@ -109,16 +122,7 @@ class NegotiateMessage(CompositeType):
|
|||||||
self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True)
|
self.Signature = String("NTLMSSP\x00", readLen = CallableValue(8), constant = True)
|
||||||
self.MessageType = UInt32Le(0x00000001, constant = True)
|
self.MessageType = UInt32Le(0x00000001, constant = True)
|
||||||
|
|
||||||
self.NegotiateFlags = UInt32Le(Negotiate.NTLMSSP_NEGOTIATE_KEY_EXCH |
|
self.NegotiateFlags = UInt32Le()
|
||||||
Negotiate.NTLMSSP_NEGOTIATE_128 |
|
|
||||||
Negotiate.NTLMSSP_NEGOTIATE_56 |
|
|
||||||
Negotiate.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY |
|
|
||||||
Negotiate.NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
|
|
||||||
Negotiate.NTLMSSP_NEGOTIATE_NTLM |
|
|
||||||
Negotiate.NTLMSSP_REQUEST_TARGET |
|
|
||||||
Negotiate.NTLMSSP_NEGOTIATE_TARGET_INFO |
|
|
||||||
Negotiate.NTLMSSP_NEGOTIATE_VERSION |
|
|
||||||
Negotiate.NTLMSSP_NEGOTIATE_UNICODE)
|
|
||||||
|
|
||||||
self.DomainNameLen = UInt16Le()
|
self.DomainNameLen = UInt16Le()
|
||||||
self.DomainNameMaxLen = UInt16Le(lambda:self.DomainNameLen.value)
|
self.DomainNameMaxLen = UInt16Le(lambda:self.DomainNameLen.value)
|
||||||
@@ -219,6 +223,46 @@ 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):
|
||||||
|
"""
|
||||||
|
@summary: Create an Authenticate Message
|
||||||
|
@param domain: {str} domain microsoft
|
||||||
|
@param user: {str} user microsoft
|
||||||
|
@param NtChallengeResponse: {str} Challenge response
|
||||||
|
@param LmChallengeResponse: {str} domain microsoft
|
||||||
|
@param EncryptedRandomSessionKey: {str} EncryptedRandomSessionKey
|
||||||
|
"""
|
||||||
|
message = AuthenticateMessage()
|
||||||
|
#fill message
|
||||||
|
offset = sizeof(message)
|
||||||
|
|
||||||
|
message.DomainNameLen.value = len(domain)
|
||||||
|
message.DomainNameBufferOffset.value = offset
|
||||||
|
message.Payload.value += domain
|
||||||
|
offset += len(domain)
|
||||||
|
|
||||||
|
message.UserNameLen.value = len(user)
|
||||||
|
message.UserNameBufferOffset.value = offset
|
||||||
|
message.Payload.value += user
|
||||||
|
offset += len(user)
|
||||||
|
|
||||||
|
message.LmChallengeResponseLen.value = len(LmChallengeResponse)
|
||||||
|
message.LmChallengeResponseBufferOffset.value = offset
|
||||||
|
message.Payload.value += LmChallengeResponse
|
||||||
|
offset += len(LmChallengeResponse)
|
||||||
|
|
||||||
|
message.NtChallengeResponseLen.value = len(NtChallengeResponse)
|
||||||
|
message.NtChallengeResponseBufferOffset.value = offset
|
||||||
|
message.Payload.value += NtChallengeResponse
|
||||||
|
offset += len(NtChallengeResponse)
|
||||||
|
|
||||||
|
message.EncryptedRandomSessionLen.value = len(EncryptedRandomSessionKey)
|
||||||
|
message.EncryptedRandomSessionBufferOffset.value = offset
|
||||||
|
message.Payload.value += EncryptedRandomSessionKey
|
||||||
|
offset += len(EncryptedRandomSessionKey)
|
||||||
|
|
||||||
|
return message
|
||||||
|
|
||||||
def expandDesKey(key):
|
def expandDesKey(key):
|
||||||
"""
|
"""
|
||||||
@summary: Expand the key from a 7-byte password key into a 8-byte DES key
|
@summary: Expand the key from a 7-byte password key into a 8-byte DES key
|
||||||
@@ -233,6 +277,13 @@ def expandDesKey(key):
|
|||||||
s = s + chr((ord(key[6]) & 0x7f) << 1)
|
s = s + chr((ord(key[6]) & 0x7f) << 1)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
def CurrentFileTimes():
|
||||||
|
"""
|
||||||
|
@summary: Current File times in 64 bits
|
||||||
|
@return : {str[8]}
|
||||||
|
"""
|
||||||
|
return struct.pack("Q", filetimes.dt_to_filetime(datetime.datetime.now()))
|
||||||
|
|
||||||
def DES(key, data):
|
def DES(key, data):
|
||||||
"""
|
"""
|
||||||
@summary: DES use in microsoft specification
|
@summary: DES use in microsoft specification
|
||||||
@@ -289,137 +340,207 @@ def RC4K(key, plaintext):
|
|||||||
"""
|
"""
|
||||||
return rc4.crypt(rc4.RC4Key(key), plaintext)
|
return rc4.crypt(rc4.RC4Key(key), plaintext)
|
||||||
|
|
||||||
def KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge):
|
def KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge):
|
||||||
"""
|
"""
|
||||||
@summary: Key eXchange Key
|
@summary: Key eXchange Key for NTLMv2
|
||||||
@param SessionBaseKey: {str} computed by NTLMv1Anthentication or NTLMv2Authenticate function
|
@param SessionBaseKey: {str} computed by NTLMv1Anthentication or NTLMv2Authenticate function
|
||||||
@param LmChallengeResponse : {str} computed by NTLMv1Anthentication or NTLMv2Authenticate function
|
@param LmChallengeResponse : {str} computed by NTLMv1Anthentication or NTLMv2Authenticate function
|
||||||
@param ServerChallenge : {str} Server chanllenge come from ChallengeMessage
|
@param ServerChallenge : {str} Server chanllenge come from ChallengeMessage
|
||||||
@see: https://msdn.microsoft.com/en-us/library/cc236710.aspx
|
@see: https://msdn.microsoft.com/en-us/library/cc236710.aspx
|
||||||
"""
|
"""
|
||||||
return HMAC_MD5(SessionBaseKey, ServerChallenge + LmChallengeResponse[:8])
|
return SessionBaseKey
|
||||||
|
|
||||||
def SEALKEY(ExportedSessionKey):
|
def SEALKEY(ExportedSessionKey, client):
|
||||||
return MD5(ExportedSessionKey + "session key to client-to-server sealing key magic constant")
|
if client:
|
||||||
|
return MD5(ExportedSessionKey + "session key to client-to-server sealing key magic constant\0")
|
||||||
def SIGNKEY(ExportedSessionKey):
|
|
||||||
return MD5(ExportedSessionKey + "session key to client-to-server signing key magic constant")
|
|
||||||
|
|
||||||
|
|
||||||
def NTOWFv1(Passwd, User, UserDom):
|
|
||||||
"""
|
|
||||||
@see: https://msdn.microsoft.com/en-us/library/cc236699.aspx
|
|
||||||
"""
|
|
||||||
return MD4(UNICODE(Passwd))
|
|
||||||
|
|
||||||
def LMOWFv1(Passwd, User, UserDom):
|
|
||||||
"""
|
|
||||||
@see: https://msdn.microsoft.com/en-us/library/cc236699.aspx
|
|
||||||
"""
|
|
||||||
password = (Passwd.upper() + "\x00" * 14)[:14]
|
|
||||||
return DES(password[:7], "KGS!@#$%") + DES(password[7:], "KGS!@#$%")
|
|
||||||
|
|
||||||
def NTLMv1Anthentication(negFlag, domain, user, password, serverChallenge, serverName):
|
|
||||||
"""
|
|
||||||
@summary: Not tested yet
|
|
||||||
@param negFlag: {int} use another non secure way
|
|
||||||
@param domain: {str} microsoft domain
|
|
||||||
@param user: {str} username
|
|
||||||
@param password: {str} password
|
|
||||||
@param serverChallenge: {str[8]} server challenge
|
|
||||||
"""
|
|
||||||
ResponseKeyNT = NTOWFv1(password, user, domain)
|
|
||||||
ResponseKeyLM = LMOWFv1(password, user, domain)
|
|
||||||
|
|
||||||
if negFlag & Negotiate.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
|
|
||||||
ClientChallenge = random(64)
|
|
||||||
NtChallengeResponse = DESL(ResponseKeyNT, MD5(serverChallenge + ClientChallenge))
|
|
||||||
LmChallengeResponse = ClientChallenge + Z(16)
|
|
||||||
else:
|
else:
|
||||||
NtChallengeResponse = DESL(ResponseKeyNT, serverChallenge)
|
return MD5(ExportedSessionKey + "session key to server-to-client sealing key magic constant\0")
|
||||||
LmChallengeResponse = DESL(ResponseKeyLM, serverChallenge)
|
|
||||||
|
def SIGNKEY(ExportedSessionKey, client):
|
||||||
SessionBaseKey = MD4(ResponseKeyNT)
|
if client:
|
||||||
|
return MD5(ExportedSessionKey + "session key to client-to-server signing key magic constant\0")
|
||||||
return NtChallengeResponse, LmChallengeResponse, SessionBaseKey
|
else:
|
||||||
|
return MD5(ExportedSessionKey + "session key to server-to-client signing key magic constant\0")
|
||||||
|
|
||||||
def HMAC_MD5(key, data):
|
def HMAC_MD5(key, data):
|
||||||
|
"""
|
||||||
|
@summary: classic HMAC algorithm with MD5 sum
|
||||||
|
@param key: {str} key
|
||||||
|
@param data: {str} data
|
||||||
|
"""
|
||||||
return hmac.new(key, data, hashlib.md5).digest()
|
return hmac.new(key, data, hashlib.md5).digest()
|
||||||
|
|
||||||
def NTOWFv2(Passwd, User, UserDom):
|
def NTOWFv2(Passwd, User, UserDom):
|
||||||
|
"""
|
||||||
|
@summary: Version 2 of NTLM hash function
|
||||||
|
@param Passwd: {str} Password
|
||||||
|
@param User: {str} Username
|
||||||
|
@param UserDom: {str} microsoft domain
|
||||||
|
@see: https://msdn.microsoft.com/en-us/library/cc236700.aspx
|
||||||
|
"""
|
||||||
return HMAC_MD5(MD4(UNICODE(Passwd)), UNICODE(User.upper() + UserDom))
|
return HMAC_MD5(MD4(UNICODE(Passwd)), UNICODE(User.upper() + UserDom))
|
||||||
|
|
||||||
def LMOWFv2(Passwd, User, UserDom):
|
def LMOWFv2(Passwd, User, UserDom):
|
||||||
return NTOWFv2(Passwd, User, UserDom)
|
|
||||||
|
|
||||||
def NTLMv2Authenticate(negFlag, domain, user, password, serverChallenge, serverName, Time = "\x00" * 8, ClientChallenge = None):
|
|
||||||
"""
|
"""
|
||||||
@summary: process NTLMv2 Authenticate hash
|
@summary: Same as NTOWFv2
|
||||||
|
@param Passwd: {str} Password
|
||||||
|
@param User: {str} Username
|
||||||
|
@param UserDom: {str} microsoft domain
|
||||||
|
@see: https://msdn.microsoft.com/en-us/library/cc236700.aspx
|
||||||
|
"""
|
||||||
|
return NTOWFv2(Passwd, User, UserDom)
|
||||||
|
|
||||||
|
def ComputeResponsev2(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChallenge, Time, ServerName):
|
||||||
|
"""
|
||||||
|
@summary: process NTLMv2 Authenticate hash
|
||||||
|
@param NegFlg: {int} Negotiation flags come from challenge message
|
||||||
@see: https://msdn.microsoft.com/en-us/library/cc236700.aspx
|
@see: https://msdn.microsoft.com/en-us/library/cc236700.aspx
|
||||||
"""
|
"""
|
||||||
ResponseKeyNT = NTOWFv2(password, user, domain)
|
|
||||||
ResponseKeyLM = LMOWFv2(password, user, domain)
|
|
||||||
|
|
||||||
Responserversion = "\x01"
|
Responserversion = "\x01"
|
||||||
HiResponserversion = "\x01"
|
HiResponserversion = "\x01"
|
||||||
#Time = "\x00" * 8
|
|
||||||
if ClientChallenge is None:
|
|
||||||
ClientChallenge = random(64)
|
|
||||||
|
|
||||||
temp = Responserversion + HiResponserversion + Z(6) + Time + ClientChallenge + Z(4) + serverName + Z(4)
|
temp = Responserversion + HiResponserversion + Z(6) + Time + ClientChallenge + Z(4) + ServerName + Z(4)
|
||||||
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
|
||||||
|
|
||||||
SessionBaseKey = HMAC_MD5(ResponseKeyNT, NTProofStr)
|
SessionBaseKey = HMAC_MD5(ResponseKeyNT, NTProofStr)
|
||||||
|
|
||||||
return NtChallengeResponse, LmChallengeResponse, SessionBaseKey
|
return NtChallengeResponse, LmChallengeResponse, SessionBaseKey
|
||||||
|
|
||||||
def createAuthenticationMessage(method, challengeResponse, domain, user, password):
|
def MAC(handle, SigningKey, SeqNum, Message):
|
||||||
#extract target info
|
"""
|
||||||
NtChallengeResponse, LmChallengeResponse, SessionBaseKey = method(challengeResponse.NegotiateFlags.value,
|
@summary: generate signature for application message
|
||||||
domain, user, password,
|
@param handle: {rc4.RC4Key} handle on crypt
|
||||||
challengeResponse.ServerChallenge.value,
|
@param SigningKey: {str} Signing key
|
||||||
challengeResponse.getTargetInfo())
|
@param SeqNum: {int} Sequence number
|
||||||
|
@param Message: Message to sign
|
||||||
|
@see: https://msdn.microsoft.com/en-us/library/cc422952.aspx
|
||||||
|
"""
|
||||||
|
signature = MessageSignatureEx()
|
||||||
|
signature.SeqNum.value = SeqNum
|
||||||
|
|
||||||
if challengeResponse.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_UNICODE:
|
#write the SeqNum
|
||||||
domain, user = UNICODE(domain), UNICODE(user)
|
s = Stream()
|
||||||
|
s.writeType(signature.SeqNum)
|
||||||
|
|
||||||
message = AuthenticateMessage()
|
signature.Checksum.value = rc4.crypt(handle, HMAC_MD5(SigningKey, s.getvalue() + Message)[:8])
|
||||||
#fill message
|
|
||||||
offset = sizeof(message)
|
|
||||||
|
|
||||||
message.NegotiateFlags.value = challengeResponse.NegotiateFlags.value
|
return signature
|
||||||
|
|
||||||
message.LmChallengeResponseLen.value = len(LmChallengeResponse)
|
class NTLMv2(sspi.IAuthenticationProtocol):
|
||||||
message.LmChallengeResponseBufferOffset.value = offset
|
"""
|
||||||
message.Payload.value += LmChallengeResponse
|
@summary: Handle NTLMv2 Authentication
|
||||||
offset += len(LmChallengeResponse)
|
"""
|
||||||
|
def __init__(self, domain, user, password):
|
||||||
|
self._domain = domain
|
||||||
|
self._user = user
|
||||||
|
#https://msdn.microsoft.com/en-us/library/cc236700.aspx
|
||||||
|
self._ResponseKeyNT = NTOWFv2(password, user, domain)
|
||||||
|
self._ResponseKeyLM = LMOWFv2(password, user, domain)
|
||||||
|
|
||||||
message.NtChallengeResponseLen.value = len(NtChallengeResponse)
|
def getNegotiateMessage(self):
|
||||||
message.NtChallengeResponseBufferOffset.value = offset
|
"""
|
||||||
message.Payload.value += NtChallengeResponse
|
@summary: generate first handshake messgae
|
||||||
offset += len(NtChallengeResponse)
|
"""
|
||||||
|
message = NegotiateMessage()
|
||||||
|
message.NegotiateFlags.value = (Negotiate.NTLMSSP_NEGOTIATE_KEY_EXCH |
|
||||||
|
Negotiate.NTLMSSP_NEGOTIATE_128 |
|
||||||
|
Negotiate.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY |
|
||||||
|
Negotiate.NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
|
||||||
|
Negotiate.NTLMSSP_NEGOTIATE_NTLM |
|
||||||
|
Negotiate.NTLMSSP_NEGOTIATE_SEAL |
|
||||||
|
Negotiate.NTLMSSP_NEGOTIATE_SIGN |
|
||||||
|
Negotiate.NTLMSSP_REQUEST_TARGET |
|
||||||
|
Negotiate.NTLMSSP_NEGOTIATE_UNICODE)
|
||||||
|
return message
|
||||||
|
|
||||||
message.DomainNameLen.value = len(domain)
|
def getAuthenticateMessage(self, s):
|
||||||
message.DomainNameBufferOffset.value = offset
|
"""
|
||||||
message.Payload.value += domain
|
@summary: Client last handshake message
|
||||||
offset += len(domain)
|
@param s: {Stream} challenge message stream
|
||||||
|
@return: {(AuthenticateMessage, NTLMv2SecurityInterface)} Last handshake message and security interface use to encrypt
|
||||||
message.UserNameLen.value = len(user)
|
@see: https://msdn.microsoft.com/en-us/library/cc236676.aspx
|
||||||
message.UserNameBufferOffset.value = offset
|
"""
|
||||||
message.Payload.value += user
|
challenge = ChallengeMessage()
|
||||||
offset += len(user)
|
s.readType(challenge)
|
||||||
|
|
||||||
message.EncryptedRandomSessionLen.value = len(SessionBaseKey)
|
ServerChallenge = challenge.ServerChallenge.value
|
||||||
message.EncryptedRandomSessionBufferOffset.value = offset
|
ClientChallenge = random(64)
|
||||||
message.Payload.value += SessionBaseKey
|
Timestamp = CurrentFileTimes()
|
||||||
offset += len(SessionBaseKey)
|
ServerName = challenge.getTargetInfo()
|
||||||
|
|
||||||
return message
|
NtChallengeResponse, LmChallengeResponse, SessionBaseKey = ComputeResponsev2(self._ResponseKeyNT, self._ResponseKeyLM, ServerChallenge, ClientChallenge, Timestamp, ServerName)
|
||||||
|
KeyExchangeKey = KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge)
|
||||||
|
ExportedSessionKey = random(128)
|
||||||
|
EncryptedRandomSessionKey = RC4K(KeyExchangeKey, ExportedSessionKey)
|
||||||
|
|
||||||
|
domain, user = self._domain, self._user
|
||||||
|
if challenge.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_UNICODE:
|
||||||
|
domain, user = UNICODE(domain), UNICODE(user)
|
||||||
|
message = createAuthenticationMessage(domain, user, NtChallengeResponse, LmChallengeResponse, EncryptedRandomSessionKey)
|
||||||
|
|
||||||
|
ClientSigningKey = SIGNKEY(ExportedSessionKey, True)
|
||||||
|
ServerSigningKey = SIGNKEY(ExportedSessionKey, False)
|
||||||
|
ClientSealingKey = SEALKEY(ExportedSessionKey, True)
|
||||||
|
ServerSealingKey = SEALKEY(ExportedSessionKey, False)
|
||||||
|
|
||||||
|
interface = NTLMv2SecurityInterface(rc4.RC4Key(ClientSealingKey), rc4.RC4Key(ServerSealingKey), ClientSigningKey, ServerSigningKey)
|
||||||
|
|
||||||
|
return message, interface
|
||||||
|
|
||||||
|
|
||||||
|
class NTLMv2SecurityInterface(sspi.IGenericSecurityService):
|
||||||
|
"""
|
||||||
|
@summary: Generic Security Service for NTLM session
|
||||||
|
"""
|
||||||
|
def __init__(self, encryptHandle, decryptHandle, signingKey, verifyKey):
|
||||||
|
"""
|
||||||
|
@param encryptHandle: {rc4.RC4Key} rc4 keystream for encrypt phase
|
||||||
|
@param decryptHandle: {rc4.RC4Key} rc4 keystream for decrypt phase
|
||||||
|
@param signingKey: {str} signingKey
|
||||||
|
@param verifyKey: {str} verifyKey
|
||||||
|
"""
|
||||||
|
self._encryptHandle = encryptHandle
|
||||||
|
self._decryptHandle = decryptHandle
|
||||||
|
self._signingKey = signingKey
|
||||||
|
self._verifyKey = verifyKey
|
||||||
|
self._seqNum = 0
|
||||||
|
|
||||||
|
def GSS_WrapEx(self, data):
|
||||||
|
"""
|
||||||
|
@summary: Encrypt function for NTLMv2 security service
|
||||||
|
@param data: data to encrypt
|
||||||
|
@return: {str} encrypted data
|
||||||
|
"""
|
||||||
|
encryptedData = rc4.crypt(self._encryptHandle, data)
|
||||||
|
signature = MAC(self._encryptHandle, self._signingKey, self._seqNum, data)
|
||||||
|
self._seqNum += 1
|
||||||
|
s = Stream()
|
||||||
|
s.writeType(signature)
|
||||||
|
return s.getvalue() + encryptedData
|
||||||
|
|
||||||
cssp_1 = [
|
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,
|
0x30, 0x2f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0xa1,
|
||||||
0x28, 0x30, 0x26, 0x30, 0x24, 0xa0, 0x22, 0x04,
|
0x28, 0x30, 0x26, 0x30, 0x24, 0xa0, 0x22, 0x04,
|
||||||
0x20, 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50,
|
0x20, 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50,
|
||||||
@@ -427,15 +548,15 @@ cssp_1 = [
|
|||||||
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00 ]
|
0x00 ]
|
||||||
cssp_2 = [
|
peer1_0 = [
|
||||||
0x30, 0x82, 0x01, 0x09, 0xa0, 0x03, 0x02, 0x01,
|
0x30, 0x82, 0x01, 0x09, 0xa0, 0x03, 0x02, 0x01,
|
||||||
0x02, 0xa1, 0x82, 0x01, 0x00, 0x30, 0x81, 0xfd,
|
0x02, 0xa1, 0x82, 0x01, 0x00, 0x30, 0x81, 0xfd,
|
||||||
0x30, 0x81, 0xfa, 0xa0, 0x81, 0xf7, 0x04, 0x81,
|
0x30, 0x81, 0xfa, 0xa0, 0x81, 0xf7, 0x04, 0x81,
|
||||||
0xf4, 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50,
|
0xf4, 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50,
|
||||||
0x00, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e,
|
0x00, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e,
|
||||||
0x00, 0x38, 0x00, 0x00, 0x00, 0x35, 0x82, 0x89,
|
0x00, 0x38, 0x00, 0x00, 0x00, 0x35, 0x82, 0x89,
|
||||||
0x62, 0x73, 0xc7, 0x43, 0xa9, 0xe7, 0xfc, 0xbb,
|
0x62, 0x0a, 0xee, 0xd7, 0xc3, 0xeb, 0x8e, 0x34,
|
||||||
0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0xae, 0x00, 0xae, 0x00, 0x46, 0x00, 0x00,
|
0x00, 0xae, 0x00, 0xae, 0x00, 0x46, 0x00, 0x00,
|
||||||
0x00, 0x06, 0x01, 0xb1, 0x1d, 0x00, 0x00, 0x00,
|
0x00, 0x06, 0x01, 0xb1, 0x1d, 0x00, 0x00, 0x00,
|
||||||
0x0f, 0x53, 0x00, 0x49, 0x00, 0x52, 0x00, 0x41,
|
0x0f, 0x53, 0x00, 0x49, 0x00, 0x52, 0x00, 0x41,
|
||||||
@@ -460,86 +581,84 @@ cssp_2 = [
|
|||||||
0x00, 0x61, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6c,
|
0x00, 0x61, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6c,
|
||||||
0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63,
|
0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63,
|
||||||
0x00, 0x61, 0x00, 0x6c, 0x00, 0x07, 0x00, 0x08,
|
0x00, 0x61, 0x00, 0x6c, 0x00, 0x07, 0x00, 0x08,
|
||||||
0x00, 0x56, 0x93, 0x34, 0x32, 0xc7, 0x55, 0xd0,
|
0x00, 0xe5, 0x40, 0x3c, 0xa6, 0x68, 0x57, 0xd0,
|
||||||
0x01, 0x00, 0x00, 0x00, 0x00 ]
|
0x01, 0x00, 0x00, 0x00, 0x00 ]
|
||||||
cssp_3 = [
|
peer0_1 = [
|
||||||
0x30, 0x82, 0x02, 0x0f, 0xa0, 0x03, 0x02, 0x01,
|
0x30, 0x82, 0x02, 0x21, 0xa0, 0x03, 0x02, 0x01,
|
||||||
0x02, 0xa1, 0x82, 0x01, 0x62, 0x30, 0x82, 0x01,
|
0x02, 0xa1, 0x82, 0x01, 0x76, 0x30, 0x82, 0x01,
|
||||||
0x5e, 0x30, 0x82, 0x01, 0x5a, 0xa0, 0x82, 0x01,
|
0x72, 0x30, 0x82, 0x01, 0x6e, 0xa0, 0x82, 0x01,
|
||||||
0x56, 0x04, 0x82, 0x01, 0x52, 0x4e, 0x54, 0x4c,
|
0x6a, 0x04, 0x82, 0x01, 0x66, 0x4e, 0x54, 0x4c,
|
||||||
0x4d, 0x53, 0x53, 0x50, 0x00, 0x03, 0x00, 0x00,
|
0x4d, 0x53, 0x53, 0x50, 0x00, 0x03, 0x00, 0x00,
|
||||||
0x00, 0x18, 0x00, 0x18, 0x00, 0x50, 0x00, 0x00,
|
0x00, 0x18, 0x00, 0x18, 0x00, 0x64, 0x00, 0x00,
|
||||||
0x00, 0xda, 0x00, 0xda, 0x00, 0x68, 0x00, 0x00,
|
0x00, 0xda, 0x00, 0xda, 0x00, 0x7c, 0x00, 0x00,
|
||||||
0x00, 0x08, 0x00, 0x08, 0x00, 0x40, 0x00, 0x00,
|
0x00, 0x0e, 0x00, 0x0e, 0x00, 0x40, 0x00, 0x00,
|
||||||
0x00, 0x08, 0x00, 0x08, 0x00, 0x48, 0x00, 0x00,
|
0x00, 0x16, 0x00, 0x16, 0x00, 0x4e, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x10, 0x00, 0x10, 0x00, 0x42, 0x01, 0x00,
|
0x00, 0x10, 0x00, 0x10, 0x00, 0x56, 0x01, 0x00,
|
||||||
0x00, 0x35, 0x82, 0x08, 0x60, 0x63, 0x00, 0x6f,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x69,
|
||||||
0x00, 0x63, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x6f,
|
0x00, 0x72, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65,
|
||||||
0x00, 0x74, 0x00, 0x6f, 0x00, 0x1a, 0x8a, 0xc2,
|
0x00, 0x6c, 0x00, 0x73, 0x00, 0x70, 0x00, 0x65,
|
||||||
0xbc, 0x64, 0xda, 0xc0, 0x28, 0x9b, 0xa8, 0x14,
|
0x00, 0x79, 0x00, 0x72, 0x00, 0x65, 0x00, 0x66,
|
||||||
0x08, 0x51, 0x6d, 0xd6, 0xb8, 0x29, 0x09, 0xd2,
|
0x00, 0x69, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65,
|
||||||
0x99, 0x19, 0x33, 0x70, 0x9e, 0x51, 0xa0, 0x6e,
|
0x00, 0x8a, 0x01, 0x34, 0xd8, 0x57, 0x6e, 0x14,
|
||||||
0xc5, 0x39, 0x47, 0xf3, 0x9e, 0x96, 0x6a, 0xc3,
|
0x2b, 0xda, 0xc6, 0x91, 0x02, 0x49, 0xbb, 0xc4,
|
||||||
0xfc, 0xb2, 0xeb, 0xc7, 0xe0, 0x01, 0x01, 0x00,
|
0x00, 0x19, 0x6c, 0x60, 0x26, 0x16, 0xdb, 0x37,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x08,
|
0x8f, 0x98, 0xe1, 0x04, 0xf8, 0x36, 0x6a, 0x96,
|
||||||
0x32, 0xc7, 0x55, 0xd0, 0x01, 0x29, 0x09, 0xd2,
|
0xa2, 0xa1, 0x9a, 0xf9, 0x5f, 0x1f, 0x04, 0x63,
|
||||||
0x99, 0x19, 0x33, 0x70, 0x9e, 0x00, 0x00, 0x00,
|
0x69, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x02, 0x00, 0x0e, 0x00, 0x53, 0x00, 0x49,
|
0x00, 0x38, 0x8d, 0x10, 0x08, 0x71, 0x57, 0xd0,
|
||||||
0x00, 0x52, 0x00, 0x41, 0x00, 0x44, 0x00, 0x45,
|
0x01, 0x19, 0x6c, 0x60, 0x26, 0x16, 0xdb, 0x37,
|
||||||
0x00, 0x4c, 0x00, 0x01, 0x00, 0x16, 0x00, 0x57,
|
0x8f, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x0e,
|
||||||
0x00, 0x41, 0x00, 0x56, 0x00, 0x2d, 0x00, 0x47,
|
0x00, 0x53, 0x00, 0x49, 0x00, 0x52, 0x00, 0x41,
|
||||||
0x00, 0x4c, 0x00, 0x57, 0x00, 0x2d, 0x00, 0x30,
|
0x00, 0x44, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x01,
|
||||||
0x00, 0x30, 0x00, 0x39, 0x00, 0x04, 0x00, 0x1a,
|
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, 0x53, 0x00, 0x69, 0x00, 0x72, 0x00, 0x61,
|
||||||
0x00, 0x64, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x2e,
|
0x00, 0x64, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x2e,
|
||||||
0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x61,
|
0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x61,
|
||||||
0x00, 0x6c, 0x00, 0x03, 0x00, 0x32, 0x00, 0x77,
|
0x00, 0x6c, 0x00, 0x07, 0x00, 0x08, 0x00, 0xe5,
|
||||||
0x00, 0x61, 0x00, 0x76, 0x00, 0x2d, 0x00, 0x67,
|
0x40, 0x3c, 0xa6, 0x68, 0x57, 0xd0, 0x01, 0x00,
|
||||||
0x00, 0x6c, 0x00, 0x77, 0x00, 0x2d, 0x00, 0x30,
|
0x00, 0x00, 0x00, 0x59, 0x49, 0x84, 0x63, 0xf2,
|
||||||
0x00, 0x30, 0x00, 0x39, 0x00, 0x2e, 0x00, 0x53,
|
0x84, 0x53, 0x18, 0xea, 0xa4, 0xc3, 0xb6, 0x97,
|
||||||
0x00, 0x69, 0x00, 0x72, 0x00, 0x61, 0x00, 0x64,
|
0x0d, 0x3e, 0x38, 0xa3, 0x81, 0x9f, 0x04, 0x81,
|
||||||
0x00, 0x65, 0x00, 0x6c, 0x00, 0x2e, 0x00, 0x6c,
|
0x9c, 0x01, 0x00, 0x00, 0x00, 0xc9, 0x56, 0x22,
|
||||||
0x00, 0x6f, 0x00, 0x63, 0x00, 0x61, 0x00, 0x6c,
|
0x84, 0x7d, 0xba, 0xa2, 0xe6, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x05, 0x00, 0x1a, 0x00, 0x53, 0x00, 0x69,
|
0x00, 0x1c, 0x6d, 0x39, 0xe1, 0x5a, 0x31, 0x5d,
|
||||||
0x00, 0x72, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65,
|
0xf5, 0x01, 0xa6, 0xea, 0x4b, 0xaf, 0x83, 0x13,
|
||||||
0x00, 0x6c, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f,
|
0xdc, 0x8a, 0x45, 0xb3, 0x76, 0xc6, 0x3d, 0xbf,
|
||||||
0x00, 0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x07,
|
0x73, 0x4c, 0x93, 0xe6, 0x75, 0x8b, 0x42, 0x21,
|
||||||
0x00, 0x08, 0x00, 0x56, 0x93, 0x34, 0x32, 0xc7,
|
0xea, 0xe6, 0x0c, 0xfa, 0x3c, 0xd0, 0x7c, 0x8d,
|
||||||
0x55, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xbf,
|
0xd6, 0x2a, 0x97, 0x7a, 0x49, 0xb5, 0x7d, 0xeb,
|
||||||
0xec, 0xf5, 0xf6, 0x69, 0x01, 0x3a, 0xef, 0x5b,
|
0xc2, 0x94, 0xc0, 0x84, 0xb4, 0xef, 0x7f, 0x1e,
|
||||||
0xd0, 0xab, 0xfe, 0x3f, 0xdf, 0x75, 0x30, 0xa3,
|
0xa3, 0xa3, 0x3f, 0x61, 0x7c, 0x1c, 0xd9, 0x82,
|
||||||
0x82, 0x00, 0xa0, 0x04, 0x82, 0x00, 0x9c, 0x01,
|
0xc6, 0x0b, 0x6c, 0x85, 0x15, 0xb0, 0x47, 0x25,
|
||||||
0x00, 0x00, 0x00, 0xc4, 0x0e, 0xcd, 0x96, 0x8f,
|
0xe9, 0x0a, 0x88, 0x58, 0x3c, 0x6d, 0x8e, 0x60,
|
||||||
0x67, 0xc0, 0xdd, 0x00, 0x00, 0x00, 0x00, 0xcf,
|
0x2a, 0xbc, 0x04, 0x57, 0x7f, 0x5b, 0x03, 0x7c,
|
||||||
0x88, 0xbd, 0x30, 0xe2, 0x53, 0x4a, 0x4b, 0x8d,
|
0x7a, 0x8f, 0x1b, 0x7b, 0xe3, 0x67, 0xb6, 0x02,
|
||||||
0x49, 0xd4, 0xe9, 0xa3, 0x63, 0x1f, 0xe8, 0x19,
|
0xa4, 0xc0, 0xdd, 0x9e, 0x97, 0x4c, 0xd8, 0x86,
|
||||||
0x59, 0xe6, 0x88, 0x96, 0xaa, 0x50, 0x35, 0x81,
|
0x5c, 0x9a, 0x45, 0x0d, 0x85, 0x4b, 0x46, 0x87,
|
||||||
0x02, 0x9a, 0x91, 0x25, 0x8b, 0x1c, 0x0f, 0x8f,
|
0xde, 0xcf, 0x31, 0x72, 0xe3, 0xd7, 0x5d, 0x0b,
|
||||||
0xc6, 0x91, 0x44, 0x55, 0x5f, 0x4e, 0xd9, 0x1b,
|
0x67, 0x1b, 0xa1, 0xde, 0x24, 0x87, 0xdf, 0xd9,
|
||||||
0xc3, 0xae, 0x94, 0xde, 0x09, 0xa8, 0xdd, 0x80,
|
0xb2, 0x18, 0xfd, 0x5a, 0x29, 0xbb, 0x35, 0xe0,
|
||||||
0x64, 0x52, 0x85, 0x4a, 0xf2, 0xd7, 0xc7, 0x11,
|
0x3d, 0x9f, 0x85, 0xf7, 0x36 ]
|
||||||
0x29, 0x22, 0xbe, 0xe5, 0xad, 0x57, 0x6b, 0x4f,
|
|
||||||
0xdc, 0xa1, 0xae, 0x00, 0x5b, 0xff, 0xe8, 0x6c,
|
|
||||||
0xdb, 0x15, 0x84, 0x18, 0x94, 0x0e, 0xeb, 0xcd,
|
|
||||||
0x9d, 0x41, 0xc3, 0x4e, 0xf6, 0xa6, 0xcf, 0x2c,
|
|
||||||
0xf5, 0xc5, 0x9e, 0xa0, 0xd9, 0x80, 0x5f, 0xaa,
|
|
||||||
0x22, 0x66, 0x61, 0x56, 0xde, 0x3e, 0xcb, 0x5f,
|
|
||||||
0x7c, 0x64, 0xaf, 0xbf, 0xa7, 0x26, 0x83, 0xa8,
|
|
||||||
0x5c, 0x88, 0xf3, 0xbe, 0x8a, 0xe6, 0xe6, 0x4c,
|
|
||||||
0xf7, 0x95, 0xd0, 0xa8, 0xf0, 0x8c, 0x21, 0xf8,
|
|
||||||
0x86, 0x77, 0x49, 0x29, 0xe3, 0xd3, 0xf8, 0x78,
|
|
||||||
0x1f, 0x51, 0x91 ]
|
|
||||||
|
|
||||||
pubKey = "\x30\x81\x89\x02\x81\x81\x00\x9e\x95\xb5\x41\x03\xc5\x33\xea\x29\x65\x2b\x65\xef\x30\x71\xdd\x73\xbb\x30\x3b\xec\xca\x72\xcf\xbd\xe0\xf8\x21\xff\xa6\x97\x76\xa1\x08\xb5\xd2\xc6\x95\x81\xd2\xba\x71\x10\x4a\xac\x25\x34\x37\xa0\xc3\x57\xf0\xea\x1f\x8c\x84\xeb\x7b\xe6\x6c\x50\x26\x1f\xb7\x41\x0a\x58\xd3\x80\x87\x3d\x0b\x41\xd9\xbc\x54\x3a\x0f\x77\x14\x79\xf5\xb9\xa4\x38\xeb\x13\x08\x35\xae\xbf\xb3\x17\x5a\xe2\x58\x89\x39\xc4\x22\x7f\x16\x57\x90\x08\xaf\x91\x3b\x95\xc8\x53\xd0\xc0\x8e\x19\x8a\xf3\x10\xbc\xc8\xc7\x42\xfb\x12\xde\x2d\x5e\x83\x02\x03\x01\x00\x01"
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import cssp, hexdump
|
import cssp, hexdump
|
||||||
from rdpy.core.type import Stream
|
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])))
|
||||||
negotiate_data_request = cssp.decodeDERTRequest(Stream("".join([chr(i) for i in cssp_1])))
|
authenticate_data_request = cssp.decodeDERTRequest(Stream("".join([chr(i) for i in peer0_1])))
|
||||||
challenge_data_request = cssp.decodeDERTRequest(Stream("".join([chr(i) for i in cssp_2])))
|
|
||||||
authenticate_data_request = cssp.decodeDERTRequest(Stream("".join([chr(i) for i in cssp_3])))
|
|
||||||
|
|
||||||
negotiate_data = cssp.getNegoTokens(negotiate_data_request)[0]
|
negotiate_data = cssp.getNegoTokens(negotiate_data_request)[0]
|
||||||
challenge_data = cssp.getNegoTokens(challenge_data_request)[0]
|
challenge_data = cssp.getNegoTokens(challenge_data_request)[0]
|
||||||
@@ -557,57 +676,39 @@ if __name__ == "__main__":
|
|||||||
authenticate = AuthenticateMessage()
|
authenticate = AuthenticateMessage()
|
||||||
authenticate_data.readType(authenticate)
|
authenticate_data.readType(authenticate)
|
||||||
|
|
||||||
NtChallengeResponse = authenticate.getNtChallengeResponse()
|
NtChallengeResponseTemp = authenticate.getNtChallengeResponse()
|
||||||
NTProofStr = NtChallengeResponse[:16]
|
NTProofStr = NtChallengeResponseTemp[:16]
|
||||||
temp = NtChallengeResponse[16:]
|
temp = NtChallengeResponseTemp[16:]
|
||||||
Time = temp[8:16]
|
Timestamp = temp[8:16]
|
||||||
ClientChallenge = temp[16:24]
|
ClientChallenge = temp[16:24]
|
||||||
ServerName2 = temp[28:-4]
|
EncryptedRandomSessionKey = authenticate.getEncryptedRandomSession()
|
||||||
|
|
||||||
LmChallengeResponse = authenticate.getLmChallengeResponse()
|
domain = "dodo"
|
||||||
EncryptedRandom = authenticate.getEncryptedRandomSession()
|
user = "uouo"
|
||||||
encryptedPubKey = cssp.getPubKeyAuth(authenticate_data_request)
|
password = "popo"
|
||||||
|
ResponseKeyNT = NTOWFv2(password, user, domain)
|
||||||
|
ResponseKeyLM = LMOWFv2(password, user, domain)
|
||||||
|
|
||||||
|
NtChallengeResponse, LmChallengeResponse, SessionBaseKey = ComputeResponsev2(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChallenge, Timestamp, ServerName)
|
||||||
|
KeyExchangeKey = KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge)
|
||||||
|
ExportedSessionKey = RC4K(KeyExchangeKey, EncryptedRandomSessionKey)
|
||||||
|
|
||||||
NtChallengeResponse2, LmChallengeResponse2, SessionBaseKey2 = NTLMv2Authenticate(None, "coco", "toto", "lolo", ServerChallenge, ServerName, Time, ClientChallenge)
|
domain, user = domain, user
|
||||||
|
if challenge.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_UNICODE:
|
||||||
|
domain, user = UNICODE(domain), UNICODE(user)
|
||||||
|
message = createAuthenticationMessage(domain, user, NtChallengeResponse, LmChallengeResponse, EncryptedRandomSessionKey)
|
||||||
|
|
||||||
KeyExchangeKey = KXKEY(SessionBaseKey2, LmChallengeResponse2, ServerChallenge)
|
ClientSigningKey = SIGNKEY(ExportedSessionKey, True)
|
||||||
#decrypt
|
ServerSigningKey = SIGNKEY(ExportedSessionKey, False)
|
||||||
ExportedSessionKey = RC4K(KeyExchangeKey, EncryptedRandom)
|
ClientSealingKey = SEALKEY(ExportedSessionKey, True)
|
||||||
|
ServerSealingKey = SEALKEY(ExportedSessionKey, False)
|
||||||
|
|
||||||
sealingKey = SEALKEY(ExportedSessionKey)
|
interface = NTLMv2SecurityInterface(rc4.RC4Key(ClientSealingKey), rc4.RC4Key(ServerSealingKey), ClientSigningKey, ServerSigningKey)
|
||||||
signingKey = SIGNKEY(ExportedSessionKey)
|
|
||||||
|
|
||||||
key = rc4.RC4Key(sealingKey)
|
EncryptedPubKeySrc = cssp.getPubKeyAuth(authenticate_data_request)
|
||||||
|
EncryptedPubKeyDst = interface.GSS_WrapEx("".join([chr(i) for i in pubKeyHex]))
|
||||||
|
|
||||||
encryptedPubKey2 = rc4.crypt(key, pubKey)
|
print "EncryptedPubKeySrc"
|
||||||
signature = rc4.crypt(key, HMAC_MD5(signingKey, "\x00\x00\x00\x00" + pubKey)[:8])
|
hexdump.hexdump(EncryptedPubKeySrc)
|
||||||
|
print "EncryptedPubKeyDst"
|
||||||
|
hexdump.hexdump(EncryptedPubKeyDst)
|
||||||
hexdump.hexdump(encryptedPubKey)
|
|
||||||
print "\n"
|
|
||||||
hexdump.hexdump(signature)
|
|
||||||
print "\n"
|
|
||||||
hexdump.hexdump(encryptedPubKey2)
|
|
||||||
# print "-"*40
|
|
||||||
# print "NtChallengeResponse"
|
|
||||||
# print "\n"
|
|
||||||
# hexdump.hexdump(NtChallengeResponse)
|
|
||||||
# print "\n"
|
|
||||||
# hexdump.hexdump(NtChallengeResponse2)
|
|
||||||
# print "-"*40
|
|
||||||
#
|
|
||||||
# print "-"*40
|
|
||||||
# print "LmChallengeResponse"
|
|
||||||
# print "\n"
|
|
||||||
# hexdump.hexdump(LmChallengeResponse)
|
|
||||||
# print "\n"
|
|
||||||
# hexdump.hexdump(LmChallengeResponse2)
|
|
||||||
# print "-"*40
|
|
||||||
#
|
|
||||||
# print "-"*40
|
|
||||||
# print "SessionBaseKey"
|
|
||||||
# print "\n"
|
|
||||||
# hexdump.hexdump(SessionBaseKey)
|
|
||||||
# print "\n"
|
|
||||||
# hexdump.hexdump(SessionBaseKey2)
|
|
||||||
# print "-"*40
|
|
||||||
55
rdpy/protocol/rdp/nla/sspi.py
Normal file
55
rdpy/protocol/rdp/nla/sspi.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2014-2015 Sylvain Peyrefitte
|
||||||
|
#
|
||||||
|
# This file is part of rdpy.
|
||||||
|
#
|
||||||
|
# rdpy is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
@summary: security service provider interface (Microsoft)
|
||||||
|
"""
|
||||||
|
|
||||||
|
from rdpy.core.error import CallPureVirtualFuntion
|
||||||
|
|
||||||
|
class IAuthenticationProtocol(object):
|
||||||
|
"""
|
||||||
|
@summary: generic class for authentication Protocol (ex: ntlmv2, SPNEGO or kerberos)
|
||||||
|
"""
|
||||||
|
def getNegotiateMessage(self):
|
||||||
|
"""
|
||||||
|
@summary: Client first handshake message for authentication protocol
|
||||||
|
@return: {object} first handshake message
|
||||||
|
"""
|
||||||
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "getNegotiateMessage", "IAuthenticationProtocol"))
|
||||||
|
|
||||||
|
def getAuthenticateMessage(self, s):
|
||||||
|
"""
|
||||||
|
@summary: Client last handshake message
|
||||||
|
@param s: {Stream} challenge message stream
|
||||||
|
@return: {(object, IGenericSecurityService)} Last handshake message and interface for application
|
||||||
|
"""
|
||||||
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "getAuthenticateMessage", "IAuthenticationProtocol"))
|
||||||
|
|
||||||
|
class IGenericSecurityService(object):
|
||||||
|
"""
|
||||||
|
@summary: use by application from authentification protocol
|
||||||
|
@see: http://www.rfc-editor.org/rfc/rfc2743.txt
|
||||||
|
"""
|
||||||
|
def GSS_WrapEx(self, data):
|
||||||
|
"""
|
||||||
|
@summary: encrypt data with key exchage in Authentication protocol
|
||||||
|
@param data: {str}
|
||||||
|
"""
|
||||||
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "GSS_WrapEx", "IGenericSecurityService"))
|
||||||
@@ -114,6 +114,7 @@ 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):
|
||||||
"""
|
"""
|
||||||
@@ -223,8 +224,10 @@ 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
|
||||||
|
#hexdump.hexdump(self.transport.protocol._tlsConnection.getpeercert())
|
||||||
#send NTLM negotiate message packet
|
#send NTLM negotiate message packet
|
||||||
RawLayer.send(self, cssp.encodeDERTRequest( [ ntlm.NegotiateMessage() ] ))
|
RawLayer.send(self, cssp.encodeDERTRequest( negoTypes = [ self._ntlm.getNegotiateMessage() ] ))
|
||||||
self.expectImmediately(self.readNTLMChallenge)
|
self.expectImmediately(self.readNTLMChallenge)
|
||||||
|
|
||||||
def readNTLMChallenge(self, data):
|
def readNTLMChallenge(self, data):
|
||||||
@@ -232,8 +235,7 @@ class TPKT(RawLayer, IFastPathSender):
|
|||||||
@summary: server NTLM challenge
|
@summary: server NTLM challenge
|
||||||
@param data: {Stream}
|
@param data: {Stream}
|
||||||
"""
|
"""
|
||||||
s = cssp.decodeDERTRequest(data)
|
request = cssp.decodeDERTRequest(data)
|
||||||
challenge = ntlm.ChallengeMessage()
|
message, interface = self._ntlm.getAuthenticateMessage(cssp.getNegoTokens(request)[0])
|
||||||
s[0].readType(challenge)
|
RawLayer.send(self, cssp.encodeDERTRequest( negoTypes = [ message ], pubKeyAuth = interface.GSS_WrapEx("".join([chr(i) for i in ntlm.pubKeyHex]))))
|
||||||
RawLayer.send(self, cssp.encodeDERTRequest( [ ntlm.createAuthenticationMessage(ntlm.NTLMv2Authenticate, challenge, "toto", "toto", "toto") ] ))
|
|
||||||
self.restartAutomata()
|
self.restartAutomata()
|
||||||
Reference in New Issue
Block a user