Request for single resource on domain
Id | 4d500e6d-c984-43a3-9f39-7edec8dcc04d |
Rulename | Request for single resource on domain |
Description | This will look for connections to a domain where only a single file is requested, this is unusual as most modern web applications require additional recources. This type of activity is often assocaited with malware beaconing or tracking URL’s delivered in emails. Developed for Zscaler but applicable to any outbound web logging. |
Severity | Low |
Tactics | CommandAndControl |
Techniques | T1102 T1071 |
Required data connectors | Zscaler |
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/Zscaler-LowVolumeDomainRequests.yaml |
Version | 1.0.1 |
Arm template | 4d500e6d-c984-43a3-9f39-7edec8dcc04d.json |
let scriptExtensions = dynamic([".php", ".aspx", ".asp", ".cfml"]);
//The number of URI's seen to be suspicious, higher = less likely to be suspicious
let uriThreshold = 1;
CommonSecurityLog
// Only look at connections that were allowed through the web proxy
| where DeviceVendor =~ "Zscaler" and DeviceAction =~ "Allowed"
// Only look where some data was exchanged.
| where SentBytes > 0 and ReceivedBytes > 0
// Extract the Domain
| extend Domain = iff(countof(DestinationHostName,'.') >= 2, strcat(split(DestinationHostName,'.')[-2], '.',split(DestinationHostName,'.')[-1]), DestinationHostName)
| extend GetData=iff(RequestURL == "?", 1, 0)
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), makelist(RequestURL), makelist(DestinationIP), makelist(SourceIP), numOfConnections = count(), make_set(RequestMethod), max(GetData), max(RequestContext) by Domain
// Determine the number of URIs that have been visited for the domain
| extend destinationURI = arraylength(list_RequestURL)
| where destinationURI <= uriThreshold
| where tostring(list_RequestURL) has_any(scriptExtensions)
//Remove matches with referer
| where max_RequestContext == ""
//Keep requests where data was trasferred either in a GET with parameters or a POST
| where set_RequestMethod in~ ("POST") or max_GetData == 1
//Defeat email click tracking, may increase FN's while decreasing FP's
| where list_RequestURL !has "click" and set_RequestMethod !has "GET"
| mvexpand list_RequestURL, list_DestinationIP
| extend RequestURL = tostring(list_RequestURL), DestinationIP = tostring(list_DestinationIP), ClientIP = tostring(list_SourceIP)
//Extend custom entitites for incidents
| extend timestamp = StartTimeUtc, IPCustomEntity = DestinationIP
| project-away list_RequestURL, list_DestinationIP, list_SourceIP, destinationURI, Domain, StartTimeUtc, EndTimeUtc, max_GetData, max_RequestContext
tactics:
- CommandAndControl
severity: Low
requiredDataConnectors:
- connectorId: Zscaler
dataTypes:
- CommonSecurityLog
triggerOperator: gt
query: |
let scriptExtensions = dynamic([".php", ".aspx", ".asp", ".cfml"]);
//The number of URI's seen to be suspicious, higher = less likely to be suspicious
let uriThreshold = 1;
CommonSecurityLog
// Only look at connections that were allowed through the web proxy
| where DeviceVendor =~ "Zscaler" and DeviceAction =~ "Allowed"
// Only look where some data was exchanged.
| where SentBytes > 0 and ReceivedBytes > 0
// Extract the Domain
| extend Domain = iff(countof(DestinationHostName,'.') >= 2, strcat(split(DestinationHostName,'.')[-2], '.',split(DestinationHostName,'.')[-1]), DestinationHostName)
| extend GetData=iff(RequestURL == "?", 1, 0)
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), makelist(RequestURL), makelist(DestinationIP), makelist(SourceIP), numOfConnections = count(), make_set(RequestMethod), max(GetData), max(RequestContext) by Domain
// Determine the number of URIs that have been visited for the domain
| extend destinationURI = arraylength(list_RequestURL)
| where destinationURI <= uriThreshold
| where tostring(list_RequestURL) has_any(scriptExtensions)
//Remove matches with referer
| where max_RequestContext == ""
//Keep requests where data was trasferred either in a GET with parameters or a POST
| where set_RequestMethod in~ ("POST") or max_GetData == 1
//Defeat email click tracking, may increase FN's while decreasing FP's
| where list_RequestURL !has "click" and set_RequestMethod !has "GET"
| mvexpand list_RequestURL, list_DestinationIP
| extend RequestURL = tostring(list_RequestURL), DestinationIP = tostring(list_DestinationIP), ClientIP = tostring(list_SourceIP)
//Extend custom entitites for incidents
| extend timestamp = StartTimeUtc, IPCustomEntity = DestinationIP
| project-away list_RequestURL, list_DestinationIP, list_SourceIP, destinationURI, Domain, StartTimeUtc, EndTimeUtc, max_GetData, max_RequestContext
triggerThreshold: 0
name: Request for single resource on domain
kind: Scheduled
version: 1.0.1
relevantTechniques:
- T1102
- T1071
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Zscaler Internet Access/Analytic Rules/Zscaler-LowVolumeDomainRequests.yaml
description: |
'This will look for connections to a domain where only a single file is requested, this is unusual as most modern web applications require additional recources. This type of activity is often assocaited with malware beaconing or tracking URL's delivered in emails. Developed for Zscaler but applicable to any outbound web logging.'
status: Available
queryFrequency: 1d
queryPeriod: 1d
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
id: 4d500e6d-c984-43a3-9f39-7edec8dcc04d
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workspace": {
"type": "String"
}
},
"resources": [
{
"id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/4d500e6d-c984-43a3-9f39-7edec8dcc04d')]",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/4d500e6d-c984-43a3-9f39-7edec8dcc04d')]",
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules",
"kind": "Scheduled",
"apiVersion": "2022-11-01",
"properties": {
"displayName": "Request for single resource on domain",
"description": "'This will look for connections to a domain where only a single file is requested, this is unusual as most modern web applications require additional recources. This type of activity is often assocaited with malware beaconing or tracking URL's delivered in emails. Developed for Zscaler but applicable to any outbound web logging.'\n",
"severity": "Low",
"enabled": true,
"query": "let scriptExtensions = dynamic([\".php\", \".aspx\", \".asp\", \".cfml\"]);\n//The number of URI's seen to be suspicious, higher = less likely to be suspicious\nlet uriThreshold = 1;\nCommonSecurityLog\n// Only look at connections that were allowed through the web proxy\n| where DeviceVendor =~ \"Zscaler\" and DeviceAction =~ \"Allowed\"\n// Only look where some data was exchanged.\n| where SentBytes > 0 and ReceivedBytes > 0\n// Extract the Domain\n| extend Domain = iff(countof(DestinationHostName,'.') >= 2, strcat(split(DestinationHostName,'.')[-2], '.',split(DestinationHostName,'.')[-1]), DestinationHostName)\n| extend GetData=iff(RequestURL == \"?\", 1, 0)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), makelist(RequestURL), makelist(DestinationIP), makelist(SourceIP), numOfConnections = count(), make_set(RequestMethod), max(GetData), max(RequestContext) by Domain\n// Determine the number of URIs that have been visited for the domain\n| extend destinationURI = arraylength(list_RequestURL)\n| where destinationURI <= uriThreshold\n| where tostring(list_RequestURL) has_any(scriptExtensions)\n//Remove matches with referer\n| where max_RequestContext == \"\"\n//Keep requests where data was trasferred either in a GET with parameters or a POST\n| where set_RequestMethod in~ (\"POST\") or max_GetData == 1\n//Defeat email click tracking, may increase FN's while decreasing FP's\n| where list_RequestURL !has \"click\" and set_RequestMethod !has \"GET\"\n| mvexpand list_RequestURL, list_DestinationIP\n| extend RequestURL = tostring(list_RequestURL), DestinationIP = tostring(list_DestinationIP), ClientIP = tostring(list_SourceIP)\n//Extend custom entitites for incidents\n| extend timestamp = StartTimeUtc, IPCustomEntity = DestinationIP\n| project-away list_RequestURL, list_DestinationIP, list_SourceIP, destinationURI, Domain, StartTimeUtc, EndTimeUtc, max_GetData, max_RequestContext\n",
"queryFrequency": "P1D",
"queryPeriod": "P1D",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0,
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"tactics": [
"CommandAndControl"
],
"techniques": [
"T1102",
"T1071"
],
"alertRuleTemplateName": "4d500e6d-c984-43a3-9f39-7edec8dcc04d",
"customDetails": null,
"entityMappings": [
{
"fieldMappings": [
{
"columnName": "IPCustomEntity",
"identifier": "Address"
}
],
"entityType": "IP"
}
],
"status": "Available",
"templateVersion": "1.0.1",
"OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Zscaler Internet Access/Analytic Rules/Zscaler-LowVolumeDomainRequests.yaml"
}
}
]
}