Detection rules › Kusto

Netskope - Unsanctioned/Risky Cloud App Access (Shadow IT)

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

Alerts when users access unsanctioned or risky cloud applications based on Cloud Confidence Level (CCL) and app tags. Detects Shadow IT usage.

MITRE ATT&CK coverage

TacticTechniques
Initial AccessT1199 Trusted Relationship
ExfiltrationT1567 Exfiltration Over Web Service

Rule body kusto

id: cdc01279-d6ea-41b1-a32d-49d726be95b8
name: Netskope - Unsanctioned/Risky Cloud App Access (Shadow IT)
description: |
  Alerts when users access unsanctioned or risky cloud applications based on Cloud Confidence Level (CCL) and app tags. Detects Shadow IT usage.
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: NetskopeWebTxConnector
    dataTypes:
      - NetskopeWebTransactions_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
  - Exfiltration
relevantTechniques:
  - T1199
  - T1567
query: |
  NetskopeWebTransactions_CL
  | where TimeGenerated > ago(1h)
  | where isnotempty(CsUsername) and isnotempty(XCsApp)
  | where XCsAppTags contains 'Unsanctioned' 
      or XCsAppCcl =~ 'poor'
      or XCsAppCcl =~ 'low'
      or XCsAppCci < 50
  | summarize 
      EventCount = count(),
      TotalBytesMB = round(sum(Bytes) / 1048576.0, 2),
      Activities = make_set(XCsAppActivity),
      FirstSeen = min(TimeGenerated),
      LastSeen = max(TimeGenerated)
      by 
      CsUsername,
      XCsApp,
      XCsAppCategory,
      XCsAppCcl,
      XCsAppCci,
      XCsAppTags,
      XCCountry,
      XCDevice
  | extend RiskLevel = case(
      XCsAppCci < 30, 'Critical',
      XCsAppCci < 50, 'High',
      XCsAppCci < 70, 'Medium',
      'Low')
  | project 
      TimeGenerated = LastSeen,
      User = CsUsername,
      RiskyApplication = XCsApp,
      AppCategory = XCsAppCategory,
      CloudConfidenceLevel = XCsAppCcl,
      CloudConfidenceIndex = XCsAppCci,
      AppTags = XCsAppTags,
      RiskLevel,
      Country = XCCountry,
      Device = XCDevice,
      Activities,
      EventCount,
      DataTransferMB = TotalBytesMB
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: User
  - entityType: CloudApplication
    fieldMappings:
      - identifier: Name
        columnName: RiskyApplication
version: 1.0.0
kind: Scheduled

Stages and Predicates

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 XCsAppTags contains 'Unsanctioned' 
    or XCsAppCcl =~ 'poor'
    or XCsAppCcl =~ 'low'
    or XCsAppCci < 50

Stage 5: summarize

| summarize 
    EventCount = count(),
    TotalBytesMB = round(sum(Bytes) / 1048576.0, 2),
    Activities = make_set(XCsAppActivity),
    FirstSeen = min(TimeGenerated),
    LastSeen = max(TimeGenerated)
    by 
    CsUsername,
    XCsApp,
    XCsAppCategory,
    XCsAppCcl,
    XCsAppCci,
    XCsAppTags,
    XCCountry,
    XCDevice

Stage 6: extend

| extend RiskLevel = case(
    XCsAppCci < 30, 'Critical',
    XCsAppCci < 50, 'High',
    XCsAppCci < 70, 'Medium',
    'Low')
RiskLevel =
ifXCsAppCci < 30'Critical'
elifXCsAppCci < 50'High'
elifXCsAppCci < 70'Medium'
else'Low'

Stage 7: project

| project 
    TimeGenerated = LastSeen,
    User = CsUsername,
    RiskyApplication = XCsApp,
    AppCategory = XCsAppCategory,
    CloudConfidenceLevel = XCsAppCcl,
    CloudConfidenceIndex = XCsAppCci,
    AppTags = XCsAppTags,
    RiskLevel,
    Country = XCCountry,
    Device = XCDevice,
    Activities,
    EventCount,
    DataTransferMB = TotalBytesMB

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)
XCsAppis_not_null
  • (no value, null check)
XCsAppCcilt
  • 50 transforms: cased
XCsAppCcleq
  • low
  • poor
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
AppTagsproject
CloudConfidenceIndexproject
CloudConfidenceLevelproject
Countryproject
DataTransferMBproject
Deviceproject
EventCountproject
RiskLevelproject
RiskyApplicationproject
TimeGeneratedproject
Userproject