Detection rules › Kusto
Netskope - Anomalous User Behavior (High Volume from Unmanaged Device)
Detects anomalous user behavior including high data volume transfers from unmanaged devices, unusual access patterns, and suspicious application usage.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Collection | T1074 Data Staged |
| Exfiltration | T1567 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.
| Field | Kind | Values |
|---|---|---|
CsUsername | is_not_null | |
TotalGB | gt |
|
UniqueApps | gt |
|
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.
| Field | Source |
|---|---|
AccessMethod | project |
Activities | project |
Applications | project |
Countries | project |
Device | project |
DownloadGB | project |
EventCount | project |
IsUnmanagedDevice | project |
RiskIndicators | project |
TimeGenerated | project |
TotalDataGB | project |
UniqueApplications | project |
UniqueHosts | project |
UploadGB | project |
User | project |