Forum Discussion

zubairrahimsoc's avatar
zubairrahimsoc
Copper Contributor
Jun 16, 2021

Bruteforce Qurey

Is it the right query to know if some one is trying to brute force attempt with 5 failed login attempts.

 

SecurityEvent
| where TimeGenerated >= ago(1d)
| where EventID == 4625
| summarize FailedLogins=count(5) by Account, Computer
| sort by FailedLogins desc

  • PrashTechTalk's avatar
    PrashTechTalk
    Brass Contributor
    There are many ways to achieve this. If it is for AAD then this should work and is generic for any application access that uses AAD accounts.

    let timeframe = <set the time frame window>;
    let threshold = <set max failures>;
    SigninLogs
    | where TimeGenerated >= ago(timeframe)
    | where ResultType in ("50126", "50074")
    | summarize min(TimeGenerated), max(TimeGenerated), FailedLogonCount = count() by ResultType, UserDisplayName , UserPrincipalName,AlternateSignInName,IPAddress
    | where FailedLogonCount >= threshold
  • GaryBushey's avatar
    GaryBushey
    Bronze Contributor

    zubairrahimsoc There are a couple of Brute force queries available OOTB that you can use as a baseline.  For instance, the code below is from the Bruce force attack against Azure Portal.  You could remove the line:

    | where AppDisplayName has "Azure Portal"

    to make it more generic

     

    let failureCountThreshold = 5;
    let successCountThreshold = 1;
    let authenticationWindow = 20m;
    let aadFunc = (tableName:string){
    table(tableName)
    | extend DeviceDetail = todynamic(DeviceDetail), Status = todynamic(DeviceDetail), LocationDetails = todynamic(LocationDetails)
    | extend OS = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser
    | extend StatusCode = tostring(Status.errorCode), StatusDetails = tostring(Status.additionalDetails)
    | extend State = tostring(LocationDetails.state), City = tostring(LocationDetails.city), Region = tostring(LocationDetails.countryOrRegion)
    | where AppDisplayName has "Azure Portal"
    // Split out failure versus non-failure types
    | extend FailureOrSuccess = iff(ResultType in ("0", "50125", "50140", "70043", "70044"), "Success", "Failure")
    | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), IPAddress = make_set(IPAddress), make_set(OS), make_set(Browser), make_set(City),
    make_set(State), make_set(Region),make_set(ResultType), FailureCount = countif(FailureOrSuccess=="Failure"), SuccessCount = countif(FailureOrSuccess=="Success")
    by bin(TimeGenerated, authenticationWindow), UserDisplayName, UserPrincipalName, AppDisplayName, Type
    | where FailureCount >= failureCountThreshold and SuccessCount >= successCountThreshold
    | mvexpand IPAddress
    | extend IPAddress = tostring(IPAddress)
    | extend timestamp = StartTime, AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress
    };
    let aadSignin = aadFunc("SigninLogs");
    let aadNonInt = aadFunc("AADNonInteractiveUserSignInLogs");
    union isfuzzy=true aadSignin, aadNonInt

Resources