diff --git a/Azure Bastion/Alerts - Queries and Alerts/Detection - Bastion Brute Force/Detection - Bastion Brute Force.json b/Azure Bastion/Alerts - Queries and Alerts/Detection - Bastion Brute Force/Detection - Bastion Brute Force.json new file mode 100644 index 00000000..7675d9da --- /dev/null +++ b/Azure Bastion/Alerts - Queries and Alerts/Detection - Bastion Brute Force/Detection - Bastion Brute Force.json @@ -0,0 +1,37 @@ +// Detection - Azure Bastion Brute Force +// Detects brute force / credential-guessing against Azure Bastion by flagging a high +// number of FAILED session logins from the same source IP within a short window. +// Data source: MicrosoftAzureBastionAuditLogs (requires the "Bastion Audit Logs" +// diagnostic setting enabled and routed to Log Analytics). +// Tuning profiles (lookback / threshold): +// Aggressive: 5m / 5 | Balanced (recommended): 15m / 5 | Conservative: 1h / 10 +let lookback = 15m; +let threshold = 5; +let AllowlistedSourceIPs = dynamic([]); +MicrosoftAzureBastionAuditLogs +| where TimeGenerated > ago(lookback) +| where Message == "Login Failed" +| extend UserName = tostring(UserName), + UserEmail = tostring(UserEmail), + SourceIP = tostring(ClientIpAddress), + TargetVM = tostring(TargetVMIPAddress), + TargetResourceId = tostring(TargetResourceId), + Protocol = tostring(Protocol) +| where isnotempty(SourceIP) +| where SourceIP !in (AllowlistedSourceIPs) +| summarize FailedAttempts = count(), + DistinctTargetVMs = dcount(TargetVM), + DistinctAccounts = dcount(UserName), + FirstSeen = min(TimeGenerated), + LastSeen = max(TimeGenerated), + TargetedAccounts = make_set(UserName, 25), + InitiatingUsers = make_set(UserEmail, 25), + TargetVMs = make_set(TargetVM, 25), + TargetResourceIds = make_set(TargetResourceId, 25), + Protocols = make_set(Protocol, 5) + by SourceIP +| where FailedAttempts >= threshold +| extend AttackWindowMinutes = datetime_diff('minute', LastSeen, FirstSeen) +| extend LikelyPasswordSpray = DistinctAccounts >= 5 +| extend HighVolume = FailedAttempts >= threshold * 2 +| order by FailedAttempts desc diff --git a/Azure Bastion/Alerts - Queries and Alerts/Detection - Bastion Brute Force/README.md b/Azure Bastion/Alerts - Queries and Alerts/Detection - Bastion Brute Force/README.md new file mode 100644 index 00000000..89a50227 --- /dev/null +++ b/Azure Bastion/Alerts - Queries and Alerts/Detection - Bastion Brute Force/README.md @@ -0,0 +1,12 @@ +# Detection - Bastion Brute Force + +This query uses Azure Bastion audit logs (`MicrosoftAzureBastionAuditLogs`) to detect potential brute force activity by identifying multiple failed session logins (`Message == "Login Failed"`) from the same source IP against Bastion-fronted VMs within a short window. It groups failures by source IP, surfaces the targeted accounts and VMs, and raises a result when the count meets the configured threshold (default: 5 failures in 15 minutes). Adjust the `lookback` and `threshold` parameters to tune sensitivity for your environment. + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. + +When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments. +