mirror of
https://github.com/TalAloni/SMBLibrary.git
synced 2025-07-25 10:28:15 +02:00
IndependentNTLMAuthenticationProvider: Added account lockout mechanism to hinder bruteforce attacks
This commit is contained in:
parent
ddafceb45c
commit
a32e62d020
3 changed files with 108 additions and 3 deletions
77
SMBLibrary/Authentication/LoginCounter.cs
Normal file
77
SMBLibrary/Authentication/LoginCounter.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 GetUserPassword m_GetUserPassword;
|
||||||
|
private LoginCounter m_loginCounter;
|
||||||
|
|
||||||
/// <param name="getUserPassword">
|
/// <param name="getUserPassword">
|
||||||
/// The NTLM challenge response will be compared against the provided password.
|
/// The NTLM challenge response will be compared against the provided password.
|
||||||
/// </param>
|
/// </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_GetUserPassword = getUserPassword;
|
||||||
|
m_loginCounter = new LoginCounter(maxLoginAttemptsInWindow, loginWindowDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override NTStatus GetChallengeMessage(out object context, NegotiateMessage negotiateMessage, out ChallengeMessage challengeMessage)
|
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);
|
string password = m_GetUserPassword(message.UserName);
|
||||||
if (password == null)
|
if (password == null)
|
||||||
{
|
{
|
||||||
|
@ -164,7 +177,14 @@ namespace SMBLibrary.Authentication.NTLM
|
||||||
}
|
}
|
||||||
else
|
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
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
<Compile Include="Authentication\GSSAPI\SPNEGO\SimpleProtectedNegotiationToken.cs" />
|
<Compile Include="Authentication\GSSAPI\SPNEGO\SimpleProtectedNegotiationToken.cs" />
|
||||||
<Compile Include="Authentication\GSSAPI\SPNEGO\SimpleProtectedNegotiationTokenInit.cs" />
|
<Compile Include="Authentication\GSSAPI\SPNEGO\SimpleProtectedNegotiationTokenInit.cs" />
|
||||||
<Compile Include="Authentication\GSSAPI\SPNEGO\SimpleProtectedNegotiationTokenResponse.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\AuthenticationMessageUtils.cs" />
|
||||||
<Compile Include="Authentication\NTLM\Helpers\AVPairUtils.cs" />
|
<Compile Include="Authentication\NTLM\Helpers\AVPairUtils.cs" />
|
||||||
<Compile Include="Authentication\NTLM\Helpers\MD4.cs" />
|
<Compile Include="Authentication\NTLM\Helpers\MD4.cs" />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue