Detection rules › Kusto
UniFi Site Manager: IPS signature count dropped >50%
Identifies when the IPS signature ruleset count drops by more than half versus the 7-day maximum, indicating broken threat-intel feeds or rollback.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Defense Impairment |
Rule body
id: aa188a24-783a-76a1-cd11-3bcac0e97de9
name: "UniFi Site Manager: IPS signature count dropped >50%"
description: |
Identifies when the IPS signature ruleset count drops by more than half versus the 7-day maximum, indicating broken threat-intel feeds or rollback.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: UniFiSiteManagerConnectorDefinition
dataTypes:
- Unifi_SiteManager_Sites_CL
queryFrequency: 6h
queryPeriod: 7d
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1562
subTechniques:
- T1562.001
query: |
Unifi_SiteManager_Sites_CL
| where TimeGenerated > ago(7d)
| extend rulesCount = toint(SiteStatistics.gateway.ipsSignature.rulesCount)
| where isnotnull(rulesCount)
| summarize MaxCount = max(rulesCount), arg_max(TimeGenerated, rulesCount) by SiteId, SiteName
| where MaxCount > 100 and toreal(rulesCount) / MaxCount < 0.5
| extend DropPct = round(100.0 * (1 - toreal(rulesCount) / MaxCount), 1)
| extend Activity = strcat('IPS rules dropped to ', rulesCount, ' (from ', MaxCount, ', -', DropPct, '%)')
| project TimeGenerated, SiteId, SiteName, Activity, CurrentRules = rulesCount, PeakRules = MaxCount, DropPct
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: SiteId
- identifier: DnsDomain
columnName: SiteName
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: PT12H
matchingMethod: AllEntities
kind: Scheduled
version: 1.0.1
Stages and Predicates
Stage 1: source
Unifi_SiteManager_Sites_CL
Stage 2: where
| where TimeGenerated > ago(7d)
Stage 3: extend
| extend rulesCount = toint(SiteStatistics.gateway.ipsSignature.rulesCount)
Stage 4: where
| where isnotnull(rulesCount)
Stage 5: summarize
| summarize MaxCount = max(rulesCount), arg_max(TimeGenerated, rulesCount) by SiteId, SiteName
Stage 6: where
| where MaxCount > 100 and toreal(rulesCount) / MaxCount < 0.5
Stage 7: extend
| extend DropPct = round(100.0 * (1 - toreal(rulesCount) / MaxCount), 1)
Stage 8: extend
| extend Activity = strcat('IPS rules dropped to ', rulesCount, ' (from ', MaxCount, ', -', DropPct, '%)')
Stage 9: project
| project TimeGenerated, SiteId, SiteName, Activity, CurrentRules = rulesCount, PeakRules = MaxCount, DropPct
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
MaxCount | gt |
| field:"MaxCount" kind:gt value:"100" |
rulesCount | is_not_null | field:"rulesCount" kind:is_not_null |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Activity | project |
CurrentRules | project |
DropPct | project |
PeakRules | project |
SiteId | project |
SiteName | project |
TimeGenerated | project |