Discord CDN Risky File Download
Id | 010bd98c-a6be-498c-bdcd-502308c0fdae |
Rulename | Discord CDN Risky File Download |
Description | Identifies callouts to Discord CDN addresses for risky file extensions. This detection will trigger when a callout for a risky file is made to a discord server that has only been seen once in your environment. Unique discord servers are identified using the server ID that is included in the request URL (DiscordServerId in query). Discord CDN has been used in multiple campaigns to download additional payloads |
Severity | Medium |
Tactics | CommandAndControl |
Techniques | T1071.001 |
Required data connectors | CefAma |
Kind | Scheduled |
Query frequency | 1d |
Query period | 1d |
Trigger threshold | 0 |
Trigger operator | gt |
Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Zscaler Internet Access/Analytic Rules/DiscordCDNRiskyDownload.yaml |
Version | 1.0.4 |
Arm template | 010bd98c-a6be-498c-bdcd-502308c0fdae.json |
let connectionThreshold = 1;
let riskyExtensions = dynamic([".bin",".exe",".dll",".bin",".msi"]);
CommonSecurityLog
| where DeviceVendor =~ "ZScaler"
| where RequestURL has_any("media.discordapp.net", "cdn.discordapp.com")
| where RequestURL has "attachments"
| where DeviceAction !~ "blocked"
| extend DiscordServerId = extract(@"\/attachments\/([0-9]+)\/", 1, RequestURL)
| summarize dcount(RequestURL), make_set(SourceUserName), make_set(SourceIP), make_set(RequestURL), min(TimeGenerated), max(TimeGenerated), make_set(DeviceAction) by DiscordServerId, DeviceProduct
| where dcount_RequestURL <= connectionThreshold
| mv-expand set_SourceUserName to typeof(string), set_RequestURL to typeof(string), set_DeviceAction to typeof(string), set_SourceIP to typeof(string)
| summarize by DiscordServerId, DeviceProduct, dcount_RequestURL, set_SourceUserName, min_TimeGenerated, max_TimeGenerated, set_DeviceAction, set_SourceIP, set_RequestURL
| project StartTime=min_TimeGenerated, EndTime=max_TimeGenerated, DeviceActionTaken=set_DeviceAction, DeviceProduct, SourceUser=set_SourceUserName, SourceIP=set_SourceIP, RequestURL=set_RequestURL
| where RequestURL has_any (riskyExtensions)
entityMappings:
- fieldMappings:
- columnName: SourceUser
identifier: FullName
entityType: Account
- fieldMappings:
- columnName: SourceIP
identifier: Address
entityType: IP
- fieldMappings:
- columnName: RequestURL
identifier: Url
entityType: URL
triggerThreshold: 0
severity: Medium
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Zscaler Internet Access/Analytic Rules/DiscordCDNRiskyDownload.yaml
queryFrequency: 1d
status: Available
tags:
- Discord
relevantTechniques:
- T1071.001
triggerOperator: gt
id: 010bd98c-a6be-498c-bdcd-502308c0fdae
requiredDataConnectors:
- connectorId: CefAma
dataTypes:
- CommonSecurityLog
version: 1.0.4
name: Discord CDN Risky File Download
description: |
'Identifies callouts to Discord CDN addresses for risky file extensions. This detection will trigger when a callout for a risky file is made to a discord server that has only been seen once in your environment. Unique discord servers are identified using the server ID that is included in the request URL (DiscordServerId in query). Discord CDN has been used in multiple campaigns to download additional payloads'
query: |
let connectionThreshold = 1;
let riskyExtensions = dynamic([".bin",".exe",".dll",".bin",".msi"]);
CommonSecurityLog
| where DeviceVendor =~ "ZScaler"
| where RequestURL has_any("media.discordapp.net", "cdn.discordapp.com")
| where RequestURL has "attachments"
| where DeviceAction !~ "blocked"
| extend DiscordServerId = extract(@"\/attachments\/([0-9]+)\/", 1, RequestURL)
| summarize dcount(RequestURL), make_set(SourceUserName), make_set(SourceIP), make_set(RequestURL), min(TimeGenerated), max(TimeGenerated), make_set(DeviceAction) by DiscordServerId, DeviceProduct
| where dcount_RequestURL <= connectionThreshold
| mv-expand set_SourceUserName to typeof(string), set_RequestURL to typeof(string), set_DeviceAction to typeof(string), set_SourceIP to typeof(string)
| summarize by DiscordServerId, DeviceProduct, dcount_RequestURL, set_SourceUserName, min_TimeGenerated, max_TimeGenerated, set_DeviceAction, set_SourceIP, set_RequestURL
| project StartTime=min_TimeGenerated, EndTime=max_TimeGenerated, DeviceActionTaken=set_DeviceAction, DeviceProduct, SourceUser=set_SourceUserName, SourceIP=set_SourceIP, RequestURL=set_RequestURL
| where RequestURL has_any (riskyExtensions)
tactics:
- CommandAndControl
queryPeriod: 1d
kind: Scheduled
{
"$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/010bd98c-a6be-498c-bdcd-502308c0fdae')]",
"kind": "Scheduled",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/010bd98c-a6be-498c-bdcd-502308c0fdae')]",
"properties": {
"alertRuleTemplateName": "010bd98c-a6be-498c-bdcd-502308c0fdae",
"customDetails": null,
"description": "'Identifies callouts to Discord CDN addresses for risky file extensions. This detection will trigger when a callout for a risky file is made to a discord server that has only been seen once in your environment. Unique discord servers are identified using the server ID that is included in the request URL (DiscordServerId in query). Discord CDN has been used in multiple campaigns to download additional payloads'\n",
"displayName": "Discord CDN Risky File Download",
"enabled": true,
"entityMappings": [
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "SourceUser",
"identifier": "FullName"
}
]
},
{
"entityType": "IP",
"fieldMappings": [
{
"columnName": "SourceIP",
"identifier": "Address"
}
]
},
{
"entityType": "URL",
"fieldMappings": [
{
"columnName": "RequestURL",
"identifier": "Url"
}
]
}
],
"OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Zscaler Internet Access/Analytic Rules/DiscordCDNRiskyDownload.yaml",
"query": "let connectionThreshold = 1;\nlet riskyExtensions = dynamic([\".bin\",\".exe\",\".dll\",\".bin\",\".msi\"]);\nCommonSecurityLog\n| where DeviceVendor =~ \"ZScaler\"\n| where RequestURL has_any(\"media.discordapp.net\", \"cdn.discordapp.com\")\n| where RequestURL has \"attachments\"\n| where DeviceAction !~ \"blocked\"\n| extend DiscordServerId = extract(@\"\\/attachments\\/([0-9]+)\\/\", 1, RequestURL)\n| summarize dcount(RequestURL), make_set(SourceUserName), make_set(SourceIP), make_set(RequestURL), min(TimeGenerated), max(TimeGenerated), make_set(DeviceAction) by DiscordServerId, DeviceProduct\n| where dcount_RequestURL <= connectionThreshold\n| mv-expand set_SourceUserName to typeof(string), set_RequestURL to typeof(string), set_DeviceAction to typeof(string), set_SourceIP to typeof(string)\n| summarize by DiscordServerId, DeviceProduct, dcount_RequestURL, set_SourceUserName, min_TimeGenerated, max_TimeGenerated, set_DeviceAction, set_SourceIP, set_RequestURL\n| project StartTime=min_TimeGenerated, EndTime=max_TimeGenerated, DeviceActionTaken=set_DeviceAction, DeviceProduct, SourceUser=set_SourceUserName, SourceIP=set_SourceIP, RequestURL=set_RequestURL\n| where RequestURL has_any (riskyExtensions)\n",
"queryFrequency": "P1D",
"queryPeriod": "P1D",
"severity": "Medium",
"status": "Available",
"subTechniques": [
"T1071.001"
],
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"tactics": [
"CommandAndControl"
],
"tags": [
"Discord"
],
"techniques": [
"T1071"
],
"templateVersion": "1.0.4",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0
},
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
}
]
}