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

Malformed user agent

Back
Ida357535e-f722-4afe-b375-cff362b2b376
RulenameMalformed user agent
DescriptionMalware authors will sometimes hardcode user agent string values when writing the network communication component of their malware. Malformed user agents can be an indication of such malware.
SeverityMedium
TacticsInitialAccess
CommandAndControl
Execution
TechniquesT1189
T1071
T1203
Required data connectorsAWS
AzureActiveDirectory
AzureMonitor(IIS)
Office365
WAF
KindScheduled
Query frequency1d
Query period1d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Detections/MultipleDataSources/MalformedUserAgents.yaml
Version1.0.6
Arm templatea357535e-f722-4afe-b375-cff362b2b376.json
Deploy To Azure
(union isfuzzy=true
(OfficeActivity | where UserAgent != ""),
(OfficeActivity
| where RecordType in ("AzureActiveDirectory", "AzureActiveDirectoryStsLogon")
| extend OperationName = Operation
| parse ExtendedProperties with * 'User-Agent\\":\\"' UserAgent2 '\\' *
| parse ExtendedProperties with * 'UserAgent",      "Value": "' UserAgent1 '"' *
| where isnotempty(UserAgent1) or isnotempty(UserAgent2)
| extend UserAgent = iff( RecordType == 'AzureActiveDirectoryStsLogon', UserAgent1, UserAgent2)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = ClientIP, Account = UserId, Type, RecordType, Operation
),
(AzureDiagnostics
| where ResourceType =~ "APPLICATIONGATEWAYS"
| where OperationName =~ "ApplicationGatewayAccess"
| extend ClientIP = columnifexists("clientIP_s", "None"), UserAgent = columnifexists("userAgent_s", "None")
| where UserAgent != '-'
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = ClientIP,  requestUri_s, httpMethod_s, host_s, requestQuery_s, Type
),
(
W3CIISLog
| where isnotempty(csUserAgent)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent = csUserAgent, SourceIP = cIP, Account = csUserName, Type, sSiteName, csMethod, csUriStem
),
(
AWSCloudTrail
| where isnotempty(UserAgent)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = SourceIpAddress, Account = UserIdentityUserName, Type, EventSource, EventName
),
(SigninLogs
| where isnotempty(UserAgent)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = IPAddress, Account = UserPrincipalName, Type, OperationName, tostring(LocationDetails), tostring(DeviceDetail), AppDisplayName, ClientAppUsed
),
(AADNonInteractiveUserSignInLogs
| where isnotempty(UserAgent)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = IPAddress, Account = UserPrincipalName, Type, OperationName, tostring(LocationDetails), tostring(DeviceDetail), AppDisplayName, ClientAppUsed
)
)
// Likely artefact of hardcoding
| where UserAgent startswith "User" or UserAgent startswith '\"'
// Incorrect casing
or (UserAgent startswith "Mozilla" and not(UserAgent contains_cs "Mozilla"))
// Incorrect casing
or UserAgent contains_cs  "(Compatible;"
// Missing MSIE version
or UserAgent matches regex @"MSIE\s?;"
// Incorrect spacing around MSIE version
or UserAgent matches regex  @"MSIE(?:\d|.{1,5}?\d\s;)"
| extend AccountName = split(Account, "@")[0], UPNSuffix = split(Account, "@")[1]
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/MultipleDataSources/MalformedUserAgents.yaml
query: |
  (union isfuzzy=true
  (OfficeActivity | where UserAgent != ""),
  (OfficeActivity
  | where RecordType in ("AzureActiveDirectory", "AzureActiveDirectoryStsLogon")
  | extend OperationName = Operation
  | parse ExtendedProperties with * 'User-Agent\\":\\"' UserAgent2 '\\' *
  | parse ExtendedProperties with * 'UserAgent",      "Value": "' UserAgent1 '"' *
  | where isnotempty(UserAgent1) or isnotempty(UserAgent2)
  | extend UserAgent = iff( RecordType == 'AzureActiveDirectoryStsLogon', UserAgent1, UserAgent2)
  | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = ClientIP, Account = UserId, Type, RecordType, Operation
  ),
  (AzureDiagnostics
  | where ResourceType =~ "APPLICATIONGATEWAYS"
  | where OperationName =~ "ApplicationGatewayAccess"
  | extend ClientIP = columnifexists("clientIP_s", "None"), UserAgent = columnifexists("userAgent_s", "None")
  | where UserAgent != '-'
  | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = ClientIP,  requestUri_s, httpMethod_s, host_s, requestQuery_s, Type
  ),
  (
  W3CIISLog
  | where isnotempty(csUserAgent)
  | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent = csUserAgent, SourceIP = cIP, Account = csUserName, Type, sSiteName, csMethod, csUriStem
  ),
  (
  AWSCloudTrail
  | where isnotempty(UserAgent)
  | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = SourceIpAddress, Account = UserIdentityUserName, Type, EventSource, EventName
  ),
  (SigninLogs
  | where isnotempty(UserAgent)
  | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = IPAddress, Account = UserPrincipalName, Type, OperationName, tostring(LocationDetails), tostring(DeviceDetail), AppDisplayName, ClientAppUsed
  ),
  (AADNonInteractiveUserSignInLogs
  | where isnotempty(UserAgent)
  | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = IPAddress, Account = UserPrincipalName, Type, OperationName, tostring(LocationDetails), tostring(DeviceDetail), AppDisplayName, ClientAppUsed
  )
  )
  // Likely artefact of hardcoding
  | where UserAgent startswith "User" or UserAgent startswith '\"'
  // Incorrect casing
  or (UserAgent startswith "Mozilla" and not(UserAgent contains_cs "Mozilla"))
  // Incorrect casing
  or UserAgent contains_cs  "(Compatible;"
  // Missing MSIE version
  or UserAgent matches regex @"MSIE\s?;"
  // Incorrect spacing around MSIE version
  or UserAgent matches regex  @"MSIE(?:\d|.{1,5}?\d\s;)"
  | extend AccountName = split(Account, "@")[0], UPNSuffix = split(Account, "@")[1]  
