Detection rules › Kusto

Netskope - Anomalous User Behavior (High Volume from Unmanaged Device)

Status
available
Severity
medium
Time window
1h
Group by
CsUsername, XCDevice, XCsAccessMethod
Source
github.com/Azure/Azure-Sentinel

Detects anomalous user behavior including high data volume transfers from unmanaged devices, unusual access patterns, and suspicious application usage.

MITRE ATT&CK coverage

TacticTechniques
CollectionT1074 Data Staged
ExfiltrationT1567 Exfiltration Over Web Service

Rule body kusto

id: fa4c4f1c-3c5f-4c3a-a13f-924c30db56e9
name: Netskope - Anomalous User Behavior (High Volume from Unmanaged Device)
description: |
  Detects anomalous user behavior including high data volume transfers from unmanaged devices, unusual access patterns, and suspicious application usage.
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: NetskopeWebTxConnector
    dataTypes:
      - NetskopeWebTransactions_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Exfiltration
  - Collection
relevantTechniques:
  - T1567
  - T1074
query: |
  let highVolumeThresholdGB = 1;
  NetskopeWebTransactions_CL
  | where TimeGenerated > ago(1h)
  | where isnotempty(CsUsername)
  | summarize 
      TotalBytes = sum(Bytes),
      UploadBytes = sum(CsBytes),
      DownloadBytes = sum(ScBytes),
      UniqueApps = dcount(XCsApp),
      Apps = make_set(XCsApp, 20),
      UniqueHosts = dcount(CsHost),
      Activities = make_set(XCsAppActivity),
      Countries = make_set(XCCountry),
      Devices = make_set(XCDevice),
      AccessMethods = make_set(XCsAccessMethod),
      EventCount = count()
      by CsUsername, XCDevice, XCsAccessMethod
  | extend 
      TotalGB = round(TotalBytes / 1073741824.0, 3),
      UploadGB = round(UploadBytes / 1073741824.0, 3),
      DownloadGB = round(DownloadBytes / 1073741824.0, 3)
  | where TotalGB > highVolumeThresholdGB
  | extend IsUnmanagedDevice = XCDevice =~ 'unmanaged' or XCDevice =~ 'BYOD' or XCDevice =~ 'Personal' or XCDevice =~ 'Unknown' or XCsAccessMethod != 'Client'
  | where IsUnmanagedDevice or TotalGB > 5 or UniqueApps > 20
  | extend RiskIndicators = strcat_array(array_concat(
      iff(IsUnmanagedDevice, dynamic(['Unmanaged Device']), dynamic([])),
      iff(TotalGB > 5, dynamic(['High Data Volume']), dynamic([])),
      iff(UniqueApps > 20, dynamic(['Many Apps Accessed']), dynamic([])),
      iff(array_length(Countries) > 1, dynamic(['Multiple Countries']), dynamic([]))
  ), ', ')
  | project 
      TimeGenerated = now(),
      User = CsUsername,
      Device = XCDevice,
      AccessMethod = XCsAccessMethod,
      TotalDataGB = TotalGB,
      UploadGB,
      DownloadGB,
      UniqueApplications = UniqueApps,
      Applications = Apps,
      UniqueHosts,
      Activities,
      Countries,
      EventCount,
      IsUnmanagedDevice,
      RiskIndicators
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: User
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: Device
version: 1.0.0
kind: Scheduled

Stages and Predicates

Parameters

let highVolumeThresholdGB = 1;

Stage 1: source

NetskopeWebTransactions_CL

Stage 2: where

| where TimeGenerated > ago(1h)

Stage 3: where

| where isnotempty(CsUsername)

Stage 4: summarize

| summarize 
    TotalBytes = sum(Bytes),
    UploadBytes = sum(CsBytes),
    DownloadBytes = sum(ScBytes),
    UniqueApps = dcount(XCsApp),
    Apps = make_set(XCsApp, 20),
    UniqueHosts = dcount(CsHost),
    Activities = make_set(XCsAppActivity),
    Countries = make_set(XCCountry),
    Devices = make_set(XCDevice),
    AccessMethods = make_set(XCsAccessMethod),
    EventCount = count()
    by CsUsername, XCDevice, XCsAccessMethod

Stage 5: extend

| extend 
    TotalGB = round(TotalBytes / 1073741824.0, 3),
    UploadGB = round(UploadBytes / 1073741824.0, 3),
    DownloadGB = round(DownloadBytes / 1073741824.0, 3)

Stage 6: where

| where TotalGB > highVolumeThresholdGB

Stage 7: extend

| extend IsUnmanagedDevice = XCDevice =~ 'unmanaged' or XCDevice =~ 'BYOD' or XCDevice =~ 'Personal' or XCDevice =~ 'Unknown' or XCsAccessMethod != 'Client'

Stage 8: where

| where IsUnmanagedDevice or TotalGB > 5 or UniqueApps > 20

Stage 9: extend

| extend RiskIndicators = strcat_array(array_concat(
    iff(IsUnmanagedDevice, dynamic(['Unmanaged Device']), dynamic([])),
    iff(TotalGB > 5, dynamic(['High Data Volume']), dynamic([])),
    iff(UniqueApps > 20, dynamic(['Many Apps Accessed']), dynamic([])),
    iff(array_length(Countries) > 1, dynamic(['Multiple Countries']), dynamic([]))
), ', ')

Stage 10: project

| project 
    TimeGenerated = now(),
    User = CsUsername,
    Device = XCDevice,
    AccessMethod = XCsAccessMethod,
    TotalDataGB = TotalGB,
    UploadGB,
    DownloadGB,
    UniqueApplications = UniqueApps,
    Applications = Apps,
    UniqueHosts,
    Activities,
    Countries,
    EventCount,
    IsUnmanagedDevice,
    RiskIndicators

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
CsUsernameis_not_null
  • (no value, null check)
TotalGBgt
  • 1 transforms: cased
  • 5 transforms: cased
UniqueAppsgt
  • 20 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
AccessMethodproject
Activitiesproject
Applicationsproject
Countriesproject
Deviceproject
DownloadGBproject
EventCountproject
IsUnmanagedDeviceproject
RiskIndicatorsproject
TimeGeneratedproject
TotalDataGBproject
UniqueApplicationsproject
UniqueHostsproject
UploadGBproject
Userproject