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

New UserAgent observed in last 24 hours

Back
Idb725d62c-eb77-42ff-96f6-bdc6745fc6e0
RulenameNew UserAgent observed in last 24 hours
DescriptionIdentifies new UserAgents observed in the last 24 hours versus the previous 14 days. This detection

extracts words from user agents to build the baseline and determine rareity rather than perform a

direct comparison. This avoids FPs caused by version numbers and other high entropy user agent components.

These new UserAgents could be benign. However, in normally stable environments,

these new UserAgents could provide a starting point for investigating malicious activity.

Note: W3CIISLog can be noisy depending on the environment, however OfficeActivity and AWSCloudTrail are

usually stable with low numbers of detections.
SeverityLow
TacticsInitialAccess
CommandAndControl
Execution
TechniquesT1189
T1071
T1203
Required data connectorsAWS
AzureMonitor(IIS)
Office365
KindScheduled
Query frequency1d
Query period14d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Network Threat Protection Essentials/Analytic Rules/NewUserAgentLast24h.yaml
Version1.0.4
Arm templateb725d62c-eb77-42ff-96f6-bdc6745fc6e0.json
Deploy To Azure
let starttime = 14d;
let endtime = 1d;
let UserAgentAll =
(union isfuzzy=true
(OfficeActivity
| where TimeGenerated >= ago(starttime)
| where isnotempty(UserAgent)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = ClientIP, Account = UserId, Type, RecordType, Operation
),
(
W3CIISLog
| where TimeGenerated >= ago(starttime)
| where isnotempty(csUserAgent)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent = csUserAgent, SourceIP = cIP, Account = csUserName, Type, sSiteName, csMethod, csUriStem
),
(
AWSCloudTrail
| where TimeGenerated >= ago(starttime)
| where isnotempty(UserAgent)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = SourceIpAddress, Account = UserIdentityUserName, Type, EventSource, EventName
))
// remove wordSize blocks of non-numeric hex characters prior to word extraction
| extend UserAgentNoHexAlphas = replace("([A-Fa-f]{4,})", "x", UserAgent)
// once blocks of hex chars are removed, extract wordSize blocks of a-z
| extend Tokens = extract_all("([A-Za-z]{4,})", UserAgentNoHexAlphas)
// concatenate extracted words to create a summarized user agent for baseline and comparison
| extend NormalizedUserAgent = strcat_array(Tokens, "|")
| project-away UserAgentNoHexAlphas, Tokens;
UserAgentAll
| where StartTime >= ago(endtime)
| summarize StartTime = min(StartTime), EndTime = max(EndTime), count() by UserAgent, NormalizedUserAgent, SourceIP, Account, Type, RecordType, Operation, EventSource, EventName, sSiteName, csMethod, csUriStem
| join kind=leftanti
(
UserAgentAll
| where StartTime < ago(endtime)
| summarize by NormalizedUserAgent, SourceIP, Account, Type, RecordType, Operation, EventSource, EventName, sSiteName, csMethod, csUriStem
)
on NormalizedUserAgent
| extend timestamp = StartTime
| extend Name = tostring(split(Account, '@', 0)[0]), UPNSuffix = tostring(split(Account, '@', 1)[0])
kind: Scheduled
status: Available
triggerThreshold: 0
relevantTechniques:
- T1189
- T1071
- T1203
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Network Threat Protection Essentials/Analytic Rules/NewUserAgentLast24h.yaml
requiredDataConnectors:
- dataTypes:
  - AWSCloudTrail
  connectorId: AWS
- dataTypes:
  - OfficeActivity
  connectorId: Office365
- dataTypes:
  - W3CIISLog
  connectorId: AzureMonitor(IIS)
queryPeriod: 14d
tactics:
- InitialAccess
- CommandAndControl
- Execution
severity: Low
triggerOperator: gt
description: |
  'Identifies new UserAgents observed in the last 24 hours versus the previous 14 days. This detection
  extracts words from user agents to build the baseline and determine rareity rather than perform a
  direct comparison. This avoids FPs caused by version numbers and other high entropy user agent components.
  These new UserAgents could be benign. However, in normally stable environments,
  these new UserAgents could provide a starting point for investigating malicious activity.
  Note: W3CIISLog can be noisy depending on the environment, however OfficeActivity and AWSCloudTrail are
  usually stable with low numbers of detections.'  
