/// <summary> /// LM v1 / NTLM v1 Extended Session Security /// </summary> private static bool AuthenticateV1Extended(string password, byte[] serverChallenge, byte[] lmResponse, byte[] ntResponse) { byte[] clientChallenge = ByteReader.ReadBytes(lmResponse, 0, 8); byte[] expectedNTLMv1Response = NTLMCryptography.ComputeNTLMv1ExtendedSessionSecurityResponse(serverChallenge, clientChallenge, password); return(ByteUtils.AreByteArraysEqual(expectedNTLMv1Response, ntResponse)); }
/// <summary> /// LM v1 / NTLM v1 /// </summary> private static bool AuthenticateV1(string password, byte[] serverChallenge, byte[] lmResponse, byte[] ntResponse) { byte[] expectedLMResponse = NTLMCryptography.ComputeLMv1Response(serverChallenge, password); if (ByteUtils.AreByteArraysEqual(expectedLMResponse, lmResponse)) { return(true); } byte[] expectedNTResponse = NTLMCryptography.ComputeNTLMv1Response(serverChallenge, password); return(ByteUtils.AreByteArraysEqual(expectedNTResponse, ntResponse)); }
/// <summary> /// LM v2 / NTLM v2 /// </summary> private bool AuthenticateV2(string domainName, string accountName, string password, byte[] serverChallenge, byte[] lmResponse, byte[] ntResponse) { // Note: Linux CIFS VFS 3.10 will send LmChallengeResponse with length of 0 bytes if (lmResponse.Length == 24) { byte[] _LMv2ClientChallenge = ByteReader.ReadBytes(lmResponse, 16, 8); byte[] expectedLMv2Response = NTLMCryptography.ComputeLMv2Response(serverChallenge, _LMv2ClientChallenge, password, accountName, domainName); if (ByteUtils.AreByteArraysEqual(expectedLMv2Response, lmResponse)) { return(true); } } if (AuthenticationMessageUtils.IsNTLMv2NTResponse(ntResponse)) { byte[] clientNTProof = ByteReader.ReadBytes(ntResponse, 0, 16); byte[] clientChallengeStructurePadded = ByteReader.ReadBytes(ntResponse, 16, ntResponse.Length - 16); byte[] expectedNTProof = NTLMCryptography.ComputeNTLMv2Proof(serverChallenge, clientChallengeStructurePadded, password, accountName, domainName); return(ByteUtils.AreByteArraysEqual(clientNTProof, expectedNTProof)); } return(false); }
public override NTStatus Authenticate(object context, AuthenticateMessage message) { AuthContext authContext = context as AuthContext; if (authContext == null) { // There are two possible reasons for authContext to be null: // 1. We have a bug in our implementation, let's assume that's not the case, // according to [MS-SMB2] 3.3.5.5.1 we aren't allowed to return SEC_E_INVALID_HANDLE anyway. // 2. The client sent AuthenticateMessage without sending NegotiateMessage first, // in this case the correct response is SEC_E_INVALID_TOKEN. return(NTStatus.SEC_E_INVALID_TOKEN); } authContext.DomainName = message.DomainName; authContext.UserName = message.UserName; authContext.WorkStation = message.WorkStation; if (message.Version != null) { authContext.OSVersion = message.Version.ToString(); } if ((message.NegotiateFlags & NegotiateFlags.Anonymous) > 0) { if (this.EnableGuestLogin) { authContext.IsGuest = true; return(NTStatus.STATUS_SUCCESS); } else { return(NTStatus.STATUS_LOGON_FAILURE); } } if (!m_loginCounter.HasRemainingLoginAttempts(message.UserName.ToLower())) { return(NTStatus.STATUS_ACCOUNT_LOCKED_OUT); } string password = m_GetUserPassword(message.UserName); if (password == null) { if (this.EnableGuestLogin) { authContext.IsGuest = true; return(NTStatus.STATUS_SUCCESS); } else { if (m_loginCounter.HasRemainingLoginAttempts(message.UserName.ToLower(), true)) { return(NTStatus.STATUS_LOGON_FAILURE); } else { return(NTStatus.STATUS_ACCOUNT_LOCKED_OUT); } } } bool success; byte[] serverChallenge = authContext.ServerChallenge; byte[] sessionBaseKey; byte[] keyExchangeKey = null; if ((message.NegotiateFlags & NegotiateFlags.ExtendedSessionSecurity) > 0) { if (AuthenticationMessageUtils.IsNTLMv1ExtendedSessionSecurity(message.LmChallengeResponse)) { // NTLM v1 Extended Session Security: success = AuthenticateV1Extended(password, serverChallenge, message.LmChallengeResponse, message.NtChallengeResponse); if (success) { // https://msdn.microsoft.com/en-us/library/cc236699.aspx sessionBaseKey = new MD4().GetByteHashFromBytes(NTLMCryptography.NTOWFv1(password)); byte[] lmowf = NTLMCryptography.LMOWFv1(password); keyExchangeKey = NTLMCryptography.KXKey(sessionBaseKey, message.NegotiateFlags, message.LmChallengeResponse, serverChallenge, lmowf); } } else { // NTLM v2: success = AuthenticateV2(message.DomainName, message.UserName, password, serverChallenge, message.LmChallengeResponse, message.NtChallengeResponse); if (success) { // https://msdn.microsoft.com/en-us/library/cc236700.aspx byte[] responseKeyNT = NTLMCryptography.NTOWFv2(password, message.UserName, message.DomainName); byte[] ntProofStr = ByteReader.ReadBytes(message.NtChallengeResponse, 0, 16); sessionBaseKey = new HMACMD5(responseKeyNT).ComputeHash(ntProofStr); keyExchangeKey = sessionBaseKey; } } } else { success = AuthenticateV1(password, serverChallenge, message.LmChallengeResponse, message.NtChallengeResponse); if (success) { // https://msdn.microsoft.com/en-us/library/cc236699.aspx sessionBaseKey = new MD4().GetByteHashFromBytes(NTLMCryptography.NTOWFv1(password)); byte[] lmowf = NTLMCryptography.LMOWFv1(password); keyExchangeKey = NTLMCryptography.KXKey(sessionBaseKey, message.NegotiateFlags, message.LmChallengeResponse, serverChallenge, lmowf); } } if (success) { // https://msdn.microsoft.com/en-us/library/cc236676.aspx // https://blogs.msdn.microsoft.com/openspecification/2010/04/19/ntlm-keys-and-sundry-stuff/ if ((message.NegotiateFlags & NegotiateFlags.KeyExchange) > 0) { authContext.SessionKey = RC4.Decrypt(keyExchangeKey, message.EncryptedRandomSessionKey); } else { authContext.SessionKey = keyExchangeKey; } return(NTStatus.STATUS_SUCCESS); } else { if (m_loginCounter.HasRemainingLoginAttempts(message.UserName.ToLower(), true)) { return(NTStatus.STATUS_LOGON_FAILURE); } else { return(NTStatus.STATUS_ACCOUNT_LOCKED_OUT); } } }