/// <summary> /// Add a typo to a password for simulating user typo errors /// </summary> /// <param name="originalPassword">The original password to add a typo to</param> /// <returns>The password modified to contain a typo</returns> public static string AddTypoToPassword(string originalPassword) { // Adding a character will meet the edit distance def. of typo, though if simulating systems that weigh // different typos differently one might want to create a variety of typos here const string typoAlphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./"; return(originalPassword + typoAlphabet[(int)StrongRandomNumberGenerator.Get32Bits(typoAlphabet.Length)]); }
public SimulatedLoginAttempt MaliciousAttemptToSantiizeIpViaAValidLogin(IPAddress ipAddressToSanitizeThroughLogin) { SimulatedUserAccount simAccount = _simAccounts.GetMaliciousAccountAtRandomUniform(); return(new SimulatedLoginAttempt(simAccount, simAccount.Password, true, false, ipAddressToSanitizeThroughLogin, StrongRandomNumberGenerator.Get64Bits().ToString(), "", DateTime.UtcNow)); }
protected int GetIndexOfRandomBitOfDesiredValue(bool desiredValueOfElement) { int elementIndex; do { elementIndex = (int)(StrongRandomNumberGenerator.Get64Bits((ulong)base.Length)); } while (base[elementIndex] != desiredValueOfElement); return(elementIndex); }
protected int GetIndexOfRandomBitOfDesiredValue(bool desiredValueOfElement) { int elementIndex; // Iterate through random elements until we find one that is set to one (true) and can be cleared do { elementIndex = (int)(StrongRandomNumberGenerator.Get64Bits((ulong)base.Length)); } while (base[elementIndex] != desiredValueOfElement); return(elementIndex); }
public int Step(string key, int?heightOfLadderInRungs = null) { List <int> rungs = GetIndexesAssociatedWithAnElement(key, heightOfLadderInRungs).ToList(); List <int> rungsAbove = rungs.Where(rung => !base[rung]).ToList(); int indexOfElementToSet = (rungsAbove.Count > 0) ? rungsAbove[(int)(StrongRandomNumberGenerator.Get32Bits((uint)rungsAbove.Count))] : GetIndexOfRandomBitOfDesiredValue(false); int indexOfElementToClear = GetIndexOfRandomBitOfDesiredValue(true); SwapBits(indexOfElementToSet, indexOfElementToClear); return(rungs.Count - rungsAbove.Count); }
public SimulatedLoginAttempt MaliciousLoginAttemptWeighted(DateTime eventTimeUtc) { SimulatedUserAccount targetBenignAccount = (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ProbabilityThatAttackerChoosesAnInvalidAccount) ? null : _simAccounts.GetBenignAccountAtRandomUniform(); return(new SimulatedLoginAttempt( targetBenignAccount, _simPasswords.GetPasswordFromWeightedDistribution(), true, true, _ipPool.GetRandomMaliciousIp(), StrongRandomNumberGenerator.Get64Bits().ToString(), "", eventTimeUtc)); }
public static double GetNormal() { double v1; double s; do { v1 = 2.0 * StrongRandomNumberGenerator.GetFraction() - 1.0; double v2 = 2.0 * StrongRandomNumberGenerator.GetFraction() - 1.0; s = v1 * v1 + v2 * v2; } while (s >= 1d || s <= 0d); s = Math.Sqrt((-2.0 * Math.Log(s)) / s); return(v1 * s); }
public async Task CookieUsedInPriorLoginAsync() { Init(); string username = "******"; string password = "******"; DbUserAccount account = userAccountController.Create(username, password); string randomCookiesHash = Convert.ToBase64String(StrongRandomNumberGenerator.GetBytes(16)); bool cookieAlreadyPresentOnFirstTest = await userAccountController.HasClientWithThisHashedCookieSuccessfullyLoggedInBeforeAsync(account, randomCookiesHash); Assert.False(cookieAlreadyPresentOnFirstTest); await userAccountController.RecordHashOfDeviceCookieUsedDuringSuccessfulLoginAsync(account, randomCookiesHash); bool cookieAlreadyPresentOnSecondTest = await userAccountController.HasClientWithThisHashedCookieSuccessfullyLoggedInBeforeAsync(account, randomCookiesHash); Assert.True(cookieAlreadyPresentOnSecondTest); }
public async Task AddIncorrectPhase2HashAsync() { Init(); string username = "******"; string password = "******"; DbUserAccount account = userAccountController.Create(username, password); string incorrectPasswordHash = Convert.ToBase64String(StrongRandomNumberGenerator.GetBytes(16)); bool incorrectPasswordAlreadyPresentOnFirstTest = await userAccountController.AddIncorrectPhaseTwoHashAsync(account, incorrectPasswordHash); Assert.False(incorrectPasswordAlreadyPresentOnFirstTest); // Since the hash is added via a background task to minimize response latency, we'll want to // wait to be sure it's added Thread.Sleep(1000); bool incorrectPasswordPresentOnSecondTest = await userAccountController.AddIncorrectPhaseTwoHashAsync(account, incorrectPasswordHash); Assert.True(incorrectPasswordPresentOnSecondTest); }
public SimulatedLoginAttempt(SimulatedUserAccount account, string password, bool isFromAttacker, bool isGuess, IPAddress clientAddress, string cookieProvidedByBrowser, string mistakeType, DateTime eventTimeUtc ) { SimAccount = account; UserNameOrAccountId = account != null ? account.UsernameOrAccountId : StrongRandomNumberGenerator.Get64Bits().ToString(); IsPasswordValid = account != null && account.Password == password; AddressOfClientInitiatingRequest = clientAddress; TimeOfAttemptUtc = eventTimeUtc; CookieProvidedByBrowser = cookieProvidedByBrowser; Password = password; IsFromAttacker = isFromAttacker; IsGuess = isGuess; MistakeType = mistakeType; }
/// <summary> /// When one Adds an element to a binomial sketch, a random bit among the subset of k that are currently 0 (false) /// will be set to 1 (true). /// To ensure roughly half the bits remain zero at all times, a random index from the subset of all k bits that /// are currently 1 (true) will be set to 0 (false). /// </summary> /// <param name="key">The element to add to the set.</param> /// <param name="heightOfLadderInRungs">Set if using a ladder shorter than the default for this sketch</param> /// <returns>Of the bits at the indices for the given element, the number of bits that were set to 1 (true) /// before the Step operation. The maximum possible value to be returned, if all bits were already /// set to 1 (true) would be MaxLadderHeightInRungs. If an element has not been seen before, the expected (average) /// result is MaxLadderHeightInRungs/2, but will vary with the binomial distribution.</returns> public int Step(string key, int?heightOfLadderInRungs = null) { // Get the set of rungs List <int> rungs = GetIndexesAssociatedWithAnElement(key, heightOfLadderInRungs).ToList(); // Select the subset of rungs that have value zero (that are above the element in the ladder) List <int> rungsAbove = rungs.Where(rung => !base[rung]).ToList(); // Identify an element of the array to set int indexOfElementToSet = (rungsAbove.Count > 0) ? // If there are rungs with value value zero/false (rungs above the element), pick one at random rungsAbove[(int)(StrongRandomNumberGenerator.Get32Bits((uint)rungsAbove.Count))] : // otherwise, pick an element with value zero/false from the entire array GetIndexOfRandomBitOfDesiredValue(false); // Identify an index to clear from the entire array (selected from those elements with value 1/true) int indexOfElementToClear = GetIndexOfRandomBitOfDesiredValue(true); // Swap the values of element to be set with the element to be cleared SwapBits(indexOfElementToSet, indexOfElementToClear); // Return the height of the ladder before the step return(rungs.Count - rungsAbove.Count); }
public FilterArray(int numberOfBitsInArray, int maximumBitIndexesPerElement, bool initilizeBitsOfArrayAtRandom, string saltForHashFunctions = "") { int capacityInBytes = (numberOfBitsInArray + 7) / 8; HashFunctionsMappingElementsToBitsInTheArray = new UniversalHashFunction[maximumBitIndexesPerElement]; for (int i = 0; i < HashFunctionsMappingElementsToBitsInTheArray.Length; i++) { HashFunctionsMappingElementsToBitsInTheArray[i] = new UniversalHashFunction(i + ":" + saltForHashFunctions, 64); } if (initilizeBitsOfArrayAtRandom) { byte[] initialBitValues = new byte[capacityInBytes]; StrongRandomNumberGenerator.GetBytes(initialBitValues); BitArray = new BitArray(initialBitValues); } else { BitArray = new BitArray(capacityInBytes * 8); } }
/// <summary> /// Get a new IP address for use in a benign request /// </summary> /// <returns>An IP address</returns> public IPAddress GetNewRandomBenignIp() { IpAddressDebugInfo debugInfo; if (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.FractionOfBenignIPsBehindProxies) { // Use a proxy IP address lock (_proxyAddressLock) { if (_currentProxyAddress == null || ++_numberOfClientsBehindTheCurrentProxy >= _experimentalConfiguration.ProxySizeInUniqueClientIPs) { // Create a new proxy IP address _currentProxyAddress = new IPAddress(StrongRandomNumberGenerator.Get32Bits()); debugInfo = GetIpAddressDebugInfo(_currentProxyAddress); debugInfo.IsPartOfProxy = true; debugInfo.UsedByBenignUsers = true; _numberOfClientsBehindTheCurrentProxy = 0; return(_currentProxyAddress); } else { // Use the most recent proxy IP return(_currentProxyAddress); } } } else { // Just pick a random address IPAddress address = new IPAddress(StrongRandomNumberGenerator.Get32Bits()); _ipAddresssesInUseByBenignUsers.Add(address); debugInfo = GetIpAddressDebugInfo(address); debugInfo.UsedByBenignUsers = true; return(address); } }
public int GetRandomShardIndex() { return((int)StrongRandomNumberGenerator.Get32Bits(NumberOfShards)); }
/// <summary> /// Evaluate the accuracy of our stopguessing service by sending user logins and malicious traffic /// </summary> /// <returns></returns> public async Task Run(CancellationToken cancellationToken = default(CancellationToken)) { _logger.WriteStatus("In RunInBackground"); _logger.WriteStatus("Priming password-tracking with known common passwords"); _simPasswords.PrimeWithKnownPasswordsAsync(_binomialLadderFilter, 40); _logger.WriteStatus("Finished priming password-tracking with known common passwords"); _logger.WriteStatus("Creating IP Pool"); _ipPool = new IpPool(_experimentalConfiguration); _logger.WriteStatus("Generating simualted account records"); _simAccounts = new SimulatedAccounts(_ipPool, _simPasswords, _logger); await _simAccounts.GenerateAsync(_experimentalConfiguration, cancellationToken); _logger.WriteStatus("Creating login-attempt generator"); _attemptGenerator = new SimulatedLoginAttemptGenerator(_experimentalConfiguration, _simAccounts, _ipPool, _simPasswords); _logger.WriteStatus("Finiished creating login-attempt generator"); foreach (TextWriter writer in new TextWriter[] { _AttackAttemptsWithValidPasswords, _LegitiamteAttemptsWithValidPasswords, _OtherAttempts }) { writer.WriteLine("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9}", //,{9} "Password", "UserID", "IP", "IsFrequentlyGuessedPw", "IsPasswordCorrect", "IsFromAttackAttacker", "IsAGuess", "IPInOposingPool", "IsClientAProxyIP", "TypeOfMistake" //string.Join(",") ); } TimeSpan testTimeSpan = _experimentalConfiguration.TestTimeSpan; double ticksBetweenLogins = ((double)testTimeSpan.Ticks) / (double)_experimentalConfiguration.TotalLoginAttemptsToIssue; await TaskParalllel.RepeatWithWorkers(_experimentalConfiguration.TotalLoginAttemptsToIssue, async (count, cancelToken) => { if (count % 10000 == 0) { _logger.WriteStatus("Login Attempt {0:N0}", count); } DateTime eventTimeUtc = StartTimeUtc.AddTicks((long)(ticksBetweenLogins *count)); SimulatedLoginAttempt simAttempt; if (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.FractionOfLoginAttemptsFromAttacker) { switch (_experimentalConfiguration.AttackersStrategy) { case ExperimentalConfiguration.AttackStrategy.UseUntilLikelyPopular: simAttempt = _attemptGenerator.MaliciousLoginAttemptBreadthFirstAvoidMakingPopular(eventTimeUtc); break; case ExperimentalConfiguration.AttackStrategy.Weighted: simAttempt = _attemptGenerator.MaliciousLoginAttemptWeighted(eventTimeUtc); break; case ExperimentalConfiguration.AttackStrategy.BreadthFirst: default: simAttempt = _attemptGenerator.MaliciousLoginAttemptBreadthFirst(eventTimeUtc); break; } } else { simAttempt = _attemptGenerator.BenignLoginAttempt(eventTimeUtc); } // Get information about the client's IP SimIpHistory ipHistory = await _ipHistoryCache.GetAsync(simAttempt.AddressOfClientInitiatingRequest, cancelToken); double[] scores = ipHistory.GetAllScores(_experimentalConfiguration.BlockingOptions.BlockScoreHalfLife, simAttempt.TimeOfAttemptUtc); simAttempt.UpdateSimulatorState(this, ipHistory); var ipInfo = _ipPool.GetIpAddressDebugInfo(simAttempt.AddressOfClientInitiatingRequest); string outputString = string.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10}", simAttempt.Password, simAttempt.SimAccount?.UsernameOrAccountId ?? "<null>", simAttempt.AddressOfClientInitiatingRequest, simAttempt.IsFrequentlyGuessedPassword ? "Frequent" : "Infrequent", simAttempt.IsPasswordValid ? "Correct" : "Incorrect", simAttempt.IsFromAttacker ? "FromAttacker" : "FromUser", simAttempt.IsGuess ? "IsGuess" : "NotGuess", simAttempt.IsFromAttacker ? (ipInfo.UsedByBenignUsers ? "IsInBenignPool" : "NotUsedByBenign") : (ipInfo.UsedByAttackers ? "IsInAttackersIpPool" : "NotUsedByAttacker"), ipInfo.IsPartOfProxy ? "ProxyIP" : "NotAProxy", string.IsNullOrEmpty(simAttempt.MistakeType) ? "-" : simAttempt.MistakeType, string.Join(",", scores.Select(s => s.ToString(CultureInfo.InvariantCulture)).ToArray()) ); if (simAttempt.IsFromAttacker && simAttempt.IsPasswordValid) { await _AttackAttemptsWithValidPasswords.WriteLineAsync(outputString); await _AttackAttemptsWithValidPasswords.FlushAsync(); } else if (!simAttempt.IsFromAttacker && simAttempt.IsPasswordValid) { await _LegitiamteAttemptsWithValidPasswords.WriteLineAsync(outputString); await _LegitiamteAttemptsWithValidPasswords.FlushAsync(); } else { await _OtherAttempts.WriteLineAsync(outputString); await _OtherAttempts.FlushAsync(); } }, //(e) => { //}, cancellationToken : cancellationToken); _memoryUsageLimiter.Dispose(); }
/// <summary> /// Evaluate the accuracy of our stopguessing service by sending user logins and malicious traffic /// </summary> /// <returns></returns> public void Run() { _logger.WriteStatus("In RunInBackground"); _logger.WriteStatus("Priming password-tracking with known common passwords"); _simPasswords.PrimeWithKnownPasswordsAsync(_binomialLadderFilter, 40); _logger.WriteStatus("Finished priming password-tracking with known common passwords"); _logger.WriteStatus("Creating IP Pool"); _ipPool = new IpPool(_experimentalConfiguration); _logger.WriteStatus("Generating simualted account records"); _simAccounts = new SimulatedAccounts(_ipPool, _simPasswords, _logger); _simAccounts.Generate(_experimentalConfiguration); _logger.WriteStatus("Creating login-attempt generator"); _attemptGenerator = new SimulatedLoginAttemptGenerator(_experimentalConfiguration, _simAccounts, _ipPool, _simPasswords); _logger.WriteStatus("Finiished creating login-attempt generator"); foreach ( ConcurrentStreamWriter writer in new[] { _AttackAttemptsWithValidPasswords, _LegitimateAttemptsWithValidPasswords, _OtherAttempts }) { lock (writer) { writer.WriteLine(string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}" + "\t{11}\t{12}\t{13}\t{14}\t{15}\t{16}\t{17}\t{18}\t{19}\t{20}\t{21}\t{22}\t{23}\t{24}\t{25}", "Password", "UserID", "IP", "DeviceCookie", "IsFrequentlyGuessedPw", "IsPasswordCorrect", "IsFromAttackAttacker", "IsAGuess", "IPInOposingPool", "IsClientAProxyIP", "TypeOfMistake", "DecayedInvalidAttemptsPerPassword", "DecayedMaxConsecutiveIncorrectAttemptsPerAccount", "DecayedSuccessfulLogins", "DecayedAccountFailuresInfrequentPassword", "DecayedAccountFailuresFrequentPassword", "DecayedRepeatAccountFailuresInfrequentPassword", "DecayedRepeatAccountFailuresFrequentPassword", "DecayedPasswordFailuresNoTypoInfrequentPassword", "DecayedPasswordFailuresNoTypoFrequentPassword", "DecayedPasswordFailuresTypoInfrequentPassword", "DecayedPasswordFailuresTypoFrequentPassword", "DecayedRepeatPasswordFailuresNoTypoInfrequentPassword", "DecayedRepeatPasswordFailuresNoTypoFrequentPassword", "DecayedRepeatPasswordFailuresTypoInfrequentPassword", "DecayedRepeatPasswordFailuresTypoFrequentPassword" )); } } TimeSpan testTimeSpan = _experimentalConfiguration.TestTimeSpan; double ticksBetweenLogins = ((double)testTimeSpan.Ticks) / (double)_experimentalConfiguration.TotalLoginAttemptsToIssue; int interlockedCount = 0; Parallel.For(0L, (long)_experimentalConfiguration.TotalLoginAttemptsToIssue, (count, pls) => //) TaskParalllel.RepeatWithWorkers(_experimentalConfiguration.TotalLoginAttemptsToIssue, //async (count, cancelToken) => // (count) => { interlockedCount = Interlocked.Add(ref interlockedCount, 1); if (interlockedCount % 10000 == 0) { _logger.WriteStatus("Login Attempt {0:N0}", interlockedCount); } DateTime eventTimeUtc = StartTimeUtc.AddTicks((long)(ticksBetweenLogins * interlockedCount)); SimulatedLoginAttempt simAttempt; if (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.FractionOfLoginAttemptsFromAttacker) { switch (_experimentalConfiguration.AttackersStrategy) { case ExperimentalConfiguration.AttackStrategy.UseUntilLikelyPopular: simAttempt = _attemptGenerator.MaliciousLoginAttemptBreadthFirstAvoidMakingPopular(eventTimeUtc); break; case ExperimentalConfiguration.AttackStrategy.Weighted: simAttempt = _attemptGenerator.MaliciousLoginAttemptWeighted(eventTimeUtc); break; case ExperimentalConfiguration.AttackStrategy.BreadthFirst: default: simAttempt = _attemptGenerator.MaliciousLoginAttemptBreadthFirst(eventTimeUtc); break; } } else { simAttempt = _attemptGenerator.BenignLoginAttempt(eventTimeUtc); } // Get information about the client's IP SimIpHistory ipHistory = _ipHistoryCache.GetOrAdd(simAttempt.AddressOfClientInitiatingRequest, (ip) => new SimIpHistory( _experimentalConfiguration.BlockingOptions .NumberOfFailuresToTrackForGoingBackInTimeToIdentifyTypos)); //SimIpHistory ipHistory = await _ipHistoryCache.GetAsync(simAttempt.AddressOfClientInitiatingRequest, cancelToken); double[] scores = ipHistory.GetAllScores(_experimentalConfiguration.BlockingOptions.BlockScoreHalfLife, simAttempt.TimeOfAttemptUtc); simAttempt.UpdateSimulatorState(this, ipHistory); double decayingInvalidPasswordAttempts = 0d; if (simAttempt.IsPasswordValid) { DecayingDouble incorrectPasswordAttempts; if (_incorrectPasswordCounts.TryGetValue(simAttempt.Password, out incorrectPasswordAttempts)) { decayingInvalidPasswordAttempts = incorrectPasswordAttempts.GetValue(_experimentalConfiguration.BlockingOptions.BlockScoreHalfLife, simAttempt.TimeOfAttemptUtc); } } else { decayingInvalidPasswordAttempts = 1d; DecayingDouble incorrectPasswordAttempts; if (_incorrectPasswordCounts.TryGetValue(simAttempt.Password, out incorrectPasswordAttempts)) { decayingInvalidPasswordAttempts += incorrectPasswordAttempts.GetValue(_experimentalConfiguration.BlockingOptions.BlockScoreHalfLife, simAttempt.TimeOfAttemptUtc); } _incorrectPasswordCounts[simAttempt.Password] = new DecayingDouble(decayingInvalidPasswordAttempts, simAttempt.TimeOfAttemptUtc); } var ipInfo = _ipPool.GetIpAddressDebugInfo(simAttempt.AddressOfClientInitiatingRequest); string outputString = string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}\t{11}\t{12}\t{13}", simAttempt.Password, simAttempt.SimAccount?.UsernameOrAccountId ?? "<null>", simAttempt.AddressOfClientInitiatingRequest, simAttempt.DeviceCookieHadPriorSuccessfulLoginForThisAccount ? "HadCookie" : "NoCookie", simAttempt.IsFrequentlyGuessedPassword ? "Frequent" : "Infrequent", simAttempt.IsPasswordValid ? "Correct" : "Incorrect", simAttempt.IsFromAttacker ? "FromAttacker" : "FromUser", simAttempt.IsGuess ? "IsGuess" : "NotGuess", simAttempt.IsFromAttacker ? (ipInfo.UsedByBenignUsers ? "IsInBenignPool" : "NotUsedByBenign") : (ipInfo.UsedByAttackers ? "IsInAttackersIpPool" : "NotUsedByAttacker"), ipInfo.IsPartOfProxy ? "ProxyIP" : "NotAProxy", string.IsNullOrEmpty(simAttempt.MistakeType) ? "-" : simAttempt.MistakeType, decayingInvalidPasswordAttempts, simAttempt.SimAccount?.MaxConsecutiveIncorrectAttempts.GetValue(_experimentalConfiguration.BlockingOptions.BlockScoreHalfLife, simAttempt.TimeOfAttemptUtc) ?? 0d, string.Join("\t", scores.Select(s => s.ToString(CultureInfo.InvariantCulture)).ToArray()) ); if (simAttempt.IsFromAttacker && simAttempt.IsPasswordValid) { lock (_AttackAttemptsWithValidPasswords) { _AttackAttemptsWithValidPasswords.WriteLine(outputString); //_AttackAttemptsWithValidPasswords.Flush(); } } else if (!simAttempt.IsFromAttacker && simAttempt.IsPasswordValid) { lock (_LegitimateAttemptsWithValidPasswords) { _LegitimateAttemptsWithValidPasswords.WriteLine(outputString); //_LegitiamteAttemptsWithValidPasswords.Flush(); } } else { lock (_OtherAttempts) { _OtherAttempts.WriteLine(outputString); //_OtherAttempts.Flush(); } } }); //(e) => { //}, //cancellationToken: cancellationToken).ConfigureAwait(false); foreach ( ConcurrentStreamWriter writer in new [] { _AttackAttemptsWithValidPasswords, _LegitimateAttemptsWithValidPasswords, _OtherAttempts }) { writer.Close(); } //_memoryUsageLimiter.Dispose(); }
/// <summary> /// Get a benign login attempt to simulate /// </summary> /// <returns></returns> public SimulatedLoginAttempt BenignLoginAttempt(DateTime eventTimeUtc) { // If there is a benign login attempt already scheduled to occur by now, // send it instaed lock (ScheduledBenignAttempts) { if (ScheduledBenignAttempts.Count > 0 && ScheduledBenignAttempts.First().TimeOfAttemptUtc < eventTimeUtc) { SimulatedLoginAttempt result = ScheduledBenignAttempts.First(); ScheduledBenignAttempts.Remove(result); return(result); } } string mistake = ""; //1. Pick a user at random SimulatedUserAccount account = _simAccounts.BenignAccountSelector.GetItemByWeightedRandom(); //2. Deal with cookies string cookie; // Add a new cookie if there are no cookies, or with if we haven't reached the max number of cookies and lose a roll of the dice if (account.Cookies.Count == 0 || (account.Cookies.Count < _experimentalConfiguration.MaxCookiesPerUserAccount && StrongRandomNumberGenerator.GetFraction() > _experimentalConfiguration.ChanceOfCoookieReUse)) { // We'll use the decimal represenation of a 64-bit unsigned integer as our cookie cookie = StrongRandomNumberGenerator.Get64Bits().ToString(); account.Cookies.Add(cookie); } else { // Use one of the user's existing cookies selected at random cookie = account.Cookies.ToArray()[(int)StrongRandomNumberGenerator.Get32Bits(account.Cookies.Count)]; } //Console.WriteLine("The user currently has " + account.Cookies.Count + " cookies. Using: " + cookie); //3. Choose an IP address for the login // 1/3 of times login with the primary IP address, otherwise, choose an IP randomly from the benign IP pool IPAddress clientIp; if (account.ClientAddresses.Count == 0 || (account.ClientAddresses.Count < _experimentalConfiguration.MaxIpPerUserAccount && StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfIpReUse)) { // Use a new IP for the user account.ClientAddresses.Add(clientIp = _ipPool.GetNewRandomBenignIp()); } else { // Use one of the user's existing IP Addresses selected at random clientIp = account.ClientAddresses.ToArray()[(int)StrongRandomNumberGenerator.Get32Bits(account.ClientAddresses.Count)]; } string password = account.Password; // // Add benign failures // An automated client begins a string of login attempts using an old (stale) password if (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfLongRepeatOfStalePassword) { // To cause this client to be out of date, we'll change the password here. string newPassword = _simPasswords.GetPasswordFromWeightedDistribution(); _userAccountController.SetPassword(account, newPassword, account.Password); mistake += "StalePassword"; // Schedule all the future failed attempts a fixed distance aparat lock (ScheduledBenignAttempts) { double additionalMistakes = 0; DateTime currentTimeUtc = eventTimeUtc; for (additionalMistakes = 1; additionalMistakes < _experimentalConfiguration.LengthOfLongRepeatOfOldPassword; additionalMistakes++) { currentTimeUtc = currentTimeUtc.AddSeconds(_experimentalConfiguration.MinutesBetweenLongRepeatOfOldPassword); ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( account, password, false, false, clientIp, cookie, mistake, currentTimeUtc)); } for (uint correctLogins = 1; correctLogins < _experimentalConfiguration.LengthOfLongRepeatOfOldPassword; correctLogins++) { currentTimeUtc = currentTimeUtc.AddSeconds(_experimentalConfiguration.MinutesBetweenLongRepeatOfOldPassword); ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( account, newPassword, false, false, clientIp, cookie, mistake, currentTimeUtc)); } } } // The benign user may mistype her password causing a typo if (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfBenignPasswordTypo) { mistake += "Typo"; // Typos tend to come in clusters, and are hopefully followed by a correct login // Add additional typos to the schedule of future benign attempts and then a submission of the correct password lock (ScheduledBenignAttempts) { double additionalMistakes = 0; while (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfRepeatTypo) { ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( account, AddTypoToPassword(password), false, false, clientIp, cookie, mistake, eventTimeUtc.AddSeconds(_experimentalConfiguration.DelayBetweenRepeatBenignErrorsInSeconds * ++additionalMistakes))); } // Add a correct login after the string of typos ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( account, password, false, false, clientIp, cookie, "", eventTimeUtc.AddSeconds( _experimentalConfiguration.DelayBetweenRepeatBenignErrorsInSeconds * (1 + additionalMistakes)))); } // Put the typo into the password for the first typo failure, to be returned by this function. password = AddTypoToPassword(password); } // The benign user may mistakenly use a password for another of her accounts, which we draw from same distribution // we used to generate user account passwords if (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfAccidentallyUsingAnotherAccountPassword) { mistake += "WrongPassword"; // Choices of the wrong account password may come in clusters, and are hopefully followed by a correct login // Add additional typos to the schedule of future benign attempts and then a submission of the correct password lock (ScheduledBenignAttempts) { double additionalMistakes = 0; while (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfRepeatUseOfPasswordFromAnotherAccount) { ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( account, _simPasswords.GetPasswordFromWeightedDistribution(), false, false, clientIp, cookie, mistake, eventTimeUtc.AddSeconds(_experimentalConfiguration.DelayBetweenRepeatBenignErrorsInSeconds * ++additionalMistakes))); } // Add a correct login after mistakes ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( account, password, false, false, clientIp, cookie, "", eventTimeUtc.AddSeconds( _experimentalConfiguration.DelayBetweenRepeatBenignErrorsInSeconds * (additionalMistakes + 1)))); } // Make the current request have the wrong password password = _simPasswords.GetPasswordFromWeightedDistribution(); } // The benign user may mistype her account name, and land on someone else's account name if (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfBenignAccountNameTypoResultingInAValidUserName) { mistake += "WrongAccountName"; // Choices of the wrong account password may come in clusters, and are hopefully followed by a correct login // Add additional typos to the schedule of future benign attempts and then a submission of the correct password lock (ScheduledBenignAttempts) { double additionalMistakes = 0; while (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfRepeatWrongAccountName) { ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( _simAccounts.GetBenignAccountAtRandomUniform(), password, false, false, clientIp, cookie, mistake, eventTimeUtc.AddSeconds( _experimentalConfiguration.DelayBetweenRepeatBenignErrorsInSeconds * ++additionalMistakes))); } // Add a correct login after mistakes ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( account, password, false, false, clientIp, cookie, "", eventTimeUtc.AddSeconds( _experimentalConfiguration.DelayBetweenRepeatBenignErrorsInSeconds * (additionalMistakes + 1)))); // Make the current request have the wrong account name account = _simAccounts.GetBenignAccountAtRandomUniform(); } } return(new SimulatedLoginAttempt(account, password, false, false, clientIp, cookie, mistake, eventTimeUtc)); }
/// <summary> /// Clear a randomly-selected bit of the filter array to zero. /// </summary> public void ClearRandomBitToZero() { ClearBitToZero((int)StrongRandomNumberGenerator.Get32Bits((uint)BitArray.Length)); }
/// <summary> /// Set a randomly-selected bit of the filter array to one. /// </summary> public void SetRandomBitToOne() { SetBitToOne((int)StrongRandomNumberGenerator.Get32Bits((uint)BitArray.Length)); }
/// <summary> /// Create accounts, generating passwords, primary IP /// </summary> #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously public async Task GenerateAsync(ExperimentalConfiguration experimentalConfiguration, #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously //IUserAccountContextFactory accountContextFactory, CancellationToken cancellationToken = default(CancellationToken)) { _logger.WriteStatus("Creating {0:N0} benign accounts", experimentalConfiguration.NumberOfBenignAccounts); MemoryUserAccountController userAccountController = new MemoryUserAccountController();; ConcurrentBag <SimulatedUserAccount> benignSimulatedAccountBag = new ConcurrentBag <SimulatedUserAccount>(); // // Create benign accounts in parallel Parallel.For(0, (int)experimentalConfiguration.NumberOfBenignAccounts, (index) => { if (index > 0 && index % 10000 == 0) { _logger.WriteStatus("Created {0:N0} benign accounts", index); } SimulatedUserAccount userAccount = new SimulatedUserAccount() { UsernameOrAccountId = "user_" + index.ToString(), Password = _simPasswords.GetPasswordFromWeightedDistribution() }; userAccount.ClientAddresses.Add(_ipPool.GetNewRandomBenignIp()); userAccount.Cookies.Add(StrongRandomNumberGenerator.Get64Bits().ToString()); benignSimulatedAccountBag.Add(userAccount); double inverseFrequency = Distributions.GetLogNormal(0, 1); if (inverseFrequency < 0.01d) { inverseFrequency = 0.01d; } if (inverseFrequency > 50d) { inverseFrequency = 50d; } double frequency = 1 / inverseFrequency; lock (BenignAccountSelector) { BenignAccountSelector.AddItem(userAccount, frequency); } }); BenignAccounts = benignSimulatedAccountBag.ToList(); _logger.WriteStatus("Finished creating {0:N0} benign accounts", experimentalConfiguration.NumberOfBenignAccounts); // // Right after creating benign accounts we create IPs and accounts controlled by the attacker. // (We create the attacker IPs here, and not earlier, because we need to have the benign IPs generated in order to create overlap) _logger.WriteStatus("Creating attacker IPs"); _ipPool.GenerateAttackersIps(); _logger.WriteStatus("Creating {0:N0} attacker accounts", experimentalConfiguration.NumberOfAttackerControlledAccounts); ConcurrentBag <SimulatedUserAccount> maliciousSimulatedAccountBag = new ConcurrentBag <SimulatedUserAccount>(); // // Create accounts in parallel Parallel.For(0, (int)experimentalConfiguration.NumberOfAttackerControlledAccounts, (index) => { SimulatedUserAccount userAccount = new SimulatedUserAccount() { UsernameOrAccountId = "attacker_" + index.ToString(), Password = _simPasswords.GetPasswordFromWeightedDistribution(), }; userAccount.ClientAddresses.Add(_ipPool.GetRandomMaliciousIp()); maliciousSimulatedAccountBag.Add(userAccount); }); AttackerAccounts = maliciousSimulatedAccountBag.ToList(); _logger.WriteStatus("Finished creating {0:N0} attacker accounts", experimentalConfiguration.NumberOfAttackerControlledAccounts); // // Now create full UserAccount records for each simulated account and store them into the account context Parallel.ForEach(BenignAccounts.Union(AttackerAccounts), (simAccount, loopState) => { //if (loopState. % 10000 == 0) // _logger.WriteStatus("Created account {0:N0}", index); simAccount.CreditHalfLife = experimentalConfiguration.BlockingOptions.AccountCreditLimitHalfLife; simAccount.CreditLimit = experimentalConfiguration.BlockingOptions.AccountCreditLimit; foreach (string cookie in simAccount.Cookies) { userAccountController.HasClientWithThisHashedCookieSuccessfullyLoggedInBeforeAsync( simAccount, LoginAttempt.HashCookie(cookie), cancellationToken); } }); _logger.WriteStatus("Finished creating user accounts for each simluated account record"); }
public SimulatedUserAccount GetMaliciousAccountAtRandomUniform() { return(AttackerAccounts[(int)StrongRandomNumberGenerator.Get32Bits(AttackerAccounts.Count)]); }
public SimulatedUserAccount GetBenignAccountAtRandomUniform() { return(BenignAccounts[(int)StrongRandomNumberGenerator.Get32Bits(BenignAccounts.Count)]); }
public void Generate(ExperimentalConfiguration experimentalConfiguration) { SimulatedUserAccountController simUserAccountController = new SimulatedUserAccountController(); _logger.WriteStatus("Creating accounts"); ConcurrentBag <SimulatedUserAccount> benignSimulatedAccountBag = new ConcurrentBag <SimulatedUserAccount>(); Parallel.For(0, (int)experimentalConfiguration.NumberOfBenignAccounts, (index) => { //if (index > 0 && index % 10000 == 0) // _logger.WriteStatus("Created {0:N0} benign accounts", index); SimulatedUserAccount userAccount = simUserAccountController.Create( "user_" + index.ToString(), _simPasswords.GetPasswordFromWeightedDistribution() ); userAccount.ClientAddresses.Add(_ipPool.GetNewRandomBenignIp()); string initialCookie = StrongRandomNumberGenerator.Get64Bits().ToString(); userAccount.Cookies.Add(initialCookie); userAccount.HashesOfCookiesOfClientsThatHaveSuccessfullyLoggedIntoThisAccount[initialCookie] = true; benignSimulatedAccountBag.Add(userAccount); double inverseFrequency = Distributions.GetLogNormal(0, 1); if (inverseFrequency < 0.01d) { inverseFrequency = 0.01d; } if (inverseFrequency > 50d) { inverseFrequency = 50d; } double frequency = 1 / inverseFrequency; lock (BenignAccountSelector) { BenignAccountSelector.AddItem(userAccount, frequency); } }); BenignAccounts = benignSimulatedAccountBag.ToList(); // _logger.WriteStatus("Finished creating {0:N0} benign accounts", // experimentalConfiguration.NumberOfBenignAccounts); //_logger.WriteStatus("Creating attacker IPs"); _ipPool.GenerateAttackersIps(); //_logger.WriteStatus("Creating {0:N0} attacker accounts", // experimentalConfiguration.NumberOfAttackerControlledAccounts); ConcurrentBag <SimulatedUserAccount> maliciousSimulatedAccountBag = new ConcurrentBag <SimulatedUserAccount>(); Parallel.For(0, (int)experimentalConfiguration.NumberOfAttackerControlledAccounts, (index) => { SimulatedUserAccount userAccount = simUserAccountController.Create( "attacker_" + index.ToString(), _simPasswords.GetPasswordFromWeightedDistribution()); userAccount.ClientAddresses.Add(_ipPool.GetRandomMaliciousIp()); maliciousSimulatedAccountBag.Add(userAccount); }); AttackerAccounts = maliciousSimulatedAccountBag.ToList(); _logger.WriteStatus("Finished creating accounts", experimentalConfiguration.NumberOfAttackerControlledAccounts); Parallel.ForEach(BenignAccounts.Union(AttackerAccounts), (simAccount, loopState) => { simAccount.CreditHalfLife = experimentalConfiguration.BlockingOptions.AccountCreditLimitHalfLife; simAccount.CreditLimit = experimentalConfiguration.BlockingOptions.AccountCreditLimit; foreach (string cookie in simAccount.Cookies) { simUserAccountController.HasClientWithThisHashedCookieSuccessfullyLoggedInBefore( simAccount, LoginAttempt.HashCookie(cookie)); } }); //_logger.WriteStatus("Finished creating user accounts for each simluated account record"); }
/// <summary> /// Assign the value of either zero or one to a randomly-selected bit of the filter array. /// </summary> /// <param name="value">The value to be assigned. Passing 0 causes a value 0 (false) to be stored /// and passing any other value causes a one (true) to be stored in the randomly-selected bit.</param> public void AssignRandomBit(int value) { AssignBit((int)StrongRandomNumberGenerator.Get32Bits((uint)BitArray.Length), value != 0); }
public static string AddTypoToPassword(string originalPassword) { const string typoAlphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./"; return(originalPassword + typoAlphabet[(int)StrongRandomNumberGenerator.Get32Bits(typoAlphabet.Length)]); }
public SimulatedLoginAttempt BenignLoginAttempt(DateTime eventTimeUtc) { lock (ScheduledBenignAttempts) { if (ScheduledBenignAttempts.Count > 0 && ScheduledBenignAttempts.First().TimeOfAttemptUtc < eventTimeUtc) { SimulatedLoginAttempt result = ScheduledBenignAttempts.First(); ScheduledBenignAttempts.Remove(result); return(result); } } string mistake = ""; SimulatedUserAccount account = _simAccounts.BenignAccountSelector.GetItemByWeightedRandom(); string cookie; if (account.Cookies.Count == 0 || (account.Cookies.Count < _experimentalConfiguration.MaxCookiesPerUserAccount && StrongRandomNumberGenerator.GetFraction() > _experimentalConfiguration.ChanceOfCoookieReUse)) { cookie = StrongRandomNumberGenerator.Get64Bits().ToString(); account.Cookies.Add(cookie); } else { cookie = account.Cookies.ToArray()[(int)StrongRandomNumberGenerator.Get32Bits(account.Cookies.Count)]; } IPAddress clientIp; if (account.ClientAddresses.Count == 0 || (account.ClientAddresses.Count < _experimentalConfiguration.MaxIpPerUserAccount && StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfIpReUse)) { account.ClientAddresses.Add(clientIp = _ipPool.GetNewRandomBenignIp()); } else { clientIp = account.ClientAddresses.ToArray()[(int)StrongRandomNumberGenerator.Get32Bits(account.ClientAddresses.Count)]; } string password = account.Password; if (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfLongRepeatOfStalePassword) { string newPassword = _simPasswords.GetPasswordFromWeightedDistribution(); _userAccountController.SetPassword(account, newPassword, account.Password); mistake += "StalePassword"; lock (ScheduledBenignAttempts) { double additionalMistakes = 0; DateTime currentTimeUtc = eventTimeUtc; for (additionalMistakes = 1; additionalMistakes < _experimentalConfiguration.LengthOfLongRepeatOfOldPassword; additionalMistakes++) { currentTimeUtc = currentTimeUtc.AddSeconds(_experimentalConfiguration.MinutesBetweenLongRepeatOfOldPassword); ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( account, password, false, false, clientIp, cookie, mistake, currentTimeUtc)); } for (uint correctLogins = 1; correctLogins < _experimentalConfiguration.LengthOfLongRepeatOfOldPassword; correctLogins++) { currentTimeUtc = currentTimeUtc.AddSeconds(_experimentalConfiguration.MinutesBetweenLongRepeatOfOldPassword); ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( account, newPassword, false, false, clientIp, cookie, mistake, currentTimeUtc)); } } } if (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfBenignPasswordTypo) { mistake += "Typo"; lock (ScheduledBenignAttempts) { double additionalMistakes = 0; while (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfRepeatTypo) { ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( account, AddTypoToPassword(password), false, false, clientIp, cookie, mistake, eventTimeUtc.AddSeconds(_experimentalConfiguration.DelayBetweenRepeatBenignErrorsInSeconds * ++additionalMistakes))); } ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( account, password, false, false, clientIp, cookie, "", eventTimeUtc.AddSeconds( _experimentalConfiguration.DelayBetweenRepeatBenignErrorsInSeconds * (1 + additionalMistakes)))); } password = AddTypoToPassword(password); } if (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfAccidentallyUsingAnotherAccountPassword) { mistake += "WrongPassword"; lock (ScheduledBenignAttempts) { double additionalMistakes = 0; while (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfRepeatUseOfPasswordFromAnotherAccount) { ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( account, _simPasswords.GetPasswordFromWeightedDistribution(), false, false, clientIp, cookie, mistake, eventTimeUtc.AddSeconds(_experimentalConfiguration.DelayBetweenRepeatBenignErrorsInSeconds * ++additionalMistakes))); } ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( account, password, false, false, clientIp, cookie, "", eventTimeUtc.AddSeconds( _experimentalConfiguration.DelayBetweenRepeatBenignErrorsInSeconds * (additionalMistakes + 1)))); } password = _simPasswords.GetPasswordFromWeightedDistribution(); } if (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfBenignAccountNameTypoResultingInAValidUserName) { mistake += "WrongAccountName"; lock (ScheduledBenignAttempts) { double additionalMistakes = 0; while (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.ChanceOfRepeatWrongAccountName) { ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( _simAccounts.GetBenignAccountAtRandomUniform(), password, false, false, clientIp, cookie, mistake, eventTimeUtc.AddSeconds( _experimentalConfiguration.DelayBetweenRepeatBenignErrorsInSeconds * ++additionalMistakes))); } ScheduledBenignAttempts.Add(new SimulatedLoginAttempt( account, password, false, false, clientIp, cookie, "", eventTimeUtc.AddSeconds( _experimentalConfiguration.DelayBetweenRepeatBenignErrorsInSeconds * (additionalMistakes + 1)))); account = _simAccounts.GetBenignAccountAtRandomUniform(); } } return(new SimulatedLoginAttempt(account, password, false, false, clientIp, cookie, mistake, eventTimeUtc)); }
public async Task RunAsync() { _logger.WriteStatus("In RunInBackground"); //_logger.WriteStatus("Priming password-tracking with known common passwords"); _simPasswords.PrimeWithKnownPasswordsAsync(_binomialLadderFilter, 40); //_logger.WriteStatus("Finished priming password-tracking with known common passwords"); //_logger.WriteStatus("Creating IP Pool"); _ipPool = new IpPool(_experimentalConfiguration); //_logger.WriteStatus("Generating simualted account records"); _simAccounts = new SimulatedAccounts(_ipPool, _simPasswords, _logger); _simAccounts.Generate(_experimentalConfiguration); //_logger.WriteStatus("Creating login-attempt generator"); _attemptGenerator = new SimulatedLoginAttemptGenerator(_experimentalConfiguration, _simAccounts, _ipPool, _simPasswords); _logger.WriteStatus("Finiished creating login-attempt generator"); FricSimulator fri = new FricSimulator(); _logger.WriteStatus(" "); _logger.WriteStatus(" "); _logger.WriteStatus("Click Enter To First Testing Step"); _logger.WriteStatus(" "); _logger.WriteStatus(" "); Console.Read(); await fri.RunAsync(_logger, _ipPool); _logger.WriteStatus(" "); _logger.WriteStatus(" "); _logger.WriteStatus("Click Enter To Second Testing Step"); _logger.WriteStatus(" "); _logger.WriteStatus(" "); Console.Read(); Console.Read(); _logger.WriteStatus("Running Password File to check"); _logger.WriteStatus(" "); foreach ( ConcurrentStreamWriter writer in new[] { _Attempts }) { lock (writer) { writer.WriteLine(string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}", "UserID", "IP", "IsFrequentlyGuessedPw", "IsPasswordCorrect", "IsFromAttackAttacker", "IsAGuess" )); } } TimeSpan testTimeSpan = _experimentalConfiguration.TestTimeSpan; double ticksBetweenLogins = ((double)testTimeSpan.Ticks) / (double)_experimentalConfiguration.TotalLoginAttemptsToIssue; _experimentalConfiguration.TotalLoginAttemptsToIssue = 30000; int interlockedCount = 0; Parallel.For(0L, (long)_experimentalConfiguration.TotalLoginAttemptsToIssue, (count, pls) => { interlockedCount = Interlocked.Add(ref interlockedCount, 1); if (interlockedCount % 10000 == 0) { _logger.WriteStatus("Login Attempt {0:N0}", interlockedCount); } DateTime eventTimeUtc = StartTimeUtc.AddTicks((long)(ticksBetweenLogins * interlockedCount)); SimulatedLoginAttempt simAttempt; if (StrongRandomNumberGenerator.GetFraction() < _experimentalConfiguration.FractionOfLoginAttemptsFromAttacker) { switch (_experimentalConfiguration.AttackersStrategy) { case ExperimentalConfiguration.AttackStrategy.UseUntilLikelyPopular: simAttempt = _attemptGenerator.MaliciousLoginAttemptBreadthFirstAvoidMakingPopular(eventTimeUtc); break; case ExperimentalConfiguration.AttackStrategy.Weighted: simAttempt = _attemptGenerator.MaliciousLoginAttemptWeighted(eventTimeUtc); break; case ExperimentalConfiguration.AttackStrategy.BreadthFirst: default: simAttempt = _attemptGenerator.MaliciousLoginAttemptBreadthFirst(eventTimeUtc); break; } } else { simAttempt = _attemptGenerator.BenignLoginAttempt(eventTimeUtc); } SimIpHistory ipHistory = _ipHistoryCache.GetOrAdd(simAttempt.AddressOfClientInitiatingRequest, (ip) => new SimIpHistory( _experimentalConfiguration.BlockingOptions .NumberOfFailuresToTrackForGoingBackInTimeToIdentifyTypos)); double[] scores = ipHistory.GetAllScores(_experimentalConfiguration.BlockingOptions.BlockScoreHalfLife, simAttempt.TimeOfAttemptUtc); simAttempt.UpdateSimulatorState(this, ipHistory); double decayingInvalidPasswordAttempts = 0d; if (simAttempt.IsPasswordValid) { DecayingDouble incorrectPasswordAttempts; if (_incorrectPasswordCounts.TryGetValue(simAttempt.Password, out incorrectPasswordAttempts)) { decayingInvalidPasswordAttempts = incorrectPasswordAttempts.GetValue(_experimentalConfiguration.BlockingOptions.BlockScoreHalfLife, simAttempt.TimeOfAttemptUtc); } } else { decayingInvalidPasswordAttempts = 1d; DecayingDouble incorrectPasswordAttempts; if (_incorrectPasswordCounts.TryGetValue(simAttempt.Password, out incorrectPasswordAttempts)) { decayingInvalidPasswordAttempts += incorrectPasswordAttempts.GetValue(_experimentalConfiguration.BlockingOptions.BlockScoreHalfLife, simAttempt.TimeOfAttemptUtc); } _incorrectPasswordCounts[simAttempt.Password] = new DecayingDouble(decayingInvalidPasswordAttempts, simAttempt.TimeOfAttemptUtc); } var ipInfo = _ipPool.GetIpAddressDebugInfo(simAttempt.AddressOfClientInitiatingRequest); string outputString = string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}", simAttempt.SimAccount?.UsernameOrAccountId ?? "<null>", simAttempt.AddressOfClientInitiatingRequest, simAttempt.IsFrequentlyGuessedPassword ? "Frequent" : "Infrequent", simAttempt.IsPasswordValid ? "Correct" : "Incorrect", simAttempt.IsFromAttacker ? "FromAttacker" : "FromUser", simAttempt.IsGuess ? "IsGuess" : "NotGuess", simAttempt.IsFromAttacker ? (ipInfo.UsedByBenignUsers ? "IsInBenignPool" : "NotUsedByBenign") : (ipInfo.UsedByAttackers ? "IsInAttackersIpPool" : "NotUsedByAttacker"), ipInfo.IsPartOfProxy ? "ProxyIP" : "NotAProxy", string.IsNullOrEmpty(simAttempt.MistakeType) ? "-" : simAttempt.MistakeType, decayingInvalidPasswordAttempts, simAttempt.SimAccount?.MaxConsecutiveIncorrectAttempts.GetValue(_experimentalConfiguration.BlockingOptions.BlockScoreHalfLife, simAttempt.TimeOfAttemptUtc) ?? 0d, string.Join("\t", scores.Select(s => s.ToString(CultureInfo.InvariantCulture)).ToArray()) ); _Attempts.WriteLine(outputString); _logger.WriteStatus(outputString); Thread.Sleep(1300); }); foreach ( ConcurrentStreamWriter writer in new[] { _Attempts }) { writer.Close(); } }