query: |
  let starttime = 14d;
  let endtime = 1d;
  let UserAgentAll =
  (union isfuzzy=true
  (OfficeActivity
  | where TimeGenerated >= ago(starttime)
  | where isnotempty(UserAgent)
  | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = ClientIP, Account = UserId, Type, RecordType, Operation
  ),
  (
  W3CIISLog
  | where TimeGenerated >= ago(starttime)
  | where isnotempty(csUserAgent)
  | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent = csUserAgent, SourceIP = cIP, Account = csUserName, Type, sSiteName, csMethod, csUriStem
  ),
  (
  AWSCloudTrail
  | where TimeGenerated >= ago(starttime)
  | where isnotempty(UserAgent)
  | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = SourceIpAddress, Account = UserIdentityUserName, Type, EventSource, EventName
  ))
  // remove wordSize blocks of non-numeric hex characters prior to word extraction
  | extend UserAgentNoHexAlphas = replace("([A-Fa-f]{4,})", "x", UserAgent)
  // once blocks of hex chars are removed, extract wordSize blocks of a-z
  | extend Tokens = extract_all("([A-Za-z]{4,})", UserAgentNoHexAlphas)
  // concatenate extracted words to create a summarized user agent for baseline and comparison
  | extend NormalizedUserAgent = strcat_array(Tokens, "|")
  | project-away UserAgentNoHexAlphas, Tokens;
  UserAgentAll
  | where StartTime >= ago(endtime)
  | summarize StartTime = min(StartTime), EndTime = max(EndTime), count() by UserAgent, NormalizedUserAgent, SourceIP, Account, Type, RecordType, Operation, EventSource, EventName, sSiteName, csMethod, csUriStem
  | join kind=leftanti
  (
  UserAgentAll
  | where StartTime < ago(endtime)
  | summarize by NormalizedUserAgent, SourceIP, Account, Type, RecordType, Operation, EventSource, EventName, sSiteName, csMethod, csUriStem
  )
  on NormalizedUserAgent
  | extend timestamp = StartTime
  | extend Name = tostring(split(Account, '@', 0)[0]), UPNSuffix = tostring(split(Account, '@', 1)[0])  
name: New UserAgent observed in last 24 hours
version: 1.0.4
id: b725d62c-eb77-42ff-96f6-bdc6745fc6e0
queryFrequency: 1d
entityMappings:
- entityType: Account
  fieldMappings:
  - columnName: Name
    identifier: Name
  - columnName: UPNSuffix
    identifier: UPNSuffix
- entityType: IP
  fieldMappings:
  - columnName: SourceIP
    identifier: Address
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2023-02-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/b725d62c-eb77-42ff-96f6-bdc6745fc6e0')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/b725d62c-eb77-42ff-96f6-bdc6745fc6e0')]",
      "properties": {
        "alertRuleTemplateName": "b725d62c-eb77-42ff-96f6-bdc6745fc6e0",
        "customDetails": null,
        "description": "'Identifies new UserAgents observed in the last 24 hours versus the previous 14 days. This detection\nextracts words from user agents to build the baseline and determine rareity rather than perform a\ndirect comparison. This avoids FPs caused by version numbers and other high entropy user agent components.\nThese new UserAgents could be benign. However, in normally stable environments,\nthese new UserAgents could provide a starting point for investigating malicious activity.\nNote: W3CIISLog can be noisy depending on the environment, however OfficeActivity and AWSCloudTrail are\nusually stable with low numbers of detections.'\n",
        "displayName": "New UserAgent observed in last 24 hours",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "Name",
                "identifier": "Name"
              },
              {
                "columnName": "UPNSuffix",
                "identifier": "UPNSuffix"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "SourceIP",
                "identifier": "Address"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Network Threat Protection Essentials/Analytic Rules/NewUserAgentLast24h.yaml",
        "query": "let starttime = 14d;\nlet endtime = 1d;\nlet UserAgentAll =\n(union isfuzzy=true\n(OfficeActivity\n| where TimeGenerated >= ago(starttime)\n| where isnotempty(UserAgent)\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = ClientIP, Account = UserId, Type, RecordType, Operation\n),\n(\nW3CIISLog\n| where TimeGenerated >= ago(starttime)\n| where isnotempty(csUserAgent)\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent = csUserAgent, SourceIP = cIP, Account = csUserName, Type, sSiteName, csMethod, csUriStem\n),\n(\nAWSCloudTrail\n| where TimeGenerated >= ago(starttime)\n| where isnotempty(UserAgent)\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = SourceIpAddress, Account = UserIdentityUserName, Type, EventSource, EventName\n))\n// remove wordSize blocks of non-numeric hex characters prior to word extraction\n| extend UserAgentNoHexAlphas = replace(\"([A-Fa-f]{4,})\", \"x\", UserAgent)\n// once blocks of hex chars are removed, extract wordSize blocks of a-z\n| extend Tokens = extract_all(\"([A-Za-z]{4,})\", UserAgentNoHexAlphas)\n// concatenate extracted words to create a summarized user agent for baseline and comparison\n| extend NormalizedUserAgent = strcat_array(Tokens, \"|\")\n| project-away UserAgentNoHexAlphas, Tokens;\nUserAgentAll\n| where StartTime >= ago(endtime)\n| summarize StartTime = min(StartTime), EndTime = max(EndTime), count() by UserAgent, NormalizedUserAgent, SourceIP, Account, Type, RecordType, Operation, EventSource, EventName, sSiteName, csMethod, csUriStem\n| join kind=leftanti\n(\nUserAgentAll\n| where StartTime < ago(endtime)\n| summarize by NormalizedUserAgent, SourceIP, Account, Type, RecordType, Operation, EventSource, EventName, sSiteName, csMethod, csUriStem\n)\non NormalizedUserAgent\n| extend timestamp = StartTime\n| extend Name = tostring(split(Account, '@', 0)[0]), UPNSuffix = tostring(split(Account, '@', 1)[0])\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P14D",
        "severity": "Low",
        "status": "Available",
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CommandAndControl",
          "Execution",
          "InitialAccess"
        ],
        "techniques": [
          "T1071",
          "T1189",
          "T1203"
        ],
        "templateVersion": "1.0.4",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}