{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2024-01-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/884c4957-70ea-4f57-80b9-1bca3890315b')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/884c4957-70ea-4f57-80b9-1bca3890315b')]",
      "properties": {
        "alertRuleTemplateName": "884c4957-70ea-4f57-80b9-1bca3890315b",
        "customDetails": null,
        "description": "'Identifies when 100 or more failed attempts by a given user in 10 minutes occur on the IIS Server.\nThis could be indicative of attempted brute force based on known account information.\nThis could also simply indicate a misconfigured service or device.\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",
        "displayName": "High count of failed logons by a user",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "csUserName",
                "identifier": "FullName"
              },
              {
                "columnName": "AccountName",
                "identifier": "Name"
              },
              {
                "columnName": "AccountUPNSuffix",
                "identifier": "UPNSuffix"
              }
            ]
          },
          {
            "entityType": "Host",
            "fieldMappings": [
              {
                "columnName": "Computer",
                "identifier": "FullName"
              },
              {
                "columnName": "HostName",
                "identifier": "HostName"
              },
              {
                "columnName": "HostNameDomain",
                "identifier": "NTDomain"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Detections/W3CIISLog/HighFailedLogonCountByUser.yaml",
        "query": "let timeBin = 10m;\nlet failedThreshold = 100;\nW3CIISLog\n| where scStatus in (\"401\",\"403\")\n| where csUserName != \"-\"\n// Handling Exchange specific items in IIS logs to remove the unique log identifier in the URI\n| extend csUriQuery = iff(csUriQuery startswith \"MailboxId=\", tostring(split(csUriQuery, \"&\")[0]) , csUriQuery )\n| extend csUriQuery = iff(csUriQuery startswith \"X-ARR-CACHE-HIT=\", strcat(tostring(split(csUriQuery, \"&\")[0]),tostring(split(csUriQuery, \"&\")[1])) , csUriQuery )\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 logons by a user\n| summarize makeset(decodedUriQuery), makeset(cIP), 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), csUserName, Computer, sIP\n| where FailedConnectionsCount >= failedThreshold\n| project TimeGenerated, csUserName, set_decodedUriQuery, Computer, set_sSiteName, sIP, set_cIP, set_sPort, set_csUserAgent, set_csMethod, set_scStatusFull, set_scStatusFull_Friendly, set_scWin32Status_Hex, set_scWin32Status_Friendly, FailedConnectionsCount\n| order by FailedConnectionsCount\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(csUserName, \"@\")[0]), AccountUPNSuffix = tostring(split(csUserName, \"@\")[1])\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P1D",
        "severity": "Medium",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CredentialAccess"
        ],
        "techniques": [
          "T1110"
        ],
        "templateVersion": "1.0.3",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}
