Detection rules › Kusto
Application Gateway WAF - XSS Detection
'Identifies a match for XSS attack in the Application gateway WAF logs. The Threshold value in the query can be changed as per your infrastructure's requirement. References: https://owasp.org/www-project-top-ten/2017/A7_2017-Cross-Site_Scripting_(XSS)'
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Execution | |
| Execution |
Rules detecting the same action
These rules filter on the same operation.
Rule body
id: d2bc08fa-030a-4eea-931a-762d27c6a042
name: Application Gateway WAF - XSS Detection
description: |
'Identifies a match for XSS attack in the Application gateway WAF logs. The Threshold value in the query can be changed as per your infrastructure's requirement.
References: https://owasp.org/www-project-top-ten/2017/A7_2017-Cross-Site_Scripting_(XSS)'
severity: High
requiredDataConnectors:
- connectorId: WAF
dataTypes:
- AzureDiagnostics
queryFrequency: 6h
queryPeriod: 6h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- Execution
relevantTechniques:
- T1189
- T1203
- T0853
tags:
- Cross Site Scripting
query: |
let Threshold = 1;
AzureDiagnostics
| where Category == "ApplicationGatewayFirewallLog"
| where action_s == "Matched"
| project transactionId_g, hostname_s, requestUri_s, TimeGenerated, clientIp_s, Message, details_message_s, details_data_s
| join kind = inner(
AzureDiagnostics
| where Category == "ApplicationGatewayFirewallLog"
| where action_s == "Blocked"
| parse Message with MessageText 'Total Inbound Score: ' TotalInboundScore ' - SQLI=' SQLI_Score ',XSS=' XSS_Score ',RFI=' RFI_Score ',LFI=' LFI_Score ',RCE=' RCE_Score ',PHPI=' PHPI_Score ',HTTP=' HTTP_Score ',SESS=' SESS_Score '): ' Blocked_Reason '; individual paranoia level scores:' Paranoia_Score
| where Blocked_Reason contains "XSS" and toint(TotalInboundScore) >=15 and toint(XSS_Score) >= 10 and toint(SQLI_Score) <= 5) on transactionId_g
| extend Uri = strcat(hostname_s,requestUri_s)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), TransactionID = make_set(transactionId_g), Message = make_set(Message), Detail_Message = make_set(details_message_s), Detail_Data = make_set(details_data_s), Total_TransactionId = dcount(transactionId_g) by clientIp_s, Uri, action_s, SQLI_Score, XSS_Score, TotalInboundScore
| where Total_TransactionId >= Threshold
# The Threshold value above can be changed as per your infrastructure's requirement
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: Uri
- entityType: IP
fieldMappings:
- identifier: Address
columnName: clientIp_s
version: 1.0.1
kind: Scheduled
metadata:
source:
kind: Community
author:
name: shabaz-github
support:
tier: Community
categories:
domains: [ "Security - Threat Protection", "Platform" ]
Stages and Predicates
Parameters
let Threshold = 1;
Stage 1: source
AzureDiagnostics
Stage 2: where
| where Category == "ApplicationGatewayFirewallLog"
Stage 3: where
| where action_s == "Matched"
Stage 4: project
| project transactionId_g, hostname_s, requestUri_s, TimeGenerated, clientIp_s, Message, details_message_s, details_data_s
Stage 5: join
| join kind = inner(
AzureDiagnostics
| where Category == "ApplicationGatewayFirewallLog"
| where action_s == "Blocked"
| parse Message with MessageText 'Total Inbound Score: ' TotalInboundScore ' - SQLI=' SQLI_Score ',XSS=' XSS_Score ',RFI=' RFI_Score ',LFI=' LFI_Score ',RCE=' RCE_Score ',PHPI=' PHPI_Score ',HTTP=' HTTP_Score ',SESS=' SESS_Score '): ' Blocked_Reason '; individual paranoia level scores:' Paranoia_Score
| where Blocked_Reason contains "XSS" and toint(TotalInboundScore) >=15 and toint(XSS_Score) >= 10 and toint(SQLI_Score) <= 5) on transactionId_g
Stage 6: extend
| extend Uri = strcat(hostname_s,requestUri_s)
Stage 7: summarize
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), TransactionID = make_set(transactionId_g), Message = make_set(Message), Detail_Message = make_set(details_message_s), Detail_Data = make_set(details_data_s), Total_TransactionId = dcount(transactionId_g) by clientIp_s, Uri, action_s, SQLI_Score, XSS_Score, TotalInboundScore
Stage 8: where
| where Total_TransactionId >= Threshold
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Blocked_Reason | contains |
| field:"Blocked_Reason" kind:contains value:"XSS" |
Category | eq |
| field:"Category" kind:eq value:"ApplicationGatewayFirewallLog" |
SQLI_Score | le |
| field:"SQLI_Score" kind:le value:"5" |
TotalInboundScore | ge |
| field:"TotalInboundScore" kind:ge value:"15" |
Total_TransactionId | ge |
| field:"Total_TransactionId" kind:ge value:"1" |
XSS_Score | ge |
| field:"XSS_Score" kind:ge value:"10" |
action_s | eq |
| field:"action_s" kind:eq |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Detail_Data | summarize |
Detail_Message | summarize |
EndTime | summarize |
Message | summarize |
SQLI_Score | summarize |
StartTime | summarize |
TotalInboundScore | summarize |
Total_TransactionId | summarize |
TransactionID | summarize |
Uri | summarize |
XSS_Score | summarize |
action_s | summarize |
clientIp_s | summarize |