Detection rules › Kusto

Dataverse - Malware found in SharePoint document management site

Status
available
Severity
medium
Time window
14d
Group by
MalwareUserId, SharePointUrl, Site_Url, SourceFileName, UserId
Source
github.com/Azure/Azure-Sentinel

This query identifies malware uploaded via Dynamics 365 document management or directly in SharePoint impacting Dataverse associated SharePoint sites.

MITRE ATT&CK coverage

TacticTechniques
Execution

Telemetry coverage

Rules detecting the same action

These rules filter on the same operation.

Rule body

id: 2e3878bb-d519-43aa-9992-ea069df099e4
kind: Scheduled
name: Dataverse - Malware found in SharePoint document management site
description: This query identifies malware uploaded via Dynamics 365 document management
  or directly in SharePoint impacting Dataverse associated SharePoint sites.
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: Dataverse
    dataTypes:
      - DataverseActivity
  - connectorId: Office365
    dataTypes:
      - OfficeActivity (SharePoint)
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Execution
relevantTechniques:
  - T1204
query: |
  let query_frequency = 15m;
    let malware_events = OfficeActivity
        | where OfficeWorkload == "SharePoint" and Operation == "FileMalwareDetected"
        | summarize by MalwareUserId = UserId, SourceFileName, Site_Url
        | join kind=inner (DataverseSharePointSites) on $left.Site_Url == $right.SharePointUrl;
    let file_upload_events = OfficeActivity
        | where OfficeWorkload == "SharePoint" and Operation == "FileUploaded"
        | project TimeGenerated, UserId, Site_Url, SourceFileName, ApplicationId, ClientIP;
    let d365_upload_events = DataverseActivity
        | where TimeGenerated >= ago(query_frequency)
        | where Message == "UploadDocument"
        | summarize by UserId, D365ClientIp = ClientIp;
    malware_events
    | join kind=inner (file_upload_events) on SourceFileName, Site_Url
    | lookup (d365_upload_events) on UserId
    | extend ClientIp = iif(ApplicationId == "00000007-0000-0000-c000-000000000000", D365ClientIp, ClientIP)
    | extend
        CloudAppId = int(32780),
        SharePointId = int(20892),
        AccountName = tostring(split(UserId, '@')[0]),
        UPNSuffix = tostring(split(UserId, '@')[1])
    | project
        TimeGenerated,
        UserId,
        ClientIp,
        InstanceUrl,
        SharePointUrl,
        SourceFileName,
        CloudAppId,
        SharePointId,
        AccountName,
        UPNSuffix
eventGroupingSettings:
  aggregationKind: SingleAlert
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: UPNSuffix
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: ClientIp
  - entityType: File
    fieldMappings:
      - identifier: Name
        columnName: SourceFileName
  - entityType: CloudApplication
    fieldMappings:
      - identifier: AppId
        columnName: CloudAppId
      - identifier: InstanceName
        columnName: InstanceUrl
  - entityType: CloudApplication
    fieldMappings:
      - identifier: AppId
        columnName: SharePointId
      - identifier: InstanceName
        columnName: SharePointUrl
alertDetailsOverride:
  alertDisplayNameFormat: 'Dataverse - Malware was found in SharePoint document management
    site for {{InstanceUrl}} '
  alertDescriptionFormat: A malicious file {{SourceFileName}} was found in SharePoint
    site {{SharePointUrl}}. The file was uploaded by {{UserId}}
version: 3.2.0

Stages and Predicates

Parameters

let query_frequency = 15m;

let malware_events is inlined into the numbered stages below.

Let binding: file_upload_events used in Stage 5

let file_upload_events = OfficeActivity
      | where OfficeWorkload == "SharePoint" and Operation == "FileUploaded"
      | project TimeGenerated, UserId, Site_Url, SourceFileName, ApplicationId, ClientIP;

Let binding: d365_upload_events used in Stage 6

let d365_upload_events = DataverseActivity
      | where TimeGenerated >= ago(query_frequency)
      | where Message == "UploadDocument"
      | summarize by UserId, D365ClientIp = ClientIp;

Stages 1 to 4 define let malware_events (the rule's main pipeline source); stages 5 to 9 run on it.

Stage 1: source

OfficeActivity

Stage 2: where

| where OfficeWorkload == "SharePoint" and Operation == "FileMalwareDetected"

Stage 3: summarize

| summarize by MalwareUserId = UserId, SourceFileName, Site_Url

Stage 4: join

| join kind=inner (DataverseSharePointSites) on $left.Site_Url == $right.SharePointUrl

Stage 5: join

malware_events
| join kind=inner (file_upload_events) on SourceFileName, Site_Url

Stage 6: kusto:lookup

| lookup (d365_upload_events) on UserId

Stage 7: extend

| extend ClientIp = iif(ApplicationId == "00000007-0000-0000-c000-000000000000", D365ClientIp, ClientIP)

Stage 8: extend

| extend
      CloudAppId = int(32780),
      SharePointId = int(20892),
      AccountName = tostring(split(UserId, '@')[0]),
      UPNSuffix = tostring(split(UserId, '@')[1])

Stage 9: project

| project
      TimeGenerated,
      UserId,
      ClientIp,
      InstanceUrl,
      SharePointUrl,
      SourceFileName,
      CloudAppId,
      SharePointId,
      AccountName,
      UPNSuffix

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
AccountNameproject
ClientIpproject
CloudAppIdproject
InstanceUrlproject
SharePointIdproject
SharePointUrlproject
SourceFileNameproject
TimeGeneratedproject
UPNSuffixproject
UserIdproject