Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix netlogon implementation #1848

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions impacket/dcerpc/v5/nrpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1623,9 +1623,10 @@ class NL_AUTH_SHA2_SIGNATURE(Structure):
('Pad','<H=0xffff'),
('Flags','<H=0'),
('SequenceNumber','8s=""'),
('Checksum','32s=""'),
('Checksum','8s=""'),
('_Confounder','_-Confounder','8'),
('Confounder',':'),
('Reserved','24s=""'),
)
def __init__(self, data = None, alignment = 0):
Structure.__init__(self, data, alignment)
Expand Down Expand Up @@ -1698,7 +1699,7 @@ def ComputeNetlogonSignatureAES(authSignature, message, confounder, sessionKey):
# If no confidentiality requested, it should be ''
hm.update(confounder)
hm.update(bytes(message))
return hm.digest()[:8]+'\x00'*24
return hm.digest()[:8]

def ComputeNetlogonSignatureMD5(authSignature, message, confounder, sessionKey):
# [MS-NRPC] Section 3.3.4.2.1, point 7
Expand All @@ -1713,6 +1714,21 @@ def ComputeNetlogonSignatureMD5(authSignature, message, confounder, sessionKey):
hm.update(finalMD5)
return hm.digest()[:8]

def ComputeNetlogonAuthenticatorAES(clientStoredCredential, sessionKey):
# [MS-NRPC] Section 3.1.4.5
timestamp = int(time.time())

authenticator = NETLOGON_AUTHENTICATOR()
authenticator['Timestamp'] = timestamp

credential = unpack('<I', clientStoredCredential[:4])[0] + timestamp
if credential > 0xffffffff:
credential &= 0xffffffff
credential = pack('<I', credential)

authenticator['Credential'] = ComputeNetlogonCredentialAES(credential + clientStoredCredential[4:], sessionKey)
return authenticator

def ComputeNetlogonAuthenticator(clientStoredCredential, sessionKey):
# [MS-NRPC] Section 3.1.4.5
timestamp = int(time.time())
Expand Down Expand Up @@ -1761,22 +1777,24 @@ def SIGN(data, confounder, sequenceNum, key, aes = False):
if aes is False:
signature = NL_AUTH_SIGNATURE()
signature['SignatureAlgorithm'] = NL_SIGNATURE_HMAC_MD5
if confounder == '':
if confounder == b'':
signature['SealAlgorithm'] = NL_SEAL_NOT_ENCRYPTED
else:
signature['SealAlgorithm'] = NL_SEAL_RC4
signature['Checksum'] = ComputeNetlogonSignatureMD5(signature, data, confounder, key)
signature['SequenceNumber'] = encryptSequenceNumberRC4(deriveSequenceNumber(sequenceNum), signature['Checksum'], key)
return signature
else:
signature = NL_AUTH_SIGNATURE()
signature = NL_AUTH_SHA2_SIGNATURE()
signature['SignatureAlgorithm'] = NL_SIGNATURE_HMAC_SHA256
if confounder == '':
if confounder == b'':
signature['SealAlgorithm'] = NL_SEAL_NOT_ENCRYPTED
else:
signature['SealAlgorithm'] = NL_SEAL_AES128
signature['Checksum'] = ComputeNetlogonSignatureAES(signature, data, confounder, key)
signature['SequenceNumber'] = encryptSequenceNumberAES(deriveSequenceNumber(sequenceNum), signature['Checksum'], key)
# 2.2.1.3.3 : Reserved: The sender SHOULD set these bytes to zero, and the receiver MUST ignore them.
signature['Reserved'] = b'\x00'*24
return signature

def SEAL(data, confounder, sequenceNum, key, aes = False):
Expand Down
14 changes: 9 additions & 5 deletions impacket/dcerpc/v5/rpcrt.py
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,8 @@ def __init__(self, transport):
self.__aesKey = ''
self.__TGT = None
self.__TGS = None


self.__aesNegociated = False
self.__clientSigningKey = b''
self.__serverSigningKey = b''
self.__clientSealingKey = b''
Expand All @@ -922,6 +923,9 @@ def __init__(self, transport):
self.__confounder = b''
self.__gss = None

def set_aes(self, is_aes):
self.__aesNegociated = is_aes

def set_session_key(self, session_key):
self.__sessionKey = session_key

Expand Down Expand Up @@ -1200,7 +1204,7 @@ def _transport_send(self, rpc_packet, forceWriteAndx = 0, forceRecv = 0):
self.__clientSealingHandle)
elif self.__auth_type == RPC_C_AUTHN_NETLOGON:
from impacket.dcerpc.v5 import nrpc
sealedMessage, signature = nrpc.SEAL(plain_data, self.__confounder, self.__sequence, self.__sessionKey, False)
sealedMessage, signature = nrpc.SEAL(plain_data, self.__confounder, self.__sequence, self.__sessionKey, self.__aesNegociated)
elif self.__auth_type == RPC_C_AUTHN_GSS_NEGOTIATE:
sealedMessage, signature = self.__gss.GSS_Wrap(self.__sessionKey, plain_data, self.__sequence)

Expand All @@ -1227,7 +1231,7 @@ def _transport_send(self, rpc_packet, forceWriteAndx = 0, forceRecv = 0):
self.__confounder,
self.__sequence,
self.__sessionKey,
False)
self.__aesNegociated)
elif self.__auth_type == RPC_C_AUTHN_GSS_NEGOTIATE:
signature = self.__gss.GSS_GetMIC(self.__sessionKey, plain_data, self.__sequence)

Expand Down Expand Up @@ -1374,7 +1378,7 @@ def recv(self):
answer, cfounder = nrpc.UNSEAL(answer,
auth_data[len(sec_trailer):],
self.__sessionKey,
False)
self.__aesNegociated)
self.__sequence += 1
elif self.__auth_type == RPC_C_AUTHN_GSS_NEGOTIATE:
if self.__sequence > 0:
Expand Down Expand Up @@ -1406,7 +1410,7 @@ def recv(self):
self.__confounder,
self.__sequence,
self.__sessionKey,
False)
self.__aesNegociated)
self.__sequence += 1
elif self.__auth_type == RPC_C_AUTHN_GSS_NEGOTIATE:
# Do NOT increment the sequence number when Signing Kerberos
Expand Down