Detection rules › Kusto
New UserAgent observed in last 24 hours
'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.'
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Execution | |
| Command & Control |
Rule body
id: b725d62c-eb77-42ff-96f6-bdc6745fc6e0
name: New UserAgent observed in last 24 hours
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.'
severity: Low
status: Available
requiredDataConnectors:
- connectorId: AWS
dataTypes:
- AWSCloudTrail
- connectorId: Office365
dataTypes:
- OfficeActivity
- connectorId: AzureMonitor(IIS)
dataTypes:
- W3CIISLog
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- CommandAndControl
- Execution
relevantTechniques:
- T1189
- T1071
- T1203
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])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SourceIP
version: 1.0.5
kind: Scheduled
Stages and Predicates
Stage 0: let
let starttime = 14d;
let endtime = 1d;
let UserAgentAll = (union <inlined as stages below>;
Stage 1: union
union of 3 branches
Stage 2: source
OfficeActivity
Stage 3: where
| where TimeGenerated >= ago(starttime)
Stage 4: where
| where isnotempty(UserAgent)
Stage 5: summarize
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = ClientIP, Account = UserId, Type, RecordType, Operation
Stage 6: source
W3CIISLog
Stage 7: where
| where TimeGenerated >= ago(starttime)
Stage 8: where
| where isnotempty(csUserAgent)
Stage 9: summarize
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent = csUserAgent, SourceIP = cIP, Account = csUserName, Type, sSiteName, csMethod, csUriStem
Stage 10: source
AWSCloudTrail
Stage 11: where
| where TimeGenerated >= ago(starttime)
Stage 12: where
| where isnotempty(UserAgent)
Stage 13: summarize
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = SourceIpAddress, Account = UserIdentityUserName, Type, EventSource, EventName
Stage 14: extend (3 consecutive steps)
extend NormalizedUserAgent, Tokens, UserAgentNoHexAlphas
Stage 15: project-away
project-away Tokens, UserAgentNoHexAlphas
Stage 16: where
where StartTime >= ago(86400s)
Stage 17: summarize
summarize EndTime, StartTime by UserAgent, NormalizedUserAgent, SourceIP, Account, Type, RecordType, Operation, EventSource, EventName, sSiteName, csMethod, csUriStem
Stage 18: join (negated)
join kind=leftanti (UserAgentAll) on NormalizedUserAgent
Stage 19: extend
extend timestamp
Stage 20: extend
extend Name, UPNSuffix
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
UserAgent | is_not_null | field:"aws::userAgent" kind:is_not_null | |
csUserAgent | is_not_null | field:"csUserAgent" kind:is_not_null |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
UserAgent | is_not_null | excludes:UserAgent | |
csUserAgent | is_not_null | excludes:csUserAgent |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Account | summarize |
EndTime | summarize |
EventName | summarize |
EventSource | summarize |
NormalizedUserAgent | summarize |
Operation | summarize |
RecordType | summarize |
SourceIP | summarize |
StartTime | summarize |
Type | summarize |
UserAgent | summarize |
csMethod | summarize |
csUriStem | summarize |
sSiteName | summarize |
timestamp | extend |
Name | extend |
UPNSuffix | extend |