IndependentNTLMAuthenticationProvider: Added account lockout mechanism to hinder bruteforce attacks

This commit is contained in:
Tal Aloni 2017-08-11 23:01:29 +03:00
parent ddafceb45c
commit a32e62d020
3 changed files with 108 additions and 3 deletions

View file

@ -0,0 +1,77 @@
/* Copyright (C) 2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace SMBLibrary.Authentication
{
public class LoginCounter
{
public class LoginEntry
{
public DateTime LoginWindowStartDT;
public int NumberOfAttempts;
}
private int m_maxLoginAttemptsInWindow;
private TimeSpan m_loginWindowDuration;
private Dictionary<string, LoginEntry> m_loginEntries = new Dictionary<string, LoginEntry>();
public LoginCounter(int maxLoginAttemptsInWindow, TimeSpan loginWindowDuration)
{
m_maxLoginAttemptsInWindow = maxLoginAttemptsInWindow;
m_loginWindowDuration = loginWindowDuration;
}
public bool HasRemainingLoginAttempts(string userID)
{
return HasRemainingLoginAttempts(userID, false);
}
public bool HasRemainingLoginAttempts(string userID, bool incrementCount)
{
lock (m_loginEntries)
{
LoginEntry entry;
if (m_loginEntries.TryGetValue(userID, out entry))
{
if (entry.LoginWindowStartDT.Add(m_loginWindowDuration) >= DateTime.Now)
{
// Existing login Window
if (incrementCount)
{
entry.NumberOfAttempts++;
}
}
else
{
// New login Window
if (!incrementCount)
{
return true;
}
entry.LoginWindowStartDT = DateTime.Now;
entry.NumberOfAttempts = 1;
}
}
else
{
if (!incrementCount)
{
return true;
}
entry = new LoginEntry();
entry.LoginWindowStartDT = DateTime.Now;
entry.NumberOfAttempts = 1;
m_loginEntries.Add(userID, entry);
}
return (entry.NumberOfAttempts < m_maxLoginAttemptsInWindow);
}
}
}
}

View file

@ -33,14 +33,22 @@ namespace SMBLibrary.Authentication.NTLM
}
}
private static readonly int DefaultMaxLoginAttemptsInWindow = 12;
private static readonly TimeSpan DefaultLoginWindowDuration = new TimeSpan(0, 5, 0);
private GetUserPassword m_GetUserPassword;
private LoginCounter m_loginCounter;
/// <param name="getUserPassword">
/// The NTLM challenge response will be compared against the provided password.
/// </param>
public IndependentNTLMAuthenticationProvider(GetUserPassword getUserPassword)
public IndependentNTLMAuthenticationProvider(GetUserPassword getUserPassword) : this(getUserPassword, DefaultMaxLoginAttemptsInWindow, DefaultLoginWindowDuration)
{
}
public IndependentNTLMAuthenticationProvider(GetUserPassword getUserPassword, int maxLoginAttemptsInWindow, TimeSpan loginWindowDuration)
{
m_GetUserPassword = getUserPassword;
m_loginCounter = new LoginCounter(maxLoginAttemptsInWindow, loginWindowDuration);
}
public override NTStatus GetChallengeMessage(out object context, NegotiateMessage negotiateMessage, out ChallengeMessage challengeMessage)
@ -154,6 +162,11 @@ namespace SMBLibrary.Authentication.NTLM
}
}
if (!m_loginCounter.HasRemainingLoginAttempts(message.UserName.ToLower()))
{
return NTStatus.STATUS_ACCOUNT_LOCKED_OUT;
}
string password = m_GetUserPassword(message.UserName);
if (password == null)
{
@ -164,7 +177,14 @@ namespace SMBLibrary.Authentication.NTLM
}
else
{
return NTStatus.STATUS_LOGON_FAILURE;
if (m_loginCounter.HasRemainingLoginAttempts(message.UserName.ToLower(), true))
{
return NTStatus.STATUS_LOGON_FAILURE;
}
else
{
return NTStatus.STATUS_ACCOUNT_LOCKED_OUT;
}
}
}
@ -228,7 +248,14 @@ namespace SMBLibrary.Authentication.NTLM
}
else
{
return NTStatus.STATUS_LOGON_FAILURE;
if (m_loginCounter.HasRemainingLoginAttempts(message.UserName.ToLower(), true))
{
return NTStatus.STATUS_LOGON_FAILURE;
}
else
{
return NTStatus.STATUS_ACCOUNT_LOCKED_OUT;
}
}
}

View file

@ -38,6 +38,7 @@
<Compile Include="Authentication\GSSAPI\SPNEGO\SimpleProtectedNegotiationToken.cs" />
<Compile Include="Authentication\GSSAPI\SPNEGO\SimpleProtectedNegotiationTokenInit.cs" />
<Compile Include="Authentication\GSSAPI\SPNEGO\SimpleProtectedNegotiationTokenResponse.cs" />
<Compile Include="Authentication\LoginCounter.cs" />
<Compile Include="Authentication\NTLM\Helpers\AuthenticationMessageUtils.cs" />
<Compile Include="Authentication\NTLM\Helpers\AVPairUtils.cs" />
<Compile Include="Authentication\NTLM\Helpers\MD4.cs" />