Detection rules › Kusto

Netskope - Heavy Personal Cloud Storage Usage (Shadow IT)

Status
available
Severity
medium
Time window
1h
Group by
CsUsername, XCCountry, XCDevice, XCsApp, XCsAppCategory, XCsAppInstanceName, XCsAppTags
Source
github.com/Azure/Azure-Sentinel

Detects heavy usage of personal cloud storage applications like personal Dropbox, Google Drive, OneDrive personal, etc. Indicates potential Shadow IT or data leakage risk.

MITRE ATT&CK coverage

Rule body kusto

id: 272f9bca-5fd0-4413-b494-03b2d9f0bb9b
name: Netskope - Heavy Personal Cloud Storage Usage (Shadow IT)
description: |
  Detects heavy usage of personal cloud storage applications like personal Dropbox, Google Drive, OneDrive personal, etc. Indicates potential Shadow IT or data leakage risk.
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: NetskopeWebTxConnector
    dataTypes:
      - NetskopeWebTransactions_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Exfiltration
  - Collection
relevantTechniques:
  - T1567
  - T1530
query: |
  let heavyUsageThresholdMB = 500;
  NetskopeWebTransactions_CL
  | where TimeGenerated > ago(1h)
  | where isnotempty(CsUsername) and isnotempty(XCsApp)
  | where XCsApp has_any ('Dropbox', 'Google Drive', 'OneDrive', 'Box', 'iCloud', 'pCloud', 'MEGA', 'MediaFire', 'WeTransfer')
  | where XCsAppInstanceTag contains 'Personal' 
      or XCsAppInstanceName contains 'Personal'
      or XCsAppTags contains 'Unsanctioned'
      or not(XCsAppTags contains 'Enterprise')
  | summarize 
      TotalBytes = sum(Bytes),
      UploadBytes = sum(CsBytes),
      DownloadBytes = sum(ScBytes),
      FileCount = dcount(XCsAppObjectName),
      Files = make_set(XCsAppObjectName, 10),
      Activities = make_set(XCsAppActivity),
      EventCount = count()
      by CsUsername, XCsApp, XCsAppCategory, XCsAppInstanceName, XCsAppTags, XCDevice, XCCountry
  | extend 
      TotalMB = round(TotalBytes / 1048576.0, 2),
      UploadMB = round(UploadBytes / 1048576.0, 2),
      DownloadMB = round(DownloadBytes / 1048576.0, 2)
  | where TotalMB > heavyUsageThresholdMB or FileCount > 50
  | project 
      TimeGenerated = now(),
      User = CsUsername,
      CloudApplication = XCsApp,
      AppCategory = XCsAppCategory,
      AppInstance = XCsAppInstanceName,
      AppTags = XCsAppTags,
      TotalDataMB = TotalMB,
      UploadMB,
      DownloadMB,
      FileCount,
      Files,
      Activities,
      Device = XCDevice,
      Country = XCCountry,
      EventCount
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: User
  - entityType: CloudApplication
    fieldMappings:
      - identifier: Name
        columnName: CloudApplication
version: 1.0.0
kind: Scheduled

Stages and Predicates

Parameters

let heavyUsageThresholdMB = 500;

Stage 1: source

NetskopeWebTransactions_CL

Stage 2: where

| where TimeGenerated > ago(1h)

Stage 3: where

| where isnotempty(CsUsername) and isnotempty(XCsApp)

Stage 4: where

| where XCsApp has_any ('Dropbox', 'Google Drive', 'OneDrive', 'Box', 'iCloud', 'pCloud', 'MEGA', 'MediaFire', 'WeTransfer')

Stage 5: where

| where XCsAppInstanceTag contains 'Personal' 
    or XCsAppInstanceName contains 'Personal'
    or XCsAppTags contains 'Unsanctioned'
    or not(XCsAppTags contains 'Enterprise')

Stage 6: summarize

| summarize 
    TotalBytes = sum(Bytes),
    UploadBytes = sum(CsBytes),
    DownloadBytes = sum(ScBytes),
    FileCount = dcount(XCsAppObjectName),
    Files = make_set(XCsAppObjectName, 10),
    Activities = make_set(XCsAppActivity),
    EventCount = count()
    by CsUsername, XCsApp, XCsAppCategory, XCsAppInstanceName, XCsAppTags, XCDevice, XCCountry

Stage 7: extend

| extend 
    TotalMB = round(TotalBytes / 1048576.0, 2),
    UploadMB = round(UploadBytes / 1048576.0, 2),
    DownloadMB = round(DownloadBytes / 1048576.0, 2)

Stage 8: where

| where TotalMB > heavyUsageThresholdMB or FileCount > 50

Stage 9: project

| project 
    TimeGenerated = now(),
    User = CsUsername,
    CloudApplication = XCsApp,
    AppCategory = XCsAppCategory,
    AppInstance = XCsAppInstanceName,
    AppTags = XCsAppTags,
    TotalDataMB = TotalMB,
    UploadMB,
    DownloadMB,
    FileCount,
    Files,
    Activities,
    Device = XCDevice,
    Country = XCCountry,
    EventCount

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)
FileCountgt
  • 50 transforms: cased
TotalMBgt
  • 500 transforms: cased
XCsAppis_not_null
  • (no value, null check)
XCsAppmatch
  • Box
  • Dropbox
  • Google Drive
  • MEGA
  • MediaFire
  • OneDrive
  • WeTransfer
  • iCloud
  • pCloud
XCsAppInstanceNamecontains
  • Personal
XCsAppInstanceTagcontains
  • Personal
XCsAppTagscontains
  • Unsanctioned

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
Activitiesproject
AppCategoryproject
AppInstanceproject
AppTagsproject
CloudApplicationproject
Countryproject
Deviceproject
DownloadMBproject
EventCountproject
FileCountproject
Filesproject
TimeGeneratedproject
TotalDataMBproject
UploadMBproject
Userproject