{
  "$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/ebd95a4d-cc56-5f01-a1de-36aa67e66794')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/ebd95a4d-cc56-5f01-a1de-36aa67e66794')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDisplayNameFormat": "RedRays: {{Title}}"
        },
        "alertRuleTemplateName": "ebd95a4d-cc56-5f01-a1de-36aa67e66794",
        "customDetails": {
          "AccountName": "AccountName",
          "EventId": "EventId",
          "FindingKey": "FindingKey",
          "Module": "Module",
          "ProductInstanceId": "ProductInstanceId",
          "SapClient": "SapClient",
          "SourceSeverity": "SourceSeverity",
          "SourceStatus": "SourceStatus",
          "SourceUrl": "SourceUrl",
          "SystemId": "SystemId"
        },
        "description": "Identifies new or materially changed, actionable password security findings from RedRays. Only High or Critical findings are selected. Initial findings raise alerts only if you enable baseline alerting in RedRays. The ATT&CK mapping describes password recovery during an authorized assessment, not evidence of an adversary attack. Records outside the one-day query window do not trigger this rule.",
        "displayName": "RedRays - Password Security",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Host",
            "fieldMappings": [
              {
                "columnName": "EntityHost",
                "identifier": "FullName"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "EntityIP",
                "identifier": "Address"
              }
            ]
          },
          {
            "entityType": "URL",
            "fieldMappings": [
              {
                "columnName": "EntityUrl",
                "identifier": "Url"
              }
            ]
          }
        ],
        "eventGroupingSettings": {
          "aggregationKind": "AlertPerResult"
        },
        "incidentConfiguration": {
          "createIncident": true,
          "groupingConfiguration": {
            "enabled": true,
            "groupByCustomDetails": [
              "FindingKey"
            ],
            "lookbackDuration": "PT24H",
            "matchingMethod": "Selected",
            "reopenClosedIncident": false
          }
        },
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/RedRays%20SAP%20Security%20Findings/Analytic%20Rules/RedRaysRecoveredPasswords.yaml",
        "query": "// Map each ProductInstanceId to its RedRays origin to resolve relative source links.\n// Example: dynamic({\"<ProductInstanceId>\": \"https://redrays.example\"})\nlet redRaysPortalUrls = dynamic({});\nlet observations = RedRaysPasswordFindings_CL\n| where TimeGenerated >= ago(1d)\n| extend ArrivedAt = ingestion_time()\n| summarize arg_min(ArrivedAt, *) by EventId;\nlet candidates = observations\n| where IsAlertCandidate == true and ArrivedAt > ago(15m)\n| project FindingKey, AlertFingerprint, AlertEventId = EventId, AlertArrivedAt = ArrivedAt\n| summarize arg_min(AlertArrivedAt, *) by FindingKey, AlertFingerprint;\nobservations\n| summarize arg_max(Revision, *) by FindingKey\n| where IsActionable == true\n| where SourceSeverity in (\"HIGH\", \"CRITICAL\")\n| join kind=inner candidates on FindingKey, AlertFingerprint\n| extend EventId = AlertEventId\n| extend EntityHost = trim_end(@\"\\.\", trim(@\"\\s+\", tostring(Host)))\n| extend EntityIP = iff(EntityHost !contains \"/\" and isnotempty(parse_ipv6(EntityHost)), EntityHost, \"\")\n| extend EntityHost = iff(isempty(EntityIP) and strlen(EntityHost) <= 253\n    and EntityHost matches regex @\"(?i)^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$\"\n    and not(EntityHost matches regex @\"^[0-9.]+$\"), tolower(EntityHost), \"\")\n| extend _portalOrigin = tostring(redRaysPortalUrls[tostring(ProductInstanceId)]), _sourceLink = tostring(SourceUrl)\n| extend _entityUrlCandidate = case(\n    _sourceLink startswith \"/app/\" and _portalOrigin matches regex @\"(?i)^https?://[^/?#@\\s\\\\]+/?$\",\n    strcat(trim_end(@\"/+\", _portalOrigin), _sourceLink),\n    _sourceLink)\n| extend _parsedEntityUrl = parse_url(_entityUrlCandidate)\n| extend EntityUrl = iff(tostring(_parsedEntityUrl.Scheme) in~ (\"https\", \"http\")\n    and isnotempty(tostring(_parsedEntityUrl.Host))\n    and isempty(tostring(_parsedEntityUrl.Username)) and isempty(tostring(_parsedEntityUrl.Password))\n    and not(_entityUrlCandidate matches regex @\"[\\s\\\\]\"), _entityUrlCandidate, \"\")\n| project-away _portalOrigin, _sourceLink, _entityUrlCandidate, _parsedEntityUrl",
        "queryFrequency": "PT15M",
        "queryPeriod": "P1D",
        "severity": "High",
        "status": "InPreview",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CredentialAccess"
        ],
        "techniques": [
          "T1110"
        ],
        "templateVersion": "1.0.3",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}
