Office 365 - New Executable via Office FileUploaded Operation
Id | 178c62b4-d5e5-40f5-8eab-7fccd0051e7a |
Rulename | Office 365 - New Executable via Office FileUploaded Operation |
Description | Identifies when executable file types are uploaded to Office services such as SharePoint and OneDrive. List currently includes exe, inf, gzip, cmd, bat file extensions. Additionally, identifies when a given user is uploading these files to another user’s workspace. This may be an indication of a staging location for malware or other malicious activity. |
Severity | Low |
Tactics | CommandAndControl LateralMovement |
Techniques | T1105 T1570 |
Required data connectors | AzureActiveDirectory |
Kind | Scheduled |
Query frequency | 1d |
Query period | 8d |
Trigger threshold | 0 |
Trigger operator | gt |
Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Global Secure Access/Analytic Rules/Office 365 - Office_Uploaded_Executables.yaml |
Version | 2.0.6 |
Arm template | 178c62b4-d5e5-40f5-8eab-7fccd0051e7a.json |
let threshold = 2;
let uploadOp = 'FileUploaded';
let execExt = dynamic(['exe', 'inf', 'gzip', 'cmd', 'bat']);
let starttime = 8d;
let endtime = 1d;
EnrichedMicrosoft365AuditLogs
| where TimeGenerated >= ago(endtime)
| where Operation == uploadOp
| extend SourceFileExtension = extract(@"\.([^\./]+)$", 1, tostring(parse_json(tostring(AdditionalProperties)).SourceFileName)) // Extract file extension
| where SourceFileExtension in (execExt)
| extend Site_Url = tostring(parse_json(tostring(AdditionalProperties)).SiteUrl)
| extend SourceRelativeUrl = tostring(parse_json(tostring(AdditionalProperties)).SourceRelativeUrl)
| extend SourceFileName = tostring(parse_json(tostring(AdditionalProperties)).SourceFileName)
| project TimeGenerated, Id, Workload, RecordType, Operation, UserType, UserKey, UserId, ClientIp, UserAgent = tostring(parse_json(tostring(AdditionalProperties)).UserAgent), Site_Url, SourceRelativeUrl, SourceFileName
| join kind=leftanti (
EnrichedMicrosoft365AuditLogs
| where TimeGenerated between (ago(starttime) .. ago(endtime))
| where Operation == uploadOp
| extend SourceFileExtension = extract(@"\.([^\./]+)$", 1, tostring(parse_json(tostring(AdditionalProperties)).SourceFileName)) // Extract file extension
| where SourceFileExtension in (execExt)
| extend SourceRelativeUrl = tostring(parse_json(tostring(AdditionalProperties)).SourceRelativeUrl)
| summarize SourceRelativeUrl = make_set(SourceRelativeUrl, 100000), UserId = make_set(UserId, 100000), PrevSeenCount = count() by SourceFileName = tostring(parse_json(tostring(AdditionalProperties)).SourceFileName)
// Uncomment the line below to enforce the threshold
// | where PrevSeenCount > threshold
| mvexpand SourceRelativeUrl, UserId
| extend SourceRelativeUrl = tostring(SourceRelativeUrl), UserId = tostring(UserId)
) on SourceFileName, SourceRelativeUrl, UserId
| extend SiteUrlUserFolder = tolower(split(Site_Url, '/')[-2])
| extend UserIdUserFolderFormat = tolower(replace_regex(UserId, '@|\\.', '_'))
| extend UserIdDiffThanUserFolder = iff(Site_Url has '/personal/' and SiteUrlUserFolder != UserIdUserFolderFormat, true, false)
| summarize TimeGenerated = make_list(TimeGenerated, 100000), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), UserAgents = make_list(UserAgent, 100000), Ids = make_list(Id, 100000), SourceRelativeUrls = make_list(SourceRelativeUrl, 100000), FileNames = make_list(SourceFileName, 100000)
by Workload, RecordType, Operation, UserType, UserKey, UserId, ClientIp, Site_Url, SiteUrlUserFolder, UserIdUserFolderFormat, UserIdDiffThanUserFolder
| extend AccountName = tostring(split(UserId, "@")[0]), AccountUPNSuffix = tostring(split(UserId, "@")[1])
queryPeriod: 8d
version: 2.0.6
tactics:
- CommandAndControl
- LateralMovement
queryFrequency: 1d
id: 178c62b4-d5e5-40f5-8eab-7fccd0051e7a
triggerOperator: gt
requiredDataConnectors:
- dataTypes:
- EnrichedMicrosoft365AuditLogs
connectorId: AzureActiveDirectory
severity: Low
entityMappings:
- entityType: Account
fieldMappings:
- columnName: UserId
identifier: FullName
- columnName: AccountName
identifier: Name
- columnName: AccountUPNSuffix
identifier: UPNSuffix
- entityType: IP
fieldMappings:
- columnName: ClientIp
identifier: Address
- entityType: URL
fieldMappings:
- columnName: Site_Url
identifier: Url
- entityType: File
fieldMappings:
- columnName: FileNames
identifier: Name
triggerThreshold: 0
relevantTechniques:
- T1105
- T1570
query: |
let threshold = 2;
let uploadOp = 'FileUploaded';
let execExt = dynamic(['exe', 'inf', 'gzip', 'cmd', 'bat']);
let starttime = 8d;
let endtime = 1d;
EnrichedMicrosoft365AuditLogs
| where TimeGenerated >= ago(endtime)
| where Operation == uploadOp
| extend SourceFileExtension = extract(@"\.([^\./]+)$", 1, tostring(parse_json(tostring(AdditionalProperties)).SourceFileName)) // Extract file extension
| where SourceFileExtension in (execExt)
| extend Site_Url = tostring(parse_json(tostring(AdditionalProperties)).SiteUrl)
| extend SourceRelativeUrl = tostring(parse_json(tostring(AdditionalProperties)).SourceRelativeUrl)
| extend SourceFileName = tostring(parse_json(tostring(AdditionalProperties)).SourceFileName)
| project TimeGenerated, Id, Workload, RecordType, Operation, UserType, UserKey, UserId, ClientIp, UserAgent = tostring(parse_json(tostring(AdditionalProperties)).UserAgent), Site_Url, SourceRelativeUrl, SourceFileName
| join kind=leftanti (
EnrichedMicrosoft365AuditLogs
| where TimeGenerated between (ago(starttime) .. ago(endtime))
| where Operation == uploadOp
| extend SourceFileExtension = extract(@"\.([^\./]+)$", 1, tostring(parse_json(tostring(AdditionalProperties)).SourceFileName)) // Extract file extension
| where SourceFileExtension in (execExt)
| extend SourceRelativeUrl = tostring(parse_json(tostring(AdditionalProperties)).SourceRelativeUrl)
| summarize SourceRelativeUrl = make_set(SourceRelativeUrl, 100000), UserId = make_set(UserId, 100000), PrevSeenCount = count() by SourceFileName = tostring(parse_json(tostring(AdditionalProperties)).SourceFileName)
// Uncomment the line below to enforce the threshold
// | where PrevSeenCount > threshold
| mvexpand SourceRelativeUrl, UserId
| extend SourceRelativeUrl = tostring(SourceRelativeUrl), UserId = tostring(UserId)
) on SourceFileName, SourceRelativeUrl, UserId
| extend SiteUrlUserFolder = tolower(split(Site_Url, '/')[-2])
| extend UserIdUserFolderFormat = tolower(replace_regex(UserId, '@|\\.', '_'))
| extend UserIdDiffThanUserFolder = iff(Site_Url has '/personal/' and SiteUrlUserFolder != UserIdUserFolderFormat, true, false)
| summarize TimeGenerated = make_list(TimeGenerated, 100000), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), UserAgents = make_list(UserAgent, 100000), Ids = make_list(Id, 100000), SourceRelativeUrls = make_list(SourceRelativeUrl, 100000), FileNames = make_list(SourceFileName, 100000)
by Workload, RecordType, Operation, UserType, UserKey, UserId, ClientIp, Site_Url, SiteUrlUserFolder, UserIdUserFolderFormat, UserIdDiffThanUserFolder
| extend AccountName = tostring(split(UserId, "@")[0]), AccountUPNSuffix = tostring(split(UserId, "@")[1])
kind: Scheduled
name: Office 365 - New Executable via Office FileUploaded Operation
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Global Secure Access/Analytic Rules/Office 365 - Office_Uploaded_Executables.yaml
description: |
Identifies when executable file types are uploaded to Office services such as SharePoint and OneDrive.
List currently includes exe, inf, gzip, cmd, bat file extensions.
Additionally, identifies when a given user is uploading these files to another user's workspace.
This may be an indication of a staging location for malware or other malicious activity.
status: Available
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workspace": {
"type": "String"
}
},
"resources": [
{
"apiVersion": "2024-01-01-preview",
"id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/178c62b4-d5e5-40f5-8eab-7fccd0051e7a')]",
"kind": "Scheduled",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/178c62b4-d5e5-40f5-8eab-7fccd0051e7a')]",
"properties": {
"alertRuleTemplateName": "178c62b4-d5e5-40f5-8eab-7fccd0051e7a",
"customDetails": null,
"description": "Identifies when executable file types are uploaded to Office services such as SharePoint and OneDrive.\nList currently includes exe, inf, gzip, cmd, bat file extensions.\nAdditionally, identifies when a given user is uploading these files to another user's workspace.\nThis may be an indication of a staging location for malware or other malicious activity.\n",
"displayName": "Office 365 - New Executable via Office FileUploaded Operation",
"enabled": true,
"entityMappings": [
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "UserId",
"identifier": "FullName"
},
{
"columnName": "AccountName",
"identifier": "Name"
},
{
"columnName": "AccountUPNSuffix",
"identifier": "UPNSuffix"
}
]
},
{
"entityType": "IP",
"fieldMappings": [
{
"columnName": "ClientIp",
"identifier": "Address"
}
]
},
{
"entityType": "URL",
"fieldMappings": [
{
"columnName": "Site_Url",
"identifier": "Url"
}
]
},
{
"entityType": "File",
"fieldMappings": [
{
"columnName": "FileNames",
"identifier": "Name"
}
]
}
],
"OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Global Secure Access/Analytic Rules/Office 365 - Office_Uploaded_Executables.yaml",
"query": "let threshold = 2;\nlet uploadOp = 'FileUploaded';\nlet execExt = dynamic(['exe', 'inf', 'gzip', 'cmd', 'bat']);\nlet starttime = 8d;\nlet endtime = 1d;\nEnrichedMicrosoft365AuditLogs\n| where TimeGenerated >= ago(endtime)\n| where Operation == uploadOp\n| extend SourceFileExtension = extract(@\"\\.([^\\./]+)$\", 1, tostring(parse_json(tostring(AdditionalProperties)).SourceFileName)) // Extract file extension\n| where SourceFileExtension in (execExt)\n| extend Site_Url = tostring(parse_json(tostring(AdditionalProperties)).SiteUrl)\n| extend SourceRelativeUrl = tostring(parse_json(tostring(AdditionalProperties)).SourceRelativeUrl)\n| extend SourceFileName = tostring(parse_json(tostring(AdditionalProperties)).SourceFileName)\n| project TimeGenerated, Id, Workload, RecordType, Operation, UserType, UserKey, UserId, ClientIp, UserAgent = tostring(parse_json(tostring(AdditionalProperties)).UserAgent), Site_Url, SourceRelativeUrl, SourceFileName\n| join kind=leftanti (\n EnrichedMicrosoft365AuditLogs\n | where TimeGenerated between (ago(starttime) .. ago(endtime))\n | where Operation == uploadOp\n | extend SourceFileExtension = extract(@\"\\.([^\\./]+)$\", 1, tostring(parse_json(tostring(AdditionalProperties)).SourceFileName)) // Extract file extension\n | where SourceFileExtension in (execExt)\n | extend SourceRelativeUrl = tostring(parse_json(tostring(AdditionalProperties)).SourceRelativeUrl)\n | summarize SourceRelativeUrl = make_set(SourceRelativeUrl, 100000), UserId = make_set(UserId, 100000), PrevSeenCount = count() by SourceFileName = tostring(parse_json(tostring(AdditionalProperties)).SourceFileName)\n // Uncomment the line below to enforce the threshold\n // | where PrevSeenCount > threshold\n | mvexpand SourceRelativeUrl, UserId\n | extend SourceRelativeUrl = tostring(SourceRelativeUrl), UserId = tostring(UserId)\n) on SourceFileName, SourceRelativeUrl, UserId\n| extend SiteUrlUserFolder = tolower(split(Site_Url, '/')[-2])\n| extend UserIdUserFolderFormat = tolower(replace_regex(UserId, '@|\\\\.', '_'))\n| extend UserIdDiffThanUserFolder = iff(Site_Url has '/personal/' and SiteUrlUserFolder != UserIdUserFolderFormat, true, false)\n| summarize TimeGenerated = make_list(TimeGenerated, 100000), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), UserAgents = make_list(UserAgent, 100000), Ids = make_list(Id, 100000), SourceRelativeUrls = make_list(SourceRelativeUrl, 100000), FileNames = make_list(SourceFileName, 100000)\nby Workload, RecordType, Operation, UserType, UserKey, UserId, ClientIp, Site_Url, SiteUrlUserFolder, UserIdUserFolderFormat, UserIdDiffThanUserFolder\n| extend AccountName = tostring(split(UserId, \"@\")[0]), AccountUPNSuffix = tostring(split(UserId, \"@\")[1])\n",
"queryFrequency": "P1D",
"queryPeriod": "P8D",
"severity": "Low",
"status": "Available",
"subTechniques": [],
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"tactics": [
"CommandAndControl",
"LateralMovement"
],
"techniques": [
"T1105",
"T1570"
],
"templateVersion": "2.0.6",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0
},
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
}
]
}