Query Details

Office Activity Excessive Share Point Activity

Query

let query_frequency = 1h;
let query_period = 14d;
let query_lookback_end = 1d;
let query_window_checks = 6;
let score_threshold = 200000;
let home_tenant_domain = toscalar(
    _GetWatchlist("UUID-EntraIdTenantIds")
    | where Notes has "[HomeTenant]"
    | project trim_end(@"\.onmicrosoft\.com", OnMicrosoftDomain)
);
let onedrive_url = strcat("https://", home_tenant_domain, "-my.sharepoint.com/"); // https://contoso365-my.sharepoint.com/
let sharepoint_url = strcat("https://", home_tenant_domain, ".sharepoint.com/"); // https://contoso365.sharepoint.com/
let _DefaultSharePointAdministrators = toscalar(
    _GetWatchlist("Activity-ExpectedSignificantActivity")
    | where Activity == "SharePointAdministrator" and Notes has "[Default]"
    | summarize make_list(ActorPrincipalName)
);
OfficeActivity
| where TimeGenerated > ago(2 * query_frequency)
| where isnotempty(Site_Url) and not(UserId in (_DefaultSharePointAdministrators))
// Don't consider sites that were visited in the previous days
| join kind=leftanti(
    OfficeActivity
    | where TimeGenerated between (ago(query_period) .. ago(query_lookback_end))
    | where not(isempty(Site_Url)) and not(UserId in (_DefaultSharePointAdministrators))
    ) on Site_Url, UserId//, OfficeObjectId
// Remove operations where site is the default SharePoint site, OfficeObjectIds usually will be default images/files
| where not(Site_Url == sharepoint_url and Operation in ("FileAccessed", "FilePreviewed"))
// Remove operations where the user accesses default images of a site
| where not(OfficeObjectId has "/siteassets/")
// Remove operations where the user accesses themes files of a site
| where not(SourceFileExtension in ("spcolor", "sptheme"))
// Remove operations where the user visualizes thumbnails
| where not(SourceFileName endswith "Thumb.jpg")
// Remove operations where the user accesses JavaScript default files from sites/apps
| where not(OfficeWorkload == "SharePoint" and Operation in ("FileAccessed", "FileAccessedExtended")
    and SourceFileExtension == "js" and SourceRelativeUrl startswith "ClientSideAssets/")
// Remove operations where the user accesses the default view of a site/folder
| where not(OfficeWorkload == "SharePoint" and Operation in ("FileAccessed", "FileAccessedExtended") and SourceFileName in ("AllPages.aspx", "AllItems.aspx", "allitems.aspx", "ByAuthor.aspx", "Thumbnails.aspx"))
// Remove operations where the user accesses the default view of a site/folder
| where not(OfficeWorkload == "OneDrive" and Operation in ("FileAccessed", "FileAccessedExtended") and SourceFileName == "All.aspx")
// Remove presumably benign operations with high noise potential
| where not(OfficeWorkload == "SharePoint" and Operation in ("FileSyncUploadedFull"))
// Remove operations where the user visited his OneDrive personal folder
| where not(OfficeWorkload == "OneDrive" and Site_Url endswith strcat(replace(@'[@\.]', @'_', UserId), "/"))
// Remove operations where the user previews or recycles files from 1:1 Teams chats
| where not(OfficeWorkload == "OneDrive" and Operation in ("FilePreviewed", "FileRecycled")
    and OfficeObjectId has strcat("_", replace(@'\.', '_', tostring(split(UserId, "@")[-1])))
    and SourceRelativeUrl has_any ("Documents/Microsoft Teams Chat Files", "Documents/Archivos de chat de Microsoft Teams")
    )
// Remove operations of some characteristic jsons in Hub Sites
| where not(OfficeWorkload == "SharePoint" and SourceRelativeUrl == "_catalogs/hubsite")// and SourceFileName matches regex @"[a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12}\-\d{4}\.json")
// Custom enterprise filters
// It is recommended you filter a few specific site/operation pairs of your tenant that might generate noise for this query
// One example could be a welcome SharePoint site that is visited automatically by all users when opening a browser
// Another example, you should exclude Microsoft Teams Chat Files in SourceRelativeUrl paths (both in English and your native language), for OneDrive
| mv-expand QueryRange = range(now() - query_frequency + query_frequency/query_window_checks, now(), query_frequency/query_window_checks) to typeof(datetime)
| where TimeGenerated between ((QueryRange - query_frequency) .. QueryRange)
| summarize
    StartTime = min(TimeGenerated),
    EndTime = max(TimeGenerated),
    DistinctSites = dcount(Site_),
    DistinctObjects = dcount(OfficeObjectId),
    FileExtensions = make_set_if(tolower(SourceFileExtension), isnotempty(SourceFileExtension)),
    OperationCount = count(),
    Site_Urls = make_set(Site_Url, 500),
    SampleOfficeObjectIds = make_set(tostring(pack(Operation, OfficeObjectId)), 250),
    Operations = make_set(Operation, 200),
    ClientIPs = make_set_if(ClientIP, isnotempty(ClientIP)),
    IsManagedDevices = make_set_if(IsManagedDevice, isnotempty(IsManagedDevice))
    by UserId, QueryRange
