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

URL Added to Application from Unknown Domain

Back
Id017e095a-94d8-430c-a047-e51a11fb737b
RulenameURL Added to Application from Unknown Domain
DescriptionDetects a URL being added to an application where the domain is not one that is associated with the tenant.

The query uses domains seen in sign in logs to determine if the domain is associated with the tenant.

Applications associated with URLs not controlled by the organization can pose a security risk.

Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-applications#application-configuration-changes
SeverityHigh
TacticsPersistence
PrivilegeEscalation
TechniquesT1078.004
Required data connectorsAzureActiveDirectory
KindScheduled
Query frequency1d
Query period1d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Detections/AuditLogs/URLAddedtoApplicationfromUnknownDomain.yaml
Version1.0.2
Arm template017e095a-94d8-430c-a047-e51a11fb737b.json
Deploy To Azure
let domains =
  SigninLogs
  | where ResultType == 0
  | extend domain = split(UserPrincipalName, "@")[1]
  | extend domain = tostring(split(UserPrincipalName, "@")[1])
  | summarize by tolower(tostring(domain));
  AuditLogs
  | where Category =~ "ApplicationManagement"
  | where Result =~ "success"
  | where OperationName =~ 'Update Application'
  | mv-expand TargetResources
  | mv-expand TargetResources.modifiedProperties
  | where TargetResources_modifiedProperties.displayName =~ "AppAddress"
  | extend Key = tostring(TargetResources_modifiedProperties.displayName)
  | extend NewValue = TargetResources_modifiedProperties.newValue
  | extend OldValue = TargetResources_modifiedProperties.oldValue
  | where isnotempty(Key) and isnotempty(NewValue)
  | project-reorder Key, NewValue, OldValue
  | extend NewUrls = extract_all('"Address":([^,]*)', tostring(NewValue))
  | extend OldUrls = extract_all('"Address":([^,]*)', tostring(OldValue))
  | extend AddedUrls = set_difference(NewUrls, OldUrls)
  | where array_length(AddedUrls) > 0
  | extend UserAgent = iif(tostring(AdditionalDetails[0].key) == "User-Agent", tostring(AdditionalDetails[0].value), "")
  | extend AddingUser = iif(isnotempty(tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)) , tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName), "")
  | extend AddingApp = iif(isnotempty(tostring(parse_json(tostring(InitiatedBy.app)).servicePrincipalName)) , tostring(parse_json(tostring(InitiatedBy.app)).servicePrincipalName), "")
  | extend AddedBy = iif(isnotempty(AddingUser), AddingUser, AddingApp)
  | project-away AddingApp, AddingUser
  | extend AppDisplayName = tostring(TargetResources.displayName)
  | extend ipAddress = tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)
  | where isnotempty(AddedUrls)
  | mv-expand AddedUrls
  | extend AddedUrls = trim(@'"', tostring(AddedUrls))
  | extend Domain = extract("^(?:https?:\\/\\/)?(?:[^@\\/\\n]+@)?(?:www\\.)?([^:\\/?\\n]+)/", 1, replace_string(tolower(AddedUrls), '"', ""))
  | where isnotempty(Domain)
  | extend Domain = strcat(split(Domain, ".")[-2], ".", split(Domain, ".")[-1])
  | where Domain !in (domains)
  | project-reorder TimeGenerated, AppDisplayName, AddedUrls, AddedBy, UserAgent, ipAddress
severity: High
queryFrequency: 1d
relevantTechniques:
- T1078.004
tactics:
- Persistence
- PrivilegeEscalation
kind: Scheduled
query: |
  let domains =
    SigninLogs
    | where ResultType == 0
    | extend domain = split(UserPrincipalName, "@")[1]
    | extend domain = tostring(split(UserPrincipalName, "@")[1])
    | summarize by tolower(tostring(domain));
    AuditLogs
    | where Category =~ "ApplicationManagement"
    | where Result =~ "success"
    | where OperationName =~ 'Update Application'
    | mv-expand TargetResources
    | mv-expand TargetResources.modifiedProperties
    | where TargetResources_modifiedProperties.displayName =~ "AppAddress"
    | extend Key = tostring(TargetResources_modifiedProperties.displayName)
    | extend NewValue = TargetResources_modifiedProperties.newValue
    | extend OldValue = TargetResources_modifiedProperties.oldValue
    | where isnotempty(Key) and isnotempty(NewValue)
    | project-reorder Key, NewValue, OldValue
    | extend NewUrls = extract_all('"Address":([^,]*)', tostring(NewValue))
    | extend OldUrls = extract_all('"Address":([^,]*)', tostring(OldValue))
    | extend AddedUrls = set_difference(NewUrls, OldUrls)
    | where array_length(AddedUrls) > 0
    | extend UserAgent = iif(tostring(AdditionalDetails[0].key) == "User-Agent", tostring(AdditionalDetails[0].value), "")
    | extend AddingUser = iif(isnotempty(tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)) , tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName), "")
    | extend AddingApp = iif(isnotempty(tostring(parse_json(tostring(InitiatedBy.app)).servicePrincipalName)) , tostring(parse_json(tostring(InitiatedBy.app)).servicePrincipalName), "")
    | extend AddedBy = iif(isnotempty(AddingUser), AddingUser, AddingApp)
    | project-away AddingApp, AddingUser
    | extend AppDisplayName = tostring(TargetResources.displayName)
    | extend ipAddress = tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)
    | where isnotempty(AddedUrls)
    | mv-expand AddedUrls
    | extend AddedUrls = trim(@'"', tostring(AddedUrls))
    | extend Domain = extract("^(?:https?:\\/\\/)?(?:[^@\\/\\n]+@)?(?:www\\.)?([^:\\/?\\n]+)/", 1, replace_string(tolower(AddedUrls), '"', ""))
    | where isnotempty(Domain)
    | extend Domain = strcat(split(Domain, ".")[-2], ".", split(Domain, ".")[-1])
    | where Domain !in (domains)
    | project-reorder TimeGenerated, AppDisplayName, AddedUrls, AddedBy, UserAgent, ipAddress  
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/AuditLogs/URLAddedtoApplicationfromUnknownDomain.yaml
queryPeriod: 1d
version: 1.0.2
tags:
- AADSecOpsGuide
metadata:
  support:
    tier: Community
  source:
    kind: Community
  categories:
    domains:
    - Security - Others
  author:
    name: Pete Bryan
name: URL Added to Application from Unknown Domain
requiredDataConnectors:
- dataTypes:
  - AuditLogs
  connectorId: AzureActiveDirectory
triggerOperator: gt
entityMappings:
- entityType: URL
  fieldMappings:
  - identifier: Url
    columnName: AddedUrls
- entityType: Account
  fieldMappings:
  - identifier: FullName
    columnName: AddedBy
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: ipAddress
id: 017e095a-94d8-430c-a047-e51a11fb737b
description: |
  'Detects a URL being added to an application where the domain is not one that is associated with the tenant.
    The query uses domains seen in sign in logs to determine if the domain is associated with the tenant.
    Applications associated with URLs not controlled by the organization can pose a security risk.
    Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-applications#application-configuration-changes'  
