Adversaries may use a single client IP to request specific server files as part of initial compromise or command and control activities. SOC teams should proactively hunt for this behavior in Azure Sentinel to identify potential low-severity, yet indicative, signs of persistent or targeted attacks.
KQL Query
let clientThreshold = 1;
let scriptExtensions = dynamic([".php", ".aspx", ".asp", ".cfml"]);
let data = W3CIISLog
| where csUriStem has_any(scriptExtensions)
// find sucessfull connection
|where scStatus == 200
//Exclude local addresses, needs editing to match your network configuration using ipv4_is_private operator
|where ipv4_is_private(cIP) == false and cIP !startswith "fe80" and cIP !startswith "::" and cIP !startswith "127."
// excluded internal web page
|where ipv4_is_private(sIP) == false
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), makelist(cIP), dcount(TimeGenerated) by csUriStem, sSiteName, csUserAgent;
data
| mvexpand list_cIP
| distinct StartTime, EndTime, tostring(list_cIP), csUriStem, sSiteName, csUserAgent
| summarize StartTime = min(StartTime), EndTime = max(StartTime), dcount(list_cIP), makelist(list_cIP), makelist(sSiteName) by csUriStem, csUserAgent
| where dcount_list_cIP == clientThreshold
//Selects user agent strings that are probably browsers, comment out to see all
| where csUserAgent startswith "Mozilla"
| extend timestamp = StartTime, UserAgentCustomEntity = csUserAgent
id: a787a819-40df-4c9f-a5ae-850d5a2a0cf6
name: URI requests from single client
description: |
'This finds connections to server files requested by only one client. Effective when actor uses static operational IP addresses. Threshold can be modified. Larger execution window increases reliability of results.'
description_detailed: |
'This will look for connections to files on the server that are requested by only a single client.
This analytic will be effective where an actor is utilising relatively static operational IP addresses. The threshold can be modified.
The larger the execution window for this query the more reliable the results returned.'
severity: Low
requiredDataConnectors:
- connectorId: AzureMonitor(IIS)
dataTypes:
- W3CIISLog
tactics:
- InitialAccess
relevantTechniques:
- T1190
query: |
let clientThreshold = 1;
let scriptExtensions = dynamic([".php", ".aspx", ".asp", ".cfml"]);
let data = W3CIISLog
| where csUriStem has_any(scriptExtensions)
// find sucessfull connection
|where scStatus == 200
//Exclude local addresses, needs editing to match your network configuration using ipv4_is_private operator
|where ipv4_is_private(cIP) == false and cIP !startswith "fe80" and cIP !startswith "::" and cIP !startswith "127."
// excluded internal web page
|where ipv4_is_private(sIP) == false
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), makelist(cIP), dcount(TimeGenerated) by csUriStem, sSiteName, csUserAgent;
data
| mvexpand list_cIP
| distinct StartTime, EndTime, tostring(list_cIP), csUriStem, sSiteName, csUserAgent
| summarize StartTime = min(StartTime), EndTime = max(StartTime), dcount(list_cIP), makelist(list_cIP), makelist(sSiteName) by csUriStem, csUserAgent
| where dcount_list_cIP == clientThreshold
//Selects user agent strings that are probably browsers, comment out to see all
| where csUserAgent startswith "Mozilla"
| extend timestamp = StartTime, UserAgentCustomEntity = csUserAgent
entityMappings:
- entityType: CloudLogonSession
fieldMappings:
- identifier: UserAgent
columnName: csUserAgent
version: 1.0.2
metadata:
source:
kind: Community
author:
name: Thomas McElroy
support:
tier: Community
categories:
domains: [ "Security - Other" ]
| Sentinel Table | Notes |
|---|---|
W3CIISLog | Ensure this data connector is enabled |
Scenario: Scheduled system backups using rsync or tar
Filter/Exclusion: Exclude connections to known backup directories (e.g., /backup/, /var/backups/) or IP ranges used by internal backup servers.
Scenario: Admin task execution via cron or systemd timer
Filter/Exclusion: Exclude URIs that match internal admin tools (e.g., /usr/sbin/, /opt/admin/) or IP addresses associated with internal scheduling services.
Scenario: Log file aggregation using rsyslog or syslog-ng
Filter/Exclusion: Exclude connections to log servers (e.g., logs.example.com, 10.0.0.100) or URIs that match log file paths (e.g., /var/log/, /tmp/log/).
Scenario: Software update or patch deployment via yum, apt, or Chocolatey
Filter/Exclusion: Exclude connections to internal package repositories (e.g., repo.example.com, 10.1.0.50) or URIs that match known update paths (e.g., /repo/, /updates/).
Scenario: Internal monitoring tool data collection (e.g., Prometheus, Zabbix)
Filter/Exclusion: Exclude connections to monitoring servers (e.g., monitoring.example.com, 10.2.0.20) or URIs that match monitoring endpoints (e.g., /metrics/, /api/v1/).