| where DistinctSites > 1
| where not(array_length(Operations) == 1 and Operations[0] == "FilePreviewed")
| where EndTime > ago(query_frequency)
| extend Score = toint(pow(DistinctObjects, 2) * pow(DistinctSites, 2) * pow(array_length(FileExtensions), 2) / tolong(OperationCount))
| where Score > score_threshold
| summarize
    StartTime = min(StartTime),
    EndTime = max(EndTime),
    DistinctSites = max(DistinctSites),
    DistinctObjects = max(DistinctObjects),
    FileExtensions = make_set(FileExtensions),
    OperationCount = max(OperationCount),
    Site_Urls = array_sort_asc(make_set(Site_Urls, 500)),
    SampleOfficeObjectIds = array_sort_asc(make_set(SampleOfficeObjectIds, 250)),
    Operations = make_set(Operations, 200),
    ClientIPs = make_set(ClientIPs),
    IsManagedDevices = make_set(IsManagedDevices),
    Score = max(Score)
    by UserId
| sort by Score desc
| project
    StartTime,
    EndTime,
    UserId,
    ClientIPs,
    IsManagedDevices,
    Score,
    Operations,
    OperationCount,
    DistinctSites,
    DistinctObjects,
    FileExtensions,
    Site_Urls,
    SampleOfficeObjectIds

Explanation

This KQL query is designed to identify unusual or potentially suspicious activity in SharePoint and OneDrive by analyzing user interactions over a specified period. Here's a simplified breakdown of what the query does:

  1. Setup Parameters:

    • Defines time intervals and thresholds for analysis, such as query_frequency (1 hour), query_period (14 days), and score_threshold (200,000).
    • Retrieves the domain of the home tenant and constructs URLs for OneDrive and SharePoint.
    • Identifies default SharePoint administrators to exclude them from the analysis.
  2. Filter Recent Activity:

    • Focuses on recent activity within the last two hours.
    • Excludes actions by default SharePoint administrators.
  3. Exclude Previously Visited Sites:

    • Removes sites visited in the past 14 days but not in the last day to focus on new or unusual activity.
  4. Filter Out Common or Benign Operations:

    • Excludes operations on default SharePoint sites, common file types (like JavaScript and theme files), and typical user actions (like accessing personal OneDrive folders or Teams chat files).
    • Removes operations related to default views and high-noise activities.
  5. Analyze and Score Activity:

    • Expands the query to check activity within smaller time windows.
    • Summarizes activity by user, capturing details like distinct sites accessed, file extensions used, and operations performed.
    • Calculates a "Score" based on the diversity and volume of activity, emphasizing unusual patterns.
  6. Filter and Sort Results:

    • Filters out users with low scores or minimal activity.
    • Sorts the results by score in descending order to highlight the most unusual activities.
  7. Output:

    • Projects relevant details for each user, including the time range of activity, user ID, client IPs, device management status, score, and a summary of operations and sites accessed.

Overall, this query is designed to detect potentially suspicious behavior by identifying users who access a wide variety of sites and files in a short period, which might indicate unauthorized or unusual activity.

Details

Jose Sebastián Canós profile picture

Jose Sebastián Canós

Released: August 21, 2025

Tables

OfficeActivity

Keywords

OfficeActivitySharePointOneDriveUserDevicesClientIPsOperationsSite_UrlsFileExtensions

Operators

lettoscalarhasprojecttrim_endstrcatsummarizemake_listagoisnotemptyinjoinkind=leftantibetweenisemptyonnotandhas_anyendswithstartswithreplacetostringsplitmv-expandrangetotypeofdatetimeminmaxdcountmake_set_iftolowercountmake_setarray_lengthextendtointpowtolongarray_sort_ascbysortdesc

Actions

GitHub