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]
queryFrequency: 1d
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
version: 1.0.6
relevantTechniques:
- T1189
- T1071
- T1203
name: Malformed user agent
triggerThreshold: 0
kind: Scheduled
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]  
triggerOperator: gt
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/MultipleDataSources/MalformedUserAgents.yaml
requiredDataConnectors:
- connectorId: WAF
  dataTypes:
  - AzureDiagnostics
- connectorId: Office365
  dataTypes:
  - OfficeActivity
- connectorId: AzureActiveDirectory
  dataTypes:
  - SigninLogs
- connectorId: AzureActiveDirectory
  dataTypes:
  - AADNonInteractiveUserSignInLogs
- connectorId: AWS
  dataTypes:
  - AWSCloudTrail
- connectorId: AzureMonitor(IIS)
  dataTypes:
  - W3CIISLog
metadata:
  source:
    kind: Community
  author:
    name: Microsoft Security Research
  support:
    tier: Community
  categories:
    domains:
    - Security - Threat Protection
tactics:
- InitialAccess
- CommandAndControl
- Execution
id: a357535e-f722-4afe-b375-cff362b2b376
queryPeriod: 1d
entityMappings:
- fieldMappings:
  - columnName: Account
    identifier: FullName
  - columnName: AccountName
    identifier: Name
  - columnName: UPNSuffix
    identifier: UPNSuffix
  entityType: Account
- fieldMappings:
  - columnName: SourceIP
    identifier: Address
  entityType: IP
{
  "$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"
    }
  ]
}