triggerThreshold: 0
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/017e095a-94d8-430c-a047-e51a11fb737b')]",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/017e095a-94d8-430c-a047-e51a11fb737b')]",
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules",
      "kind": "Scheduled",
      "apiVersion": "2022-11-01-preview",
      "properties": {
        "displayName": "URL Added to Application from Unknown Domain",
        "description": "'Detects a URL being added to an application where the domain is not one that is associated with the tenant.\n  The query uses domains seen in sign in logs to determine if the domain is associated with the tenant.\n  Applications associated with URLs not controlled by the organization can pose a security risk.\n  Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-applications#application-configuration-changes'\n",
        "severity": "High",
        "enabled": true,
        "query": "let domains =\n  SigninLogs\n  | where ResultType == 0\n  | extend domain = split(UserPrincipalName, \"@\")[1]\n  | extend domain = tostring(split(UserPrincipalName, \"@\")[1])\n  | summarize by tolower(tostring(domain));\n  AuditLogs\n  | where Category =~ \"ApplicationManagement\"\n  | where Result =~ \"success\"\n  | where OperationName =~ 'Update Application'\n  | mv-expand TargetResources\n  | mv-expand TargetResources.modifiedProperties\n  | where TargetResources_modifiedProperties.displayName =~ \"AppAddress\"\n  | extend Key = tostring(TargetResources_modifiedProperties.displayName)\n  | extend NewValue = TargetResources_modifiedProperties.newValue\n  | extend OldValue = TargetResources_modifiedProperties.oldValue\n  | where isnotempty(Key) and isnotempty(NewValue)\n  | project-reorder Key, NewValue, OldValue\n  | extend NewUrls = extract_all('\"Address\":([^,]*)', tostring(NewValue))\n  | extend OldUrls = extract_all('\"Address\":([^,]*)', tostring(OldValue))\n  | extend AddedUrls = set_difference(NewUrls, OldUrls)\n  | where array_length(AddedUrls) > 0\n  | extend UserAgent = iif(tostring(AdditionalDetails[0].key) == \"User-Agent\", tostring(AdditionalDetails[0].value), \"\")\n  | extend AddingUser = iif(isnotempty(tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)) , tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName), \"\")\n  | extend AddingApp = iif(isnotempty(tostring(parse_json(tostring(InitiatedBy.app)).servicePrincipalName)) , tostring(parse_json(tostring(InitiatedBy.app)).servicePrincipalName), \"\")\n  | extend AddedBy = iif(isnotempty(AddingUser), AddingUser, AddingApp)\n  | project-away AddingApp, AddingUser\n  | extend AppDisplayName = tostring(TargetResources.displayName)\n  | extend ipAddress = tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)\n  | where isnotempty(AddedUrls)\n  | mv-expand AddedUrls\n  | extend AddedUrls = trim(@'\"', tostring(AddedUrls))\n  | extend Domain = extract(\"^(?:https?:\\\\/\\\\/)?(?:[^@\\\\/\\\\n]+@)?(?:www\\\\.)?([^:\\\\/?\\\\n]+)/\", 1, replace_string(tolower(AddedUrls), '\"', \"\"))\n  | where isnotempty(Domain)\n  | extend Domain = strcat(split(Domain, \".\")[-2], \".\", split(Domain, \".\")[-1])\n  | where Domain !in (domains)\n  | project-reorder TimeGenerated, AppDisplayName, AddedUrls, AddedBy, UserAgent, ipAddress\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P1D",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0,
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "Persistence",
          "PrivilegeEscalation"
        ],
        "techniques": [
          "T1078.004"
        ],
        "alertRuleTemplateName": "017e095a-94d8-430c-a047-e51a11fb737b",
        "customDetails": null,
        "entityMappings": [
          {
            "fieldMappings": [
              {
                "columnName": "AddedUrls",
                "identifier": "Url"
              }
            ],
            "entityType": "URL"
          },
          {
            "fieldMappings": [
              {
                "columnName": "AddedBy",
                "identifier": "FullName"
              }
            ],
            "entityType": "Account"
          },
          {
            "fieldMappings": [
              {
                "columnName": "ipAddress",
                "identifier": "Address"
              }
            ],
            "entityType": "IP"
          }
        ],
        "tags": [
          "AADSecOpsGuide"
        ],
        "templateVersion": "1.0.2",
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Detections/AuditLogs/URLAddedtoApplicationfromUnknownDomain.yaml"
      }
    }
  ]
}