New executable via Office FileUploaded Operation
Id | d722831e-88f5-4e25-b106-4ef6e29f8c13 |
Rulename | 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 users workspace. This may be indication of a staging location for malware or other malicious activity. |
Severity | Low |
Tactics | CommandAndControl LateralMovement |
Techniques | T1105 T1570 |
Required data connectors | Office365 |
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/Microsoft 365/Analytic Rules/Office_Uploaded_Executables.yaml |
Version | 2.0.5 |
Arm template | d722831e-88f5-4e25-b106-4ef6e29f8c13.json |
// a threshold can be enabled, see commented line below for PrevSeenCount
let threshold = 2;
let uploadOp = 'FileUploaded';
// Extensions that are interesting. Add/Remove to this list as you see fit
let execExt = dynamic(['exe', 'inf', 'gzip', 'cmd', 'bat']);
let starttime = 8d;
let endtime = 1d;
OfficeActivity | where TimeGenerated >= ago(endtime)
// Limited to File Uploads due to potential noise, comment out the Operation statement below to include any operation type
// Additional, but potentially noisy operation types that include Uploads and Downloads can be included by adding the following - Operation contains "upload" or Operation contains "download"
| where Operation =~ uploadOp
| where SourceFileExtension has_any (execExt)
| project TimeGenerated, OfficeId, OfficeWorkload, RecordType, Operation, UserType, UserKey, UserId, ClientIP, UserAgent, Site_Url, SourceRelativeUrl, SourceFileName
| join kind= leftanti (
OfficeActivity | where TimeGenerated between (ago(starttime) .. ago(endtime))
| where Operation =~ uploadOp
| where SourceFileExtension has_any (execExt)
| summarize SourceRelativeUrl = make_set(SourceRelativeUrl, 100000), UserId = make_set(UserId, 100000) , PrevSeenCount = count() by SourceFileName
// To exclude previous matches when only above a specific count, change threshold above and uncomment the line below
//| 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, '@|\\.', '_'))
// identify when UserId is not a match to the specific site url personal folder reference
| 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), OfficeIds = make_list(OfficeId, 100000), SourceRelativeUrls = make_list(SourceRelativeUrl, 100000), FileNames = make_list(SourceFileName, 100000)
by OfficeWorkload, RecordType, Operation, UserType, UserKey, UserId, ClientIP, Site_Url, SiteUrlUserFolder, UserIdUserFolderFormat, UserIdDiffThanUserFolder
| extend AccountName = tostring(split(UserId, "@")[0]), AccountUPNSuffix = tostring(split(UserId, "@")[1])
relevantTechniques:
- T1105
- T1570
name: New executable via Office FileUploaded Operation
requiredDataConnectors:
- dataTypes:
- OfficeActivity (SharePoint)
connectorId: Office365
entityMappings:
- fieldMappings:
- identifier: FullName
columnName: UserId
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
entityType: Account
- fieldMappings:
- identifier: Address
columnName: ClientIP
entityType: IP
- fieldMappings:
- identifier: Url
columnName: Site_Url
entityType: URL
- fieldMappings:
- identifier: Name
columnName: FileNames
entityType: File
triggerThreshold: 0
id: d722831e-88f5-4e25-b106-4ef6e29f8c13
tactics:
- CommandAndControl
- LateralMovement
version: 2.0.5
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft 365/Analytic Rules/Office_Uploaded_Executables.yaml
queryPeriod: 8d
kind: Scheduled
queryFrequency: 1d
severity: Low
status: Available
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 users workspace.
This may be indication of a staging location for malware or other malicious activity.'
query: |
// a threshold can be enabled, see commented line below for PrevSeenCount
let threshold = 2;
let uploadOp = 'FileUploaded';
// Extensions that are interesting. Add/Remove to this list as you see fit
let execExt = dynamic(['exe', 'inf', 'gzip', 'cmd', 'bat']);
let starttime = 8d;
let endtime = 1d;
OfficeActivity | where TimeGenerated >= ago(endtime)
// Limited to File Uploads due to potential noise, comment out the Operation statement below to include any operation type
// Additional, but potentially noisy operation types that include Uploads and Downloads can be included by adding the following - Operation contains "upload" or Operation contains "download"
| where Operation =~ uploadOp
| where SourceFileExtension has_any (execExt)
| project TimeGenerated, OfficeId, OfficeWorkload, RecordType, Operation, UserType, UserKey, UserId, ClientIP, UserAgent, Site_Url, SourceRelativeUrl, SourceFileName
| join kind= leftanti (
OfficeActivity | where TimeGenerated between (ago(starttime) .. ago(endtime))
| where Operation =~ uploadOp
| where SourceFileExtension has_any (execExt)
| summarize SourceRelativeUrl = make_set(SourceRelativeUrl, 100000), UserId = make_set(UserId, 100000) , PrevSeenCount = count() by SourceFileName
// To exclude previous matches when only above a specific count, change threshold above and uncomment the line below
//| 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, '@|\\.', '_'))
// identify when UserId is not a match to the specific site url personal folder reference
| 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), OfficeIds = make_list(OfficeId, 100000), SourceRelativeUrls = make_list(SourceRelativeUrl, 100000), FileNames = make_list(SourceFileName, 100000)
by OfficeWorkload, RecordType, Operation, UserType, UserKey, UserId, ClientIP, Site_Url, SiteUrlUserFolder, UserIdUserFolderFormat, UserIdDiffThanUserFolder
| extend AccountName = tostring(split(UserId, "@")[0]), AccountUPNSuffix = tostring(split(UserId, "@")[1])
triggerOperator: gt
{
"$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/d722831e-88f5-4e25-b106-4ef6e29f8c13')]",
"kind": "Scheduled",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/d722831e-88f5-4e25-b106-4ef6e29f8c13')]",
"properties": {
"alertRuleTemplateName": "d722831e-88f5-4e25-b106-4ef6e29f8c13",
"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 users workspace.\nThis may be indication of a staging location for malware or other malicious activity.'\n",
"displayName": "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/Microsoft 365/Analytic Rules/Office_Uploaded_Executables.yaml",
"query": "// a threshold can be enabled, see commented line below for PrevSeenCount\nlet threshold = 2;\nlet uploadOp = 'FileUploaded';\n// Extensions that are interesting. Add/Remove to this list as you see fit\nlet execExt = dynamic(['exe', 'inf', 'gzip', 'cmd', 'bat']);\nlet starttime = 8d;\nlet endtime = 1d;\nOfficeActivity | where TimeGenerated >= ago(endtime)\n// Limited to File Uploads due to potential noise, comment out the Operation statement below to include any operation type\n// Additional, but potentially noisy operation types that include Uploads and Downloads can be included by adding the following - Operation contains \"upload\" or Operation contains \"download\"\n| where Operation =~ uploadOp\n| where SourceFileExtension has_any (execExt)\n| project TimeGenerated, OfficeId, OfficeWorkload, RecordType, Operation, UserType, UserKey, UserId, ClientIP, UserAgent, Site_Url, SourceRelativeUrl, SourceFileName\n| join kind= leftanti (\nOfficeActivity | where TimeGenerated between (ago(starttime) .. ago(endtime))\n| where Operation =~ uploadOp\n| where SourceFileExtension has_any (execExt)\n| summarize SourceRelativeUrl = make_set(SourceRelativeUrl, 100000), UserId = make_set(UserId, 100000) , PrevSeenCount = count() by SourceFileName\n// To exclude previous matches when only above a specific count, change threshold above and uncomment the line below\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// identify when UserId is not a match to the specific site url personal folder reference\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),\nUserAgents = make_list(UserAgent, 100000), OfficeIds = make_list(OfficeId, 100000), SourceRelativeUrls = make_list(SourceRelativeUrl, 100000), FileNames = make_list(SourceFileName, 100000)\nby OfficeWorkload, 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.5",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0
},
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
}
]
}