High count of failed attempts from same client IP
Id | 19e01883-15d8-4eb6-a7a5-3276cd668388 |
Rulename | High count of failed attempts from same client IP |
Description | Identifies when 20 or more failed attempts from a given client IP in 1 minute occur on the IIS server. This could be indicative of an attempted brute force. This could also simply indicate a misconfigured service or device. Recommendations: Validate that these are expected connections from the given Client IP. If the client IP is not recognized, potentially block these connections at the edge device. If these are expected connections, verify the credentials are properly configured on the system, service, application or device that is associated with the client IP. References: IIS status code mapping: https://support.microsoft.com/help/943891/the-http-status-code-in-iis-7-0-iis-7-5-and-iis-8-0 Win32 Status code mapping: https://msdn.microsoft.com/library/cc231199.aspx |
Severity | Medium |
Tactics | CredentialAccess |
Techniques | T1110 |
Required data connectors | AzureMonitor(IIS) |
Kind | Scheduled |
Query frequency | 1d |
Query period | 1d |
Trigger threshold | 0 |
Trigger operator | gt |
Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Detections/W3CIISLog/HighFailedLogonCountByClientIP.yaml |
Version | 1.0.2 |
Arm template | 19e01883-15d8-4eb6-a7a5-3276cd668388.json |
let timeBin = 1m;
let failedThreshold = 20;
W3CIISLog
| where scStatus in ("401","403")
| where csUserName != "-"
| extend scStatusFull = strcat(scStatus, ".",scSubStatus)
// Map common IIS codes
| extend scStatusFull_Friendly = case(
scStatusFull == "401.0", "Access denied.",
scStatusFull == "401.1", "Logon failed.",
scStatusFull == "401.2", "Logon failed due to server configuration.",
scStatusFull == "401.3", "Unauthorized due to ACL on resource.",
scStatusFull == "401.4", "Authorization failed by filter.",
scStatusFull == "401.5", "Authorization failed by ISAPI/CGI application.",
scStatusFull == "403.0", "Forbidden.",
scStatusFull == "403.4", "SSL required.",
"See - https://support.microsoft.com/help/943891/the-http-status-code-in-iis-7-0-iis-7-5-and-iis-8-0")
// Mapping to Hex so can be mapped using website in comments above
| extend scWin32Status_Hex = tohex(tolong(scWin32Status))
// Map common win32 codes
| extend scWin32Status_Friendly = case(
scWin32Status_Hex =~ "775", "The referenced account is currently locked out and cannot be logged on to.",
scWin32Status_Hex =~ "52e", "Logon failure: Unknown user name or bad password.",
scWin32Status_Hex =~ "532", "Logon failure: The specified account password has expired.",
scWin32Status_Hex =~ "533", "Logon failure: Account currently disabled.",
scWin32Status_Hex =~ "2ee2", "The request has timed out.",
scWin32Status_Hex =~ "0", "The operation completed successfully.",
scWin32Status_Hex =~ "1", "Incorrect function.",
scWin32Status_Hex =~ "2", "The system cannot find the file specified.",
scWin32Status_Hex =~ "3", "The system cannot find the path specified.",
scWin32Status_Hex =~ "4", "The system cannot open the file.",
scWin32Status_Hex =~ "5", "Access is denied.",
scWin32Status_Hex =~ "8009030e", "SEC_E_NO_CREDENTIALS",
scWin32Status_Hex =~ "8009030C", "SEC_E_LOGON_DENIED",
"See - https://msdn.microsoft.com/library/cc231199.aspx")
// decode URI when available
| extend decodedUriQuery = url_decode(csUriQuery)
// Count of failed attempts from same client IP
| summarize makeset(decodedUriQuery), makeset(csUserName), makeset(sSiteName), makeset(sPort), makeset(csUserAgent), makeset(csMethod), makeset(csUriQuery), makeset(scStatusFull), makeset(scStatusFull_Friendly), makeset(scWin32Status_Hex), makeset(scWin32Status_Friendly), FailedConnectionsCount = count() by bin(TimeGenerated, timeBin), cIP, Computer, sIP
| where FailedConnectionsCount >= failedThreshold
| project TimeGenerated, cIP, set_csUserName, set_decodedUriQuery, Computer, set_sSiteName, sIP, set_sPort, set_csUserAgent, set_csMethod, set_scStatusFull, set_scStatusFull_Friendly, set_scWin32Status_Hex, set_scWin32Status_Friendly, FailedConnectionsCount
| order by FailedConnectionsCount
| extend timestamp = TimeGenerated, HostCustomEntity = Computer, IPCustomEntity = cIP
kind: Scheduled
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/W3CIISLog/HighFailedLogonCountByClientIP.yaml
severity: Medium
metadata:
support:
tier: Community
categories:
domains:
- Security - Network
- Identity
source:
kind: Community
author:
name: Shain
name: High count of failed attempts from same client IP
entityMappings:
- entityType: Host
fieldMappings:
- columnName: HostCustomEntity
identifier: FullName
- entityType: IP
fieldMappings:
- columnName: IPCustomEntity
identifier: Address
relevantTechniques:
- T1110
queryFrequency: 1d
triggerThreshold: 0
queryPeriod: 1d
description: |
'Identifies when 20 or more failed attempts from a given client IP in 1 minute occur on the IIS server.
This could be indicative of an attempted brute force. This could also simply indicate a misconfigured service or device.
Recommendations: Validate that these are expected connections from the given Client IP. If the client IP is not recognized,
potentially block these connections at the edge device.
If these are expected connections, verify the credentials are properly configured on the system, service, application or device
that is associated with the client IP.
References:
IIS status code mapping: https://support.microsoft.com/help/943891/the-http-status-code-in-iis-7-0-iis-7-5-and-iis-8-0
Win32 Status code mapping: https://msdn.microsoft.com/library/cc231199.aspx'
id: 19e01883-15d8-4eb6-a7a5-3276cd668388
version: 1.0.2
tactics:
- CredentialAccess
query: |
let timeBin = 1m;
let failedThreshold = 20;
W3CIISLog
| where scStatus in ("401","403")
| where csUserName != "-"
| extend scStatusFull = strcat(scStatus, ".",scSubStatus)
// Map common IIS codes
| extend scStatusFull_Friendly = case(
scStatusFull == "401.0", "Access denied.",
scStatusFull == "401.1", "Logon failed.",
scStatusFull == "401.2", "Logon failed due to server configuration.",
scStatusFull == "401.3", "Unauthorized due to ACL on resource.",
scStatusFull == "401.4", "Authorization failed by filter.",
scStatusFull == "401.5", "Authorization failed by ISAPI/CGI application.",
scStatusFull == "403.0", "Forbidden.",
scStatusFull == "403.4", "SSL required.",
"See - https://support.microsoft.com/help/943891/the-http-status-code-in-iis-7-0-iis-7-5-and-iis-8-0")
// Mapping to Hex so can be mapped using website in comments above
| extend scWin32Status_Hex = tohex(tolong(scWin32Status))
// Map common win32 codes
| extend scWin32Status_Friendly = case(
scWin32Status_Hex =~ "775", "The referenced account is currently locked out and cannot be logged on to.",
scWin32Status_Hex =~ "52e", "Logon failure: Unknown user name or bad password.",
scWin32Status_Hex =~ "532", "Logon failure: The specified account password has expired.",
scWin32Status_Hex =~ "533", "Logon failure: Account currently disabled.",
scWin32Status_Hex =~ "2ee2", "The request has timed out.",
scWin32Status_Hex =~ "0", "The operation completed successfully.",
scWin32Status_Hex =~ "1", "Incorrect function.",
scWin32Status_Hex =~ "2", "The system cannot find the file specified.",
scWin32Status_Hex =~ "3", "The system cannot find the path specified.",
scWin32Status_Hex =~ "4", "The system cannot open the file.",
scWin32Status_Hex =~ "5", "Access is denied.",
scWin32Status_Hex =~ "8009030e", "SEC_E_NO_CREDENTIALS",
scWin32Status_Hex =~ "8009030C", "SEC_E_LOGON_DENIED",
"See - https://msdn.microsoft.com/library/cc231199.aspx")
// decode URI when available
| extend decodedUriQuery = url_decode(csUriQuery)
// Count of failed attempts from same client IP
| summarize makeset(decodedUriQuery), makeset(csUserName), makeset(sSiteName), makeset(sPort), makeset(csUserAgent), makeset(csMethod), makeset(csUriQuery), makeset(scStatusFull), makeset(scStatusFull_Friendly), makeset(scWin32Status_Hex), makeset(scWin32Status_Friendly), FailedConnectionsCount = count() by bin(TimeGenerated, timeBin), cIP, Computer, sIP
| where FailedConnectionsCount >= failedThreshold
| project TimeGenerated, cIP, set_csUserName, set_decodedUriQuery, Computer, set_sSiteName, sIP, set_sPort, set_csUserAgent, set_csMethod, set_scStatusFull, set_scStatusFull_Friendly, set_scWin32Status_Hex, set_scWin32Status_Friendly, FailedConnectionsCount
| order by FailedConnectionsCount
| extend timestamp = TimeGenerated, HostCustomEntity = Computer, IPCustomEntity = cIP
requiredDataConnectors:
- dataTypes:
- W3CIISLog
connectorId: AzureMonitor(IIS)
triggerOperator: gt
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workspace": {
"type": "String"
}
},
"resources": [
{
"id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/19e01883-15d8-4eb6-a7a5-3276cd668388')]",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/19e01883-15d8-4eb6-a7a5-3276cd668388')]",
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules",
"kind": "Scheduled",
"apiVersion": "2022-11-01-preview",
"properties": {
"displayName": "High count of failed attempts from same client IP",
"description": "'Identifies when 20 or more failed attempts from a given client IP in 1 minute occur on the IIS server.\nThis could be indicative of an attempted brute force. This could also simply indicate a misconfigured service or device.\nRecommendations: Validate that these are expected connections from the given Client IP. If the client IP is not recognized,\npotentially block these connections at the edge device.\nIf these are expected connections, verify the credentials are properly configured on the system, service, application or device\nthat is associated with the client IP.\nReferences:\nIIS status code mapping: https://support.microsoft.com/help/943891/the-http-status-code-in-iis-7-0-iis-7-5-and-iis-8-0\nWin32 Status code mapping: https://msdn.microsoft.com/library/cc231199.aspx'\n",
"severity": "Medium",
"enabled": true,
"query": "let timeBin = 1m;\nlet failedThreshold = 20;\nW3CIISLog\n| where scStatus in (\"401\",\"403\")\n| where csUserName != \"-\"\n| extend scStatusFull = strcat(scStatus, \".\",scSubStatus)\n// Map common IIS codes\n| extend scStatusFull_Friendly = case(\nscStatusFull == \"401.0\", \"Access denied.\",\nscStatusFull == \"401.1\", \"Logon failed.\",\nscStatusFull == \"401.2\", \"Logon failed due to server configuration.\",\nscStatusFull == \"401.3\", \"Unauthorized due to ACL on resource.\",\nscStatusFull == \"401.4\", \"Authorization failed by filter.\",\nscStatusFull == \"401.5\", \"Authorization failed by ISAPI/CGI application.\",\nscStatusFull == \"403.0\", \"Forbidden.\",\nscStatusFull == \"403.4\", \"SSL required.\",\n\"See - https://support.microsoft.com/help/943891/the-http-status-code-in-iis-7-0-iis-7-5-and-iis-8-0\")\n// Mapping to Hex so can be mapped using website in comments above\n| extend scWin32Status_Hex = tohex(tolong(scWin32Status))\n// Map common win32 codes\n| extend scWin32Status_Friendly = case(\nscWin32Status_Hex =~ \"775\", \"The referenced account is currently locked out and cannot be logged on to.\",\nscWin32Status_Hex =~ \"52e\", \"Logon failure: Unknown user name or bad password.\",\nscWin32Status_Hex =~ \"532\", \"Logon failure: The specified account password has expired.\",\nscWin32Status_Hex =~ \"533\", \"Logon failure: Account currently disabled.\",\nscWin32Status_Hex =~ \"2ee2\", \"The request has timed out.\",\nscWin32Status_Hex =~ \"0\", \"The operation completed successfully.\",\nscWin32Status_Hex =~ \"1\", \"Incorrect function.\",\nscWin32Status_Hex =~ \"2\", \"The system cannot find the file specified.\",\nscWin32Status_Hex =~ \"3\", \"The system cannot find the path specified.\",\nscWin32Status_Hex =~ \"4\", \"The system cannot open the file.\",\nscWin32Status_Hex =~ \"5\", \"Access is denied.\",\nscWin32Status_Hex =~ \"8009030e\", \"SEC_E_NO_CREDENTIALS\",\nscWin32Status_Hex =~ \"8009030C\", \"SEC_E_LOGON_DENIED\",\n\"See - https://msdn.microsoft.com/library/cc231199.aspx\")\n// decode URI when available\n| extend decodedUriQuery = url_decode(csUriQuery)\n// Count of failed attempts from same client IP\n| summarize makeset(decodedUriQuery), makeset(csUserName), makeset(sSiteName), makeset(sPort), makeset(csUserAgent), makeset(csMethod), makeset(csUriQuery), makeset(scStatusFull), makeset(scStatusFull_Friendly), makeset(scWin32Status_Hex), makeset(scWin32Status_Friendly), FailedConnectionsCount = count() by bin(TimeGenerated, timeBin), cIP, Computer, sIP\n| where FailedConnectionsCount >= failedThreshold\n| project TimeGenerated, cIP, set_csUserName, set_decodedUriQuery, Computer, set_sSiteName, sIP, set_sPort, set_csUserAgent, set_csMethod, set_scStatusFull, set_scStatusFull_Friendly, set_scWin32Status_Hex, set_scWin32Status_Friendly, FailedConnectionsCount\n| order by FailedConnectionsCount\n| extend timestamp = TimeGenerated, HostCustomEntity = Computer, IPCustomEntity = cIP\n",
"queryFrequency": "P1D",
"queryPeriod": "P1D",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0,
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"tactics": [
"CredentialAccess"
],
"techniques": [
"T1110"
],
"alertRuleTemplateName": "19e01883-15d8-4eb6-a7a5-3276cd668388",
"customDetails": null,
"entityMappings": [
{
"entityType": "Host",
"fieldMappings": [
{
"identifier": "FullName",
"columnName": "HostCustomEntity"
}
]
},
{
"entityType": "IP",
"fieldMappings": [
{
"identifier": "Address",
"columnName": "IPCustomEntity"
}
]
}
],
"templateVersion": "1.0.2",
"OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Detections/W3CIISLog/HighFailedLogonCountByClientIP.yaml"
}
}
]
}