description: |
    'Malware authors will sometimes hardcode user agent string values when writing the network communication component of their malware. Malformed user agents can be an indication of such malware.'
severity: Medium
requiredDataConnectors:
- dataTypes:
  - AzureDiagnostics
  connectorId: WAF
- dataTypes:
  - OfficeActivity
  connectorId: Office365
- dataTypes:
  - SigninLogs
  connectorId: AzureActiveDirectory
- dataTypes:
  - AADNonInteractiveUserSignInLogs
  connectorId: AzureActiveDirectory
- dataTypes:
  - AWSCloudTrail
  connectorId: AWS
- dataTypes:
  - W3CIISLog
  connectorId: AzureMonitor(IIS)
name: Malformed user agent
triggerThreshold: 0
metadata:
  source:
    kind: Community
  categories:
    domains:
    - Security - Threat Protection
  author:
    name: Microsoft Security Research
  support:
    tier: Community
tactics:
- InitialAccess
- CommandAndControl
- Execution
version: 1.0.6
relevantTechniques:
- T1189
- T1071
- T1203
triggerOperator: gt
entityMappings:
- entityType: Account
  fieldMappings:
  - columnName: Account
    identifier: FullName
  - columnName: AccountName
    identifier: Name
  - columnName: UPNSuffix
    identifier: UPNSuffix
- entityType: IP
  fieldMappings:
  - columnName: SourceIP
    identifier: Address
id: a357535e-f722-4afe-b375-cff362b2b376
kind: Scheduled
queryFrequency: 1d
queryPeriod: 1d
{
  "$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/a357535e-f722-4afe-b375-cff362b2b376')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/a357535e-f722-4afe-b375-cff362b2b376')]",
      "properties": {
        "alertRuleTemplateName": "a357535e-f722-4afe-b375-cff362b2b376",
        "customDetails": null,
        "description": "'Malware authors will sometimes hardcode user agent string values when writing the network communication component of their malware. Malformed user agents can be an indication of such malware.'\n",
        "displayName": "Malformed user agent",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "Account",
                "identifier": "FullName"
              },
              {
                "columnName": "AccountName",
                "identifier": "Name"
              },
              {
                "columnName": "UPNSuffix",
                "identifier": "UPNSuffix"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "SourceIP",
                "identifier": "Address"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Detections/MultipleDataSources/MalformedUserAgents.yaml",
        "query": "(union isfuzzy=true\n(OfficeActivity | where UserAgent != \"\"),\n(OfficeActivity\n| where RecordType in (\"AzureActiveDirectory\", \"AzureActiveDirectoryStsLogon\")\n| extend OperationName = Operation\n| parse ExtendedProperties with * 'User-Agent\\\\\":\\\\\"' UserAgent2 '\\\\' *\n| parse ExtendedProperties with * 'UserAgent\",      \"Value\": \"' UserAgent1 '\"' *\n| where isnotempty(UserAgent1) or isnotempty(UserAgent2)\n| extend UserAgent = iff( RecordType == 'AzureActiveDirectoryStsLogon', UserAgent1, UserAgent2)\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = ClientIP, Account = UserId, Type, RecordType, Operation\n),\n(AzureDiagnostics\n| where ResourceType =~ \"APPLICATIONGATEWAYS\"\n| where OperationName =~ \"ApplicationGatewayAccess\"\n| extend ClientIP = columnifexists(\"clientIP_s\", \"None\"), UserAgent = columnifexists(\"userAgent_s\", \"None\")\n| where UserAgent != '-'\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = ClientIP,  requestUri_s, httpMethod_s, host_s, requestQuery_s, Type\n),\n(\nW3CIISLog\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 isnotempty(UserAgent)\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = SourceIpAddress, Account = UserIdentityUserName, Type, EventSource, EventName\n),\n(SigninLogs\n| where isnotempty(UserAgent)\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = IPAddress, Account = UserPrincipalName, Type, OperationName, tostring(LocationDetails), tostring(DeviceDetail), AppDisplayName, ClientAppUsed\n),\n(AADNonInteractiveUserSignInLogs\n| where isnotempty(UserAgent)\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = IPAddress, Account = UserPrincipalName, Type, OperationName, tostring(LocationDetails), tostring(DeviceDetail), AppDisplayName, ClientAppUsed\n)\n)\n// Likely artefact of hardcoding\n| where UserAgent startswith \"User\" or UserAgent startswith '\\\"'\n// Incorrect casing\nor (UserAgent startswith \"Mozilla\" and not(UserAgent contains_cs \"Mozilla\"))\n// Incorrect casing\nor UserAgent contains_cs  \"(Compatible;\"\n// Missing MSIE version\nor UserAgent matches regex @\"MSIE\\s?;\"\n// Incorrect spacing around MSIE version\nor UserAgent matches regex  @\"MSIE(?:\\d|.{1,5}?\\d\\s;)\"\n| extend AccountName = split(Account, \"@\")[0], UPNSuffix = split(Account, \"@\")[1]\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P1D",
        "severity": "Medium",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CommandAndControl",
          "Execution",
          "InitialAccess"
        ],
        "techniques": [
          "T1071",
          "T1189",
          "T1203"
        ],
        "templateVersion": "1.0.6",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}