Microsoft Sentinel Analytic Rules
cloudbrothers.infoAzure Sentinel RepoToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

A potentially malicious web request was executed against a web server

Back
Id46ac55ae-47b8-414a-8f94-89ccd1962178
RulenameA potentially malicious web request was executed against a web server
DescriptionDetects unobstructed Web Application Firewall (WAF) activity in sessions where the WAF blocked incoming requests by computing the

ratio between blocked requests and unobstructed WAF requests in these sessions (BlockvsSuccessRatio metric). A high ratio value for

a given client IP and hostname calls for further investigation of the WAF data in that session, due to the significantly high number

of blocked requests and a few unobstructed logs that may be malicious but have passed undetected through the WAF. The successCode

variable defines what the detection thinks is a successful status code and should be altered to fit the environment.
SeverityMedium
TacticsInitialAccess
TechniquesT1190
Required data connectorsWAF
KindScheduled
Query frequency1d
Query period1d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Web Application Firewall (WAF)/Analytic Rules/MaliciousWAFSessions.yaml
Version1.0.4
Arm template46ac55ae-47b8-414a-8f94-89ccd1962178.json
Deploy To Azure
let queryperiod = 1d;
let mode = dynamic(['Blocked', 'Detected']);
let successCode = dynamic(['200', '101','204', '400','504','304','401','500']);
let sessionBin = 30m;
AzureDiagnostics
| where TimeGenerated > ago(queryperiod)
| where ResourceProvider == 'MICROSOFT.NETWORK' and Category =~ 'ApplicationGatewayFirewallLog' and action_s in (mode)
| sort by hostname_s asc, clientIp_s asc, TimeGenerated asc
| extend SessionBlockedStarted = row_window_session(TimeGenerated, queryperiod, 10m, ((clientIp_s != prev(clientIp_s)) or (hostname_s != prev(hostname_s))))
| summarize SessionBlockedEnded = max(TimeGenerated), SessionBlockedCount = count() by hostname_s, clientIp_s, SessionBlockedStarted
| extend TimeKey = range(bin(SessionBlockedStarted, sessionBin), bin(SessionBlockedEnded, sessionBin), sessionBin)
| mv-expand TimeKey to typeof(datetime)
| join kind = inner(
    AzureDiagnostics
    | where TimeGenerated > ago(queryperiod)
    | where Category =~ 'ApplicationGatewayAccessLog' and (isempty(httpStatus_d) or httpStatus_d in (successCode))
    | extend TimeKey = bin(TimeGenerated, sessionBin)
    | extend hostname_s = coalesce(hostname_s,host_s), clientIp_s = coalesce(clientIp_s,clientIP_s)
) on TimeKey, hostname_s , clientIp_s
| where TimeGenerated between (SessionBlockedStarted..SessionBlockedEnded)
| extend
    originalRequestUriWithArgs_s = column_ifexists("originalRequestUriWithArgs_s", ""),
    serverStatus_s = column_ifexists("serverStatus_s", "")
| summarize
    SuccessfulAccessCount = count(),
    UserAgents = make_set(userAgent_s, 250),
    RequestURIs = make_set(requestUri_s, 250),
    OriginalRequestURIs = make_set(originalRequestUriWithArgs_s, 250),
    SuccessCodes = make_set(httpStatus_d, 250),
    SuccessCodes_BackendServer = make_set(serverStatus_s, 250),
    take_any(SessionBlockedEnded, SessionBlockedCount)
    by hostname_s, clientIp_s, SessionBlockedStarted
| where SessionBlockedCount > SuccessfulAccessCount
| extend timestamp = SessionBlockedStarted, IPCustomEntity = clientIp_s
| extend BlockvsSuccessRatio = SessionBlockedCount/toreal(SuccessfulAccessCount)
| sort by BlockvsSuccessRatio desc, timestamp asc
| project-reorder SessionBlockedStarted, SessionBlockedEnded, hostname_s, clientIp_s, SessionBlockedCount, SuccessfulAccessCount, BlockvsSuccessRatio, SuccessCodes, RequestURIs, OriginalRequestURIs, UserAgents
requiredDataConnectors:
- connectorId: WAF
  dataTypes:
  - AzureDiagnostics
