From 6772c0c33e97e00fc1dbfc3b77629be9a61cf06c Mon Sep 17 00:00:00 2001 From: Tal Aloni Date: Thu, 19 Jan 2017 22:05:08 +0200 Subject: [PATCH] IsNTLMv1ExtendedSecurity and IsNTLMv2NTResponse methods added to AuthenticationMessageUtils --- .../AuthenticationMessageUtils.cs | 30 ++++++++++++ .../Server/IndependentUserCollection.cs | 10 ++-- SMBLibrary/Server/SMB1/SessionSetupHelper.cs | 3 +- SMBLibrary/Win32/Win32UserCollection.cs | 47 ++++++++++--------- 4 files changed, 65 insertions(+), 25 deletions(-) diff --git a/SMBLibrary/Authentication/AuthenticateMessage/AuthenticationMessageUtils.cs b/SMBLibrary/Authentication/AuthenticateMessage/AuthenticationMessageUtils.cs index 1b463f1..1c83103 100644 --- a/SMBLibrary/Authentication/AuthenticateMessage/AuthenticationMessageUtils.cs +++ b/SMBLibrary/Authentication/AuthenticateMessage/AuthenticationMessageUtils.cs @@ -58,6 +58,36 @@ namespace SMBLibrary.Authentication return (signature == AuthenticateMessage.ValidSignature); } + /// + /// If NTLM v1 Extended Security is used, LMResponse starts with 8-byte challenge, followed by 16 bytes of padding (set to zero). + /// + /// + /// LMResponse is 24 bytes for NTLM v1, NTLM v1 Extended Security and NTLM v2. + /// + public static bool IsNTLMv1ExtendedSecurity(byte[] lmResponse) + { + if (lmResponse.Length == 24) + { + if (ByteUtils.AreByteArraysEqual(ByteReader.ReadBytes(lmResponse, 0, 8), new byte[8])) + { + // Challenge not present, cannot be NTLM v1 Extended Security + return false; + } + return ByteUtils.AreByteArraysEqual(ByteReader.ReadBytes(lmResponse, 8, 16), new byte[16]); + } + return false; + } + + /// + /// NTLM v1 / NTLM v1 Extended Security NTResponse is 24 bytes. + /// + public static bool IsNTLMv2NTResponse(byte[] ntResponse) + { + return (ntResponse.Length >= 48 && + ntResponse[16] == NTLMv2ClientChallenge.StructureVersion && + ntResponse[17] == NTLMv2ClientChallenge.StructureVersion); + } + public static MessageTypeName GetMessageType(byte[] messageBytes) { return (MessageTypeName)LittleEndianConverter.ToUInt32(messageBytes, 8); diff --git a/SMBLibrary/Server/IndependentUserCollection.cs b/SMBLibrary/Server/IndependentUserCollection.cs index 89202a0..cd3b153 100644 --- a/SMBLibrary/Server/IndependentUserCollection.cs +++ b/SMBLibrary/Server/IndependentUserCollection.cs @@ -96,7 +96,7 @@ namespace SMBLibrary.Server return this[index]; } - if (ntResponse.Length >= 48) + if (AuthenticationMessageUtils.IsNTLMv2NTResponse(ntResponse)) { byte[] clientNTProof = ByteReader.ReadBytes(ntResponse, 0, 16); byte[] clientChallengeStructurePadded = ByteReader.ReadBytes(ntResponse, 16, ntResponse.Length - 16); @@ -161,8 +161,12 @@ namespace SMBLibrary.Server User user; if ((message.NegotiateFlags & NegotiateFlags.ExtendedSecurity) > 0) { - user = AuthenticateV1Extended(message.UserName, m_serverChallenge, message.LmChallengeResponse, message.NtChallengeResponse); - if (user == null) + if (AuthenticationMessageUtils.IsNTLMv1ExtendedSecurity(message.LmChallengeResponse)) + { + // NTLM v1 Extended Security: + user = AuthenticateV1Extended(message.UserName, m_serverChallenge, message.LmChallengeResponse, message.NtChallengeResponse); + } + else { // NTLM v2: user = AuthenticateV2(message.DomainName, message.UserName, m_serverChallenge, message.LmChallengeResponse, message.NtChallengeResponse); diff --git a/SMBLibrary/Server/SMB1/SessionSetupHelper.cs b/SMBLibrary/Server/SMB1/SessionSetupHelper.cs index bd808d0..47eebf1 100644 --- a/SMBLibrary/Server/SMB1/SessionSetupHelper.cs +++ b/SMBLibrary/Server/SMB1/SessionSetupHelper.cs @@ -183,7 +183,8 @@ namespace SMBLibrary.Server.SMB1 NegotiateFlags.Version | NegotiateFlags.Use128BitEncryption | NegotiateFlags.Use56BitEncryption; - if (ntChallengeResponse.Length >= 48) + if (AuthenticationMessageUtils.IsNTLMv1ExtendedSecurity(lmChallengeResponse) || + AuthenticationMessageUtils.IsNTLMv2NTResponse(ntChallengeResponse)) { authenticateMessage.NegotiateFlags |= NegotiateFlags.ExtendedSecurity; } diff --git a/SMBLibrary/Win32/Win32UserCollection.cs b/SMBLibrary/Win32/Win32UserCollection.cs index 8a8f6b0..3f122d5 100644 --- a/SMBLibrary/Win32/Win32UserCollection.cs +++ b/SMBLibrary/Win32/Win32UserCollection.cs @@ -82,32 +82,37 @@ namespace SMBLibrary.Server.Win32 if ((message.NegotiateFlags & NegotiateFlags.ExtendedSecurity) > 0) { - // NTLM v1 extended security: - byte[] clientChallenge = ByteReader.ReadBytes(message.LmChallengeResponse, 0, 8); - byte[] emptyPasswordNTLMv1Response = NTAuthentication.ComputeNTLMv1ExtendedSecurityResponse(m_serverChallenge, clientChallenge, String.Empty); - if (ByteUtils.AreByteArraysEqual(emptyPasswordNTLMv1Response, message.NtChallengeResponse)) + if (AuthenticationMessageUtils.IsNTLMv1ExtendedSecurity(message.LmChallengeResponse)) { - return true; - } - - // NTLM v2: - byte[] _LMv2ClientChallenge = ByteReader.ReadBytes(message.LmChallengeResponse, 16, 8); - byte[] emptyPasswordLMv2Response = NTAuthentication.ComputeLMv2Response(m_serverChallenge, _LMv2ClientChallenge, String.Empty, message.UserName, message.DomainName); - if (ByteUtils.AreByteArraysEqual(emptyPasswordLMv2Response, message.LmChallengeResponse)) - { - return true; - } - - if (message.NtChallengeResponse.Length >= 48) - { - byte[] clientNTProof = ByteReader.ReadBytes(message.NtChallengeResponse, 0, 16); - byte[] clientChallengeStructurePadded = ByteReader.ReadBytes(message.NtChallengeResponse, 16, message.NtChallengeResponse.Length - 16); - byte[] emptyPasswordNTProof = NTAuthentication.ComputeNTLMv2Proof(m_serverChallenge, clientChallengeStructurePadded, String.Empty, message.UserName, message.DomainName); - if (ByteUtils.AreByteArraysEqual(clientNTProof, emptyPasswordNTProof)) + // NTLM v1 extended security: + byte[] clientChallenge = ByteReader.ReadBytes(message.LmChallengeResponse, 0, 8); + byte[] emptyPasswordNTLMv1Response = NTAuthentication.ComputeNTLMv1ExtendedSecurityResponse(m_serverChallenge, clientChallenge, String.Empty); + if (ByteUtils.AreByteArraysEqual(emptyPasswordNTLMv1Response, message.NtChallengeResponse)) { return true; } } + else + { + // NTLM v2: + byte[] _LMv2ClientChallenge = ByteReader.ReadBytes(message.LmChallengeResponse, 16, 8); + byte[] emptyPasswordLMv2Response = NTAuthentication.ComputeLMv2Response(m_serverChallenge, _LMv2ClientChallenge, String.Empty, message.UserName, message.DomainName); + if (ByteUtils.AreByteArraysEqual(emptyPasswordLMv2Response, message.LmChallengeResponse)) + { + return true; + } + + if (AuthenticationMessageUtils.IsNTLMv2NTResponse(message.NtChallengeResponse)) + { + byte[] clientNTProof = ByteReader.ReadBytes(message.NtChallengeResponse, 0, 16); + byte[] clientChallengeStructurePadded = ByteReader.ReadBytes(message.NtChallengeResponse, 16, message.NtChallengeResponse.Length - 16); + byte[] emptyPasswordNTProof = NTAuthentication.ComputeNTLMv2Proof(m_serverChallenge, clientChallengeStructurePadded, String.Empty, message.UserName, message.DomainName); + if (ByteUtils.AreByteArraysEqual(clientNTProof, emptyPasswordNTProof)) + { + return true; + } + } + } } else {