Microsoft Sentinel Analytic Rules
cloudbrothers.infoAzure Sentinel RepoToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

Request for single resource on domain

Back
Id4d500e6d-c984-43a3-9f39-7edec8dcc04d
RulenameRequest for single resource on domain
DescriptionThis 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.
SeverityLow
TacticsCommandAndControl
TechniquesT1102
T1071
Required data connectorsCefAma
Zscaler
ZscalerAma
KindScheduled
Query frequency1d
Query period1d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Zscaler Internet Access/Analytic Rules/Zscaler-LowVolumeDomainRequests.yaml
Version1.0.4
Arm template4d500e6d-c984-43a3-9f39-7edec8dcc04d.json
Deploy To Azure
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
| project-away list_RequestURL, list_DestinationIP, list_SourceIP, destinationURI, Domain, StartTimeUtc, EndTimeUtc, max_GetData, max_RequestContext
relevantTechniques:
- T1102
- T1071
name: Request for single resource on domain
requiredDataConnectors:
- dataTypes:
  - CommonSecurityLog
  connectorId: Zscaler
- dataTypes:
  - CommonSecurityLog
  connectorId: ZscalerAma
- dataTypes:
  - CommonSecurityLog
  connectorId: CefAma
entityMappings:
- fieldMappings:
  - identifier: Address
    columnName: DestinationIP
  entityType: IP
triggerThreshold: 0
id: 4d500e6d-c984-43a3-9f39-7edec8dcc04d
tactics:
- CommandAndControl
version: 1.0.4
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Zscaler Internet Access/Analytic Rules/Zscaler-LowVolumeDomainRequests.yaml
queryPeriod: 1d
kind: Scheduled
queryFrequency: 1d
severity: Low
status: Available
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.'
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
  | project-away list_RequestURL, list_DestinationIP, list_SourceIP, destinationURI, Domain, StartTimeUtc, EndTimeUtc, max_GetData, max_RequestContext  
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/4d500e6d-c984-43a3-9f39-7edec8dcc04d')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/4d500e6d-c984-43a3-9f39-7edec8dcc04d')]",
      "properties": {
        "alertRuleTemplateName": "4d500e6d-c984-43a3-9f39-7edec8dcc04d",
        "customDetails": null,
        "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",
        "displayName": "Request for single resource on domain",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "DestinationIP",
                "identifier": "Address"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Zscaler Internet Access/Analytic Rules/Zscaler-LowVolumeDomainRequests.yaml",
        "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| project-away list_RequestURL, list_DestinationIP, list_SourceIP, destinationURI, Domain, StartTimeUtc, EndTimeUtc, max_GetData, max_RequestContext\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P1D",
        "severity": "Low",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CommandAndControl"
        ],
        "techniques": [
          "T1071",
          "T1102"
        ],
        "templateVersion": "1.0.4",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}