triggerOperator: gt
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Web Application Firewall (WAF)/Analytic Rules/MaliciousWAFSessions.yaml
version: 1.0.4
status: Available
queryPeriod: 1d
severity: Medium
relevantTechniques:
- T1190
tactics:
- InitialAccess
kind: Scheduled
queryFrequency: 1d
description: |
  'Detects unobstructed Web Application Firewall (WAF) activity in sessions where the WAF blocked incoming requests by computing the 
  ratio between blocked requests and unobstructed WAF requests in these sessions (BlockvsSuccessRatio metric). A high ratio value for 
  a given client IP and hostname calls for further investigation of the WAF data in that session, due to the significantly high number 
  of blocked requests and a few unobstructed logs that may be malicious but have passed undetected through the WAF. The successCode 
  variable defines what the detection thinks is a successful status code and should be altered to fit the environment.'  
query: |
  let queryperiod = 1d;
  let mode = dynamic(['Blocked', 'Detected']);
  let successCode = dynamic(['200', '101','204', '400','504','304','401','500']);
  let sessionBin = 30m;
  AzureDiagnostics
  | where TimeGenerated > ago(queryperiod)
  | where ResourceProvider == 'MICROSOFT.NETWORK' and Category =~ 'ApplicationGatewayFirewallLog' and action_s in (mode)
  | sort by hostname_s asc, clientIp_s asc, TimeGenerated asc
  | extend SessionBlockedStarted = row_window_session(TimeGenerated, queryperiod, 10m, ((clientIp_s != prev(clientIp_s)) or (hostname_s != prev(hostname_s))))
  | summarize SessionBlockedEnded = max(TimeGenerated), SessionBlockedCount = count() by hostname_s, clientIp_s, SessionBlockedStarted
  | extend TimeKey = range(bin(SessionBlockedStarted, sessionBin), bin(SessionBlockedEnded, sessionBin), sessionBin)
  | mv-expand TimeKey to typeof(datetime)
  | join kind = inner(
      AzureDiagnostics
      | where TimeGenerated > ago(queryperiod)
      | where Category =~ 'ApplicationGatewayAccessLog' and (isempty(httpStatus_d) or httpStatus_d in (successCode))
      | extend TimeKey = bin(TimeGenerated, sessionBin)
      | extend hostname_s = coalesce(hostname_s,host_s), clientIp_s = coalesce(clientIp_s,clientIP_s)
  ) on TimeKey, hostname_s , clientIp_s
  | where TimeGenerated between (SessionBlockedStarted..SessionBlockedEnded)
  | extend
      originalRequestUriWithArgs_s = column_ifexists("originalRequestUriWithArgs_s", ""),
      serverStatus_s = column_ifexists("serverStatus_s", "")
  | summarize
      SuccessfulAccessCount = count(),
      UserAgents = make_set(userAgent_s, 250),
      RequestURIs = make_set(requestUri_s, 250),
      OriginalRequestURIs = make_set(originalRequestUriWithArgs_s, 250),
      SuccessCodes = make_set(httpStatus_d, 250),
      SuccessCodes_BackendServer = make_set(serverStatus_s, 250),
      take_any(SessionBlockedEnded, SessionBlockedCount)
      by hostname_s, clientIp_s, SessionBlockedStarted
  | where SessionBlockedCount > SuccessfulAccessCount
  | extend timestamp = SessionBlockedStarted, IPCustomEntity = clientIp_s
  | extend BlockvsSuccessRatio = SessionBlockedCount/toreal(SuccessfulAccessCount)
  | sort by BlockvsSuccessRatio desc, timestamp asc
  | project-reorder SessionBlockedStarted, SessionBlockedEnded, hostname_s, clientIp_s, SessionBlockedCount, SuccessfulAccessCount, BlockvsSuccessRatio, SuccessCodes, RequestURIs, OriginalRequestURIs, UserAgents  
id: 46ac55ae-47b8-414a-8f94-89ccd1962178
triggerThreshold: 0
entityMappings:
- fieldMappings:
  - identifier: Address
    columnName: clientIp_s
  entityType: IP
name: A potentially malicious web request was executed against a web server
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2023-02-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/46ac55ae-47b8-414a-8f94-89ccd1962178')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/46ac55ae-47b8-414a-8f94-89ccd1962178')]",
      "properties": {
        "alertRuleTemplateName": "46ac55ae-47b8-414a-8f94-89ccd1962178",
        "customDetails": null,
        "description": "'Detects unobstructed Web Application Firewall (WAF) activity in sessions where the WAF blocked incoming requests by computing the \nratio between blocked requests and unobstructed WAF requests in these sessions (BlockvsSuccessRatio metric). A high ratio value for \na given client IP and hostname calls for further investigation of the WAF data in that session, due to the significantly high number \nof blocked requests and a few unobstructed logs that may be malicious but have passed undetected through the WAF. The successCode \nvariable defines what the detection thinks is a successful status code and should be altered to fit the environment.'\n",
        "displayName": "A potentially malicious web request was executed against a web server",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "clientIp_s",
                "identifier": "Address"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Web Application Firewall (WAF)/Analytic Rules/MaliciousWAFSessions.yaml",
        "query": "let queryperiod = 1d;\nlet mode = dynamic(['Blocked', 'Detected']);\nlet successCode = dynamic(['200', '101','204', '400','504','304','401','500']);\nlet sessionBin = 30m;\nAzureDiagnostics\n| where TimeGenerated > ago(queryperiod)\n| where ResourceProvider == 'MICROSOFT.NETWORK' and Category =~ 'ApplicationGatewayFirewallLog' and action_s in (mode)\n| sort by hostname_s asc, clientIp_s asc, TimeGenerated asc\n| extend SessionBlockedStarted = row_window_session(TimeGenerated, queryperiod, 10m, ((clientIp_s != prev(clientIp_s)) or (hostname_s != prev(hostname_s))))\n| summarize SessionBlockedEnded = max(TimeGenerated), SessionBlockedCount = count() by hostname_s, clientIp_s, SessionBlockedStarted\n| extend TimeKey = range(bin(SessionBlockedStarted, sessionBin), bin(SessionBlockedEnded, sessionBin), sessionBin)\n| mv-expand TimeKey to typeof(datetime)\n| join kind = inner(\n    AzureDiagnostics\n    | where TimeGenerated > ago(queryperiod)\n    | where Category =~ 'ApplicationGatewayAccessLog' and (isempty(httpStatus_d) or httpStatus_d in (successCode))\n    | extend TimeKey = bin(TimeGenerated, sessionBin)\n    | extend hostname_s = coalesce(hostname_s,host_s), clientIp_s = coalesce(clientIp_s,clientIP_s)\n) on TimeKey, hostname_s , clientIp_s\n| where TimeGenerated between (SessionBlockedStarted..SessionBlockedEnded)\n| extend\n    originalRequestUriWithArgs_s = column_ifexists(\"originalRequestUriWithArgs_s\", \"\"),\n    serverStatus_s = column_ifexists(\"serverStatus_s\", \"\")\n| summarize\n    SuccessfulAccessCount = count(),\n    UserAgents = make_set(userAgent_s, 250),\n    RequestURIs = make_set(requestUri_s, 250),\n    OriginalRequestURIs = make_set(originalRequestUriWithArgs_s, 250),\n    SuccessCodes = make_set(httpStatus_d, 250),\n    SuccessCodes_BackendServer = make_set(serverStatus_s, 250),\n    take_any(SessionBlockedEnded, SessionBlockedCount)\n    by hostname_s, clientIp_s, SessionBlockedStarted\n| where SessionBlockedCount > SuccessfulAccessCount\n| extend timestamp = SessionBlockedStarted, IPCustomEntity = clientIp_s\n| extend BlockvsSuccessRatio = SessionBlockedCount/toreal(SuccessfulAccessCount)\n| sort by BlockvsSuccessRatio desc, timestamp asc\n| project-reorder SessionBlockedStarted, SessionBlockedEnded, hostname_s, clientIp_s, SessionBlockedCount, SuccessfulAccessCount, BlockvsSuccessRatio, SuccessCodes, RequestURIs, OriginalRequestURIs, UserAgents\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P1D",
        "severity": "Medium",
        "status": "Available",
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "InitialAccess"
        ],
        "techniques": [
          "T1190"
        ],
        "templateVersion": "1.0.4",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}