Skip to content

Commit

Permalink
Fix netlogon implementation (#1848)
Browse files Browse the repository at this point in the history
* fix netlogon implementation

* add AES option when netlogon is used as SSP
  • Loading branch information
ThePirateWhoSmellsOfSunflowers authored Feb 19, 2025
1 parent 168e1ae commit 61f6a9e
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 10 deletions.
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

0 comments on commit 61f6a9e

Please sign in to comment.