Detection rules › Kusto

Vectra AI Detect - Suspected Compromised Account

Status
available
Severity
informational
Time window
5m
Group by
saccount
Source
github.com/Azure/Azure-Sentinel

'Create an incident when an Account is suspected to be compromised. The higher the severity level is, the more immediate attention it requires as Vectra AI engine is more confident that this is a real threat. Level of severity are: Low, Medium, High, Critical). Recommended configuration is to trigger an alert for at least High and Critical.'

MITRE ATT&CK coverage

Rule body kusto

id: 321f9dbd-64b7-4541-81dc-08cf7732ccb0
name: Vectra AI Detect - Suspected Compromised Account
description: |
  'Create an incident when an Account is suspected to be compromised. 
  The higher the severity level is, the more immediate attention it requires as Vectra AI engine is more confident that this is a real threat. 
  Level of severity are: Low, Medium, High, Critical). Recommended configuration is to trigger an alert for at least High and Critical.'
severity: Informational
status: Available
requiredDataConnectors:
  - connectorId: CefAma
    dataTypes:
      - CommonSecurityLog
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
  aggregationKind: AlertPerResult
tactics:
  - CredentialAccess
  - Discovery
  - LateralMovement
  - Collection
  - CommandAndControl
  - Exfiltration
  - Impact
relevantTechniques:
  - T1003
  - T1087
  - T1021
  - T1119
  - T1071
  - T1041
  - T1499
query: |
  // Edit this variable to only keep the Severity level where an incident needs to be created.
  //Level of severity are: Low, Medium, High, Critical). Recommended configuration is to trigger an alert for at least High and Critical.'
  let configured_level = dynamic(["High", "Critical"]);
  let upn_has_prefix = ":";
  CommonSecurityLog
  | where DeviceVendor == "Vectra Networks"
  | where DeviceProduct == "X Series"
  | where DeviceEventClassID == "asc"
  | extend saccount = extract("saccount=(.+?);", 1, AdditionalExtensions)
  | extend type = iff(saccount matches regex upn_has_prefix, tostring(split(saccount,":")[0]) ,"network" ) 
  | extend upn = iff(saccount matches regex upn_has_prefix, tostring(split(saccount,":")[1]) , saccount )
  | extend name = tostring(split(upn,"@")[0])
  | extend upn_suffix = tostring(split(upn,"@")[1])
  | project-rename threat_score = FlexNumber1
  | project-rename certainty_score = FlexNumber2
  | project-rename vectra_URL = DeviceCustomString4
  | project-rename detection_name = DeviceEventClassID
  | project-rename score_decreases = DeviceCustomString3
  | extend level = case( threat_score <  50 and certainty_score < 50, "Low",
                        threat_score < 50 and certainty_score >= 50 , "Medium", 
                        threat_score >= 50 and certainty_score <= 50, "High", 
                        threat_score >= 50 and certainty_score >= 50, "Critical",
                        "UNKNOWN")
  | extend Severity = case(level == "Info", "Informational",level == "Critical", "High", level)
  | where level in (configured_level) 
  //keep only the event with the highest threat score per Host
  | summarize arg_max(threat_score, *) by saccount
  | sort by TimeGenerated
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: name
      - identifier: UPNSuffix
        columnName: upn_suffix
alertDetailsOverride:
  alertDisplayNameFormat: Vectra AI Detect - Account {{saccount}} reaches {{level}} severity
  alertDescriptionFormat: |
    The account {{saccount}} has a threat score of {{threat_score}} and a
    certainty of {{certainty_score}}
  alertSeverityColumnName: Severity
  alertDynamicProperties:
    - alertProperty: AlertLink
      value: vectra_URL
    - alertProperty: ProductName
      value: DeviceProduct
    - alertProperty: ProviderName
      value: DeviceVendor
    - alertProperty: ConfidenceScore
      value: certainty_score
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: true
    lookbackDuration: 7d
    matchingMethod: AllEntities
customDetails:
  ScoreDecrease: score_decreases
version: 1.0.9
kind: Scheduled

Stages and Predicates

Parameters

let configured_level = dynamic(["High", "Critical"]);
let upn_has_prefix = ":";

Stage 1: source

CommonSecurityLog

Stage 2: where

| where DeviceVendor == "Vectra Networks"

Stage 3: where

| where DeviceProduct == "X Series"

Stage 4: where

| where DeviceEventClassID == "asc"

Stage 5: extend (5 consecutive steps)

| extend saccount = extract("saccount=(.+?);", 1, AdditionalExtensions)
| extend type = iff(saccount matches regex upn_has_prefix, tostring(split(saccount,":")[0]) ,"network" )
| extend upn = iff(saccount matches regex upn_has_prefix, tostring(split(saccount,":")[1]) , saccount )
| extend name = tostring(split(upn,"@")[0])
| extend upn_suffix = tostring(split(upn,"@")[1])

Stage 6: project-rename

| project-rename threat_score = FlexNumber1

Stage 7: project-rename

| project-rename certainty_score = FlexNumber2

Stage 8: project-rename

| project-rename vectra_URL = DeviceCustomString4

Stage 9: project-rename

| project-rename detection_name = DeviceEventClassID

Stage 10: project-rename

| project-rename score_decreases = DeviceCustomString3

Stage 11: extend

| extend level = case( threat_score <  50 and certainty_score < 50, "Low",
                      threat_score < 50 and certainty_score >= 50 , "Medium", 
                      threat_score >= 50 and certainty_score <= 50, "High", 
                      threat_score >= 50 and certainty_score >= 50, "Critical",
                      "UNKNOWN")
level =
ifthreat_score < 50 and certainty_score < 50"Low"
elifthreat_score < 50 and certainty_score >= 50"Medium"
elifthreat_score >= 50 and certainty_score <= 50"High"
elifthreat_score >= 50 and certainty_score >= 50"Critical"
else"UNKNOWN"

Stage 12: extend

| extend Severity = case(level == "Info", "Informational",level == "Critical", "High", level)
Severity =
iflevel == "Info""Informational"
eliflevel == "Critical""High"
elselevel

Stage 13: where

| where level in (configured_level)

Stage 14: summarize

| summarize arg_max(threat_score, *) by saccount

Stage 15: sort

| sort by TimeGenerated

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
DeviceEventClassIDeq
  • asc transforms: cased
DeviceProducteq
  • X Series transforms: cased
DeviceVendoreq
  • Vectra Networks transforms: cased
levelin
  • Critical transforms: cased
  • High transforms: cased

Output fields

Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.

FieldSource
saccountsummarize