Detection rules › Kusto

Cisco ASA - average attack detection rate increase

Status
available
Severity
low
Time window
6h
Group by
DeviceEventClassID, DeviceName, DropRate, SourceIP, SourceOfDropRateCount
Source
github.com/Azure/Azure-Sentinel

'This will help you determine if Cisco ASA devices are under heavier attack than normal over the last hour versus the previous 6 hours based on DeviceEventClassID 733100 References: https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/syslogs9.html Details on how to further troubleshoot/investigate: https://www.cisco.com/c/en/us/support/docs/security/asa-5500-x-series-next-generation-firewalls/113685-asa-threat-detection.html'

MITRE ATT&CK coverage

Rule body

id: 79f29feb-6a9d-4cdf-baaa-2daf480a5da1
name: Cisco ASA - average attack detection rate increase
description: |
  'This will help you determine if Cisco ASA devices are under heavier attack than normal over the last hour versus the previous 6 hours based on DeviceEventClassID 733100
  References: https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/syslogs9.html
  Details on how to further troubleshoot/investigate: https://www.cisco.com/c/en/us/support/docs/security/asa-5500-x-series-next-generation-firewalls/113685-asa-threat-detection.html'
severity: Low
status: Available
requiredDataConnectors:
  - connectorId: CiscoAsaAma
    dataTypes:
      - CommonSecurityLog
queryFrequency: 1h
queryPeriod: 6h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Discovery
  - Impact
relevantTechniques:
  - T1046
  - T1498
query: |
  let timeframe = 1h;
  let last1h = CommonSecurityLog
  | where TimeGenerated >= ago(timeframe)
  | where isempty(CommunicationDirection)
  | where DeviceEventClassID == "733100"
  | extend SourceOfDropRateCount = tostring(split(tostring(split(Message, "]")[0]),"[ ")[1])
  | extend splitMessage = split(Message, ".")
  | extend DropRate = tostring(split(tostring(splitMessage[0]),"] ")[1])
  | extend CurrentBurstRate = split(tostring(split(tostring(splitMessage[1]),"  ")[0]),"is ")
  | extend CurrentBurstRatePerSec = toint(split(tostring(CurrentBurstRate[1])," ")[0])
  | extend MaxConfiguredBurstRate = toint(CurrentBurstRate[2])
  | extend CurrentAvgRate = split(tostring(split(tostring(splitMessage[1]),"  ")[1]),"is ")
  | extend CurrentAvgRatePerSec = toint(split(tostring(CurrentAvgRate[1])," ")[0])
  | extend MaxConfiguredAvgRate = toint(CurrentAvgRate[2])
  | extend CumulativeTotal = toint(split(tostring(split(tostring(splitMessage[1]),"  ")[2]),"is ")[1])
  | summarize last1hCumTotal = sum(CumulativeTotal), last1hAvgRatePerSec = avg(CurrentAvgRatePerSec), last1hAvgBurstRatePerSec = avg(CurrentBurstRatePerSec) by DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate;
  let prev6h = CommonSecurityLog
  | where TimeGenerated between (ago(6h) .. ago(1h))
  | where isempty(CommunicationDirection)
  | where DeviceEventClassID == "733100"
  | extend SourceOfDropRateCount = tostring(split(tostring(split(Message, "]")[0]),"[ ")[1])
  | extend splitMessage = split(Message, ".")
  | extend DropRate = tostring(split(tostring(splitMessage[0]),"] ")[1])
  | extend CurrentBurstRate = split(tostring(split(tostring(splitMessage[1]),"  ")[0]),"is ")
  | extend prevCurrentBurstRatePerSec = toint(split(tostring(CurrentBurstRate[1])," ")[0])
  | extend prevMaxConfiguredBurstRate = toint(CurrentBurstRate[2])
  | extend CurrentAvgRate = split(tostring(split(tostring(splitMessage[1]),"  ")[1]),"is ")
  | extend prevCurrentAvgRatePerSec = toint(split(tostring(CurrentAvgRate[1])," ")[0])
  | extend prevMaxConfiguredAvgRate = toint(CurrentAvgRate[2])
  | extend prevCumulativeTotal = toint(split(tostring(split(tostring(splitMessage[1]),"  ")[2]),"is ")[1])
  | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), prev6hCumTotal = sum(prevCumulativeTotal), prev6hAvgRatePerSec = avg(prevCurrentAvgRatePerSec), prev6hAvgBurstRatePerSec = avg(prevCurrentBurstRatePerSec)
  by DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate;
  last1h | join (
    prev6h
  ) on DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate
  | project StartTimeUtc, EndTimeUtc, DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate, last1hCumTotal, prev6hCumTotal, prev6hAvgCumTotal = prev6hCumTotal/6, last1hAvgRatePerSec, prev6hAvgRatePerSec, last1hAvgBurstRatePerSec, prev6hAvgBurstRatePerSec
  // Select only events that indicate a doubling of the expected rate in the last hour over the previous 6 hours
  | where last1hCumTotal > 2*prev6hAvgCumTotal or last1hAvgRatePerSec > 2*prev6hAvgRatePerSec or last1hAvgBurstRatePerSec > 2*prev6hAvgBurstRatePerSec
  | extend HostName = tostring(split(DeviceName, ".")[0]), DomainIndex = toint(indexof(DeviceName, '.'))
  | extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)
entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: DeviceName
      - identifier: HostName
        columnName: HostName
      - identifier: DnsDomain
        columnName: HostNameDomain
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SourceIP
version: 1.0.3
kind: Scheduled

Stages and Predicates

Parameters

let timeframe = 1h;

let last1h is inlined into the numbered stages below.

Let binding: prev6h used in Stage 7

let prev6h = CommonSecurityLog
| where TimeGenerated between (ago(6h) .. ago(1h))
| where isempty(CommunicationDirection)
| where DeviceEventClassID == "733100"
| extend SourceOfDropRateCount = tostring(split(tostring(split(Message, "]")[0]),"[ ")[1])
| extend splitMessage = split(Message, ".")
| extend DropRate = tostring(split(tostring(splitMessage[0]),"] ")[1])
| extend CurrentBurstRate = split(tostring(split(tostring(splitMessage[1]),"  ")[0]),"is ")
| extend prevCurrentBurstRatePerSec = toint(split(tostring(CurrentBurstRate[1])," ")[0])
| extend prevMaxConfiguredBurstRate = toint(CurrentBurstRate[2])
| extend CurrentAvgRate = split(tostring(split(tostring(splitMessage[1]),"  ")[1]),"is ")
| extend prevCurrentAvgRatePerSec = toint(split(tostring(CurrentAvgRate[1])," ")[0])
| extend prevMaxConfiguredAvgRate = toint(CurrentAvgRate[2])
| extend prevCumulativeTotal = toint(split(tostring(split(tostring(splitMessage[1]),"  ")[2]),"is ")[1])
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), prev6hCumTotal = sum(prevCumulativeTotal), prev6hAvgRatePerSec = avg(prevCurrentAvgRatePerSec), prev6hAvgBurstRatePerSec = avg(prevCurrentBurstRatePerSec)
by DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate;

Stages 1 to 6 define let last1h (the rule's main pipeline source); stages 7 to 11 run on it.

Stage 1: source

CommonSecurityLog

Stage 2: where

| where TimeGenerated >= ago(timeframe)

Stage 3: where

| where isempty(CommunicationDirection)

Stage 4: where

| where DeviceEventClassID == "733100"

Stage 5: extend (10 consecutive steps)

| extend SourceOfDropRateCount = tostring(split(tostring(split(Message, "]")[0]),"[ ")[1])
| extend splitMessage = split(Message, ".")
| extend DropRate = tostring(split(tostring(splitMessage[0]),"] ")[1])
| extend CurrentBurstRate = split(tostring(split(tostring(splitMessage[1]),"  ")[0]),"is ")
| extend CurrentBurstRatePerSec = toint(split(tostring(CurrentBurstRate[1])," ")[0])
| extend MaxConfiguredBurstRate = toint(CurrentBurstRate[2])
| extend CurrentAvgRate = split(tostring(split(tostring(splitMessage[1]),"  ")[1]),"is ")
| extend CurrentAvgRatePerSec = toint(split(tostring(CurrentAvgRate[1])," ")[0])
| extend MaxConfiguredAvgRate = toint(CurrentAvgRate[2])
| extend CumulativeTotal = toint(split(tostring(split(tostring(splitMessage[1]),"  ")[2]),"is ")[1])

Stage 6: summarize

| summarize last1hCumTotal = sum(CumulativeTotal), last1hAvgRatePerSec = avg(CurrentAvgRatePerSec), last1hAvgBurstRatePerSec = avg(CurrentBurstRatePerSec) by DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate

Stage 7: join

last1h
| join (
  prev6h
) on DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate

Stage 8: project

| project StartTimeUtc, EndTimeUtc, DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate, last1hCumTotal, prev6hCumTotal, prev6hAvgCumTotal = prev6hCumTotal/6, last1hAvgRatePerSec, prev6hAvgRatePerSec, last1hAvgBurstRatePerSec, prev6hAvgBurstRatePerSec

Stage 9: where

| where last1hCumTotal > 2*prev6hAvgCumTotal or last1hAvgRatePerSec > 2*prev6hAvgRatePerSec or last1hAvgBurstRatePerSec > 2*prev6hAvgBurstRatePerSec

Stage 10: extend

| extend HostName = tostring(split(DeviceName, ".")[0]), DomainIndex = toint(indexof(DeviceName, '.'))

Stage 11: extend

| extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)
HostNameDomain =
ifDomainIndex != -1substring(DeviceName, (DomainIndex + 1))
elseDeviceName

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
DeviceEventClassIDproject
DeviceNameproject
DropRateproject
EndTimeUtcproject
SourceIPproject
SourceOfDropRateCountproject
StartTimeUtcproject
last1hAvgBurstRatePerSecproject
last1hAvgRatePerSecproject
last1hCumTotalproject
prev6hAvgBurstRatePerSecproject
prev6hAvgCumTotalproject
prev6hAvgRatePerSecproject
prev6hCumTotalproject
DomainIndexextend
HostNameextend
HostNameDomainextend