Back
Id41e843a8-92e7-444d-8d72-638f1145d1e1
RulenameNew Device/Location sign-in along with critical operation
DescriptionThis query identifies users seen login from a new geo location/country and a new device, then correlates that sign-in with successful risky operations such as policy changes, MFA changes, API token actions etc. This can be an indication of an attacker gaining access to a user’s credentials and then performing critical operations, which typically requires admin privileges. By detecting such patterns, organizations can quickly respond to potential security incidents and mitigate risks associated with unauthorized access and privilege escalation.
SeverityMedium
TacticsInitialAccess
Persistence
PrivilegeEscalation
TechniquesT1078
T1556
T1098
Required data connectorsOktaSSO
OktaSSOv2
KindScheduled
Query frequency1h
Query period1h
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Okta%20Single%20Sign-On/Analytic%20Rules/NewDeviceLocationCriticalOperation.yaml
Version1.1.3
Arm template41e843a8-92e7-444d-8d72-638f1145d1e1.json
Deploy To Azure
let timeframe = 1h;
let RiskyOperations = dynamic(["policy.rule.update","policy.rule.create","policy.rule.delete", "policy.rule.deactivate", "policy.lifecycle.update", "policy.rule.modify", "policy.lifecycle.create", "policy.lifecycle.delete", "policy.lifecycle.deactivate", "policy.lifecycle.modify", "network_zone.rule.disabled", "system.api_token.create", "system.api_token.revoke", "application.policy.sign_on.update", "application.policy.sign_on.rule.delete","user.mfa.factor.deactivate", "user.mfa.factor.reset_all", "system.mfa.factor.deactivate", "user.mfa.attempt_bypass"]);
let UserLoginNewCountryDevice = OktaSSO
| where eventType_s == "user.session.start"
| where outcome_result_s == "SUCCESS"
| extend debugContext_debugData_logOnlySecurityData_s = column_ifexists('debugContext_debugData_logOnlySecurityData_s', '{}')
| extend behaviors = parse_json(tostring(parse_json(debugContext_debugData_logOnlySecurityData_s).behaviors))
| where tostring(behaviors.["New Country"]) == "POSITIVE"
| where tostring(behaviors.["New Geo-Location"]) == "POSITIVE"
| where tostring(behaviors.["New Device"]) == "POSITIVE"
| summarize by timekey = bin(TimeGenerated, timeframe), actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_userAgent_browser_s, client_device_s, client_userAgent_rawUserAgent_s, client_ipAddress_s, authenticationContext_externalSessionId_s, client_geographicalContext_country_s, client_geographicalContext_city_s, displayMessage_s, outcome_result_s, outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', ""), column_ifexists('debugContext_debugData_threatSuspected_s', ""), client_geographicalContext_geolocation_lat_d, client_geographicalContext_geolocation_lon_d
| extend Location = strcat(client_geographicalContext_city_s, "-", client_geographicalContext_country_s);
let RiskyOperationsObserved = OktaSSO
| where eventType_s in (RiskyOperations)
| where outcome_result_s == "SUCCESS"
| summarize by timekey = bin(TimeGenerated, timeframe), actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_userAgent_browser_s, client_device_s, client_userAgent_rawUserAgent_s, client_ipAddress_s, authenticationContext_externalSessionId_s, client_geographicalContext_country_s, client_geographicalContext_city_s, displayMessage_s, outcome_result_s, outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', ""), column_ifexists('debugContext_debugData_threatSuspected_s', ""), client_geographicalContext_geolocation_lat_d, client_geographicalContext_geolocation_lon_d;
UserLoginNewCountryDevice
| join kind=inner (RiskyOperationsObserved) on timekey, actor_displayName_s, client_ipAddress_s
| project TimeGenerated = timekey, actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_userAgent_browser_s, client_device_s, client_userAgent_rawUserAgent_s, client_ipAddress_s, authenticationContext_externalSessionId_s, client_geographicalContext_country_s, client_geographicalContext_city_s, displayMessage_s, outcome_result_s, outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', ""), column_ifexists('debugContext_debugData_threatSuspected_s', ""), client_geographicalContext_geolocation_lat_d, client_geographicalContext_geolocation_lon_d, Location
| extend AccountName = tostring(split(actor_alternateId_s, "@")[0]), AccountUPNSuffix = tostring(split(actor_alternateId_s, "@")[1])
name: New Device/Location sign-in along with critical operation
triggerOperator: gt
query: |
  let timeframe = 1h;
  let RiskyOperations = dynamic(["policy.rule.update","policy.rule.create","policy.rule.delete", "policy.rule.deactivate", "policy.lifecycle.update", "policy.rule.modify", "policy.lifecycle.create", "policy.lifecycle.delete", "policy.lifecycle.deactivate", "policy.lifecycle.modify", "network_zone.rule.disabled", "system.api_token.create", "system.api_token.revoke", "application.policy.sign_on.update", "application.policy.sign_on.rule.delete","user.mfa.factor.deactivate", "user.mfa.factor.reset_all", "system.mfa.factor.deactivate", "user.mfa.attempt_bypass"]);
  let UserLoginNewCountryDevice = OktaSSO
  | where eventType_s == "user.session.start"
  | where outcome_result_s == "SUCCESS"
  | extend debugContext_debugData_logOnlySecurityData_s = column_ifexists('debugContext_debugData_logOnlySecurityData_s', '{}')
  | extend behaviors = parse_json(tostring(parse_json(debugContext_debugData_logOnlySecurityData_s).behaviors))
  | where tostring(behaviors.["New Country"]) == "POSITIVE"
  | where tostring(behaviors.["New Geo-Location"]) == "POSITIVE"
  | where tostring(behaviors.["New Device"]) == "POSITIVE"
  | summarize by timekey = bin(TimeGenerated, timeframe), actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_userAgent_browser_s, client_device_s, client_userAgent_rawUserAgent_s, client_ipAddress_s, authenticationContext_externalSessionId_s, client_geographicalContext_country_s, client_geographicalContext_city_s, displayMessage_s, outcome_result_s, outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', ""), column_ifexists('debugContext_debugData_threatSuspected_s', ""), client_geographicalContext_geolocation_lat_d, client_geographicalContext_geolocation_lon_d
  | extend Location = strcat(client_geographicalContext_city_s, "-", client_geographicalContext_country_s);
  let RiskyOperationsObserved = OktaSSO
  | where eventType_s in (RiskyOperations)
  | where outcome_result_s == "SUCCESS"
  | summarize by timekey = bin(TimeGenerated, timeframe), actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_userAgent_browser_s, client_device_s, client_userAgent_rawUserAgent_s, client_ipAddress_s, authenticationContext_externalSessionId_s, client_geographicalContext_country_s, client_geographicalContext_city_s, displayMessage_s, outcome_result_s, outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', ""), column_ifexists('debugContext_debugData_threatSuspected_s', ""), client_geographicalContext_geolocation_lat_d, client_geographicalContext_geolocation_lon_d;
  UserLoginNewCountryDevice
  | join kind=inner (RiskyOperationsObserved) on timekey, actor_displayName_s, client_ipAddress_s
  | project TimeGenerated = timekey, actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_userAgent_browser_s, client_device_s, client_userAgent_rawUserAgent_s, client_ipAddress_s, authenticationContext_externalSessionId_s, client_geographicalContext_country_s, client_geographicalContext_city_s, displayMessage_s, outcome_result_s, outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', ""), column_ifexists('debugContext_debugData_threatSuspected_s', ""), client_geographicalContext_geolocation_lat_d, client_geographicalContext_geolocation_lon_d, Location
  | extend AccountName = tostring(split(actor_alternateId_s, "@")[0]), AccountUPNSuffix = tostring(split(actor_alternateId_s, "@")[1])
queryFrequency: 1h
description: |
  This query identifies users seen login from a new geo location/country and a new device, then correlates that sign-in with successful risky operations such as policy changes, MFA changes, API token actions etc. This can be an indication of an attacker gaining access to a user's credentials and then performing critical operations, which typically requires admin privileges. By detecting such patterns, organizations can quickly respond to potential security incidents and mitigate risks associated with unauthorized access and privilege escalation.
id: 41e843a8-92e7-444d-8d72-638f1145d1e1
triggerThreshold: 0
queryPeriod: 1h
version: 1.1.3
kind: Scheduled
customDetails:
  ActorOS: client_userAgent_os_s
  ActorDisplayName: actor_displayName_s
  Location: Location
  ActorDevice: client_device_s
  UserAgent: client_userAgent_rawUserAgent_s
  ActorBrowser: client_userAgent_browser_s
  SessionId: authenticationContext_externalSessionId_s
status: Available
severity: Medium
requiredDataConnectors:
- connectorId: OktaSSO
  dataTypes:
  - Okta_CL
- connectorId: OktaSSOv2
  dataTypes:
  - OktaSSO
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Okta%20Single%20Sign-On/Analytic%20Rules/NewDeviceLocationCriticalOperation.yaml
alertDetailsOverride:
  alertDescriptionFormat: |
    This query identifies users seen login from new geo location/country {{Location}} as well as a new device and performing critical operations.
  alertDisplayNameFormat: New Device/Location {{Location}} sign-in along with critical operation
relevantTechniques:
- T1078
- T1556
- T1098
tactics:
- InitialAccess
- Persistence
- PrivilegeEscalation
entityMappings:
- fieldMappings:
  - identifier: Name
    columnName: AccountName
  - identifier: UPNSuffix
    columnName: AccountUPNSuffix
  entityType: Account
- fieldMappings:
  - identifier: Address
    columnName: client_ipAddress_s
  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/41e843a8-92e7-444d-8d72-638f1145d1e1')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/41e843a8-92e7-444d-8d72-638f1145d1e1')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "This query identifies users seen login from new geo location/country {{Location}} as well as a new device and performing critical operations.\n",
          "alertDisplayNameFormat": "New Device/Location {{Location}} sign-in along with critical operation"
        },
        "alertRuleTemplateName": "41e843a8-92e7-444d-8d72-638f1145d1e1",
        "customDetails": {
          "ActorBrowser": "client_userAgent_browser_s",
          "ActorDevice": "client_device_s",
          "ActorDisplayName": "actor_displayName_s",
          "ActorOS": "client_userAgent_os_s",
          "Location": "Location",
          "SessionId": "authenticationContext_externalSessionId_s",
          "UserAgent": "client_userAgent_rawUserAgent_s"
        },
        "description": "This query identifies users seen login from a new geo location/country and a new device, then correlates that sign-in with successful risky operations such as policy changes, MFA changes, API token actions etc. This can be an indication of an attacker gaining access to a user's credentials and then performing critical operations, which typically requires admin privileges. By detecting such patterns, organizations can quickly respond to potential security incidents and mitigate risks associated with unauthorized access and privilege escalation.\n",
        "displayName": "New Device/Location sign-in along with critical operation",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "AccountName",
                "identifier": "Name"
              },
              {
                "columnName": "AccountUPNSuffix",
                "identifier": "UPNSuffix"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "client_ipAddress_s",
                "identifier": "Address"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Okta%20Single%20Sign-On/Analytic%20Rules/NewDeviceLocationCriticalOperation.yaml",
        "query": "let timeframe = 1h;\nlet RiskyOperations = dynamic([\"policy.rule.update\",\"policy.rule.create\",\"policy.rule.delete\", \"policy.rule.deactivate\", \"policy.lifecycle.update\", \"policy.rule.modify\", \"policy.lifecycle.create\", \"policy.lifecycle.delete\", \"policy.lifecycle.deactivate\", \"policy.lifecycle.modify\", \"network_zone.rule.disabled\", \"system.api_token.create\", \"system.api_token.revoke\", \"application.policy.sign_on.update\", \"application.policy.sign_on.rule.delete\",\"user.mfa.factor.deactivate\", \"user.mfa.factor.reset_all\", \"system.mfa.factor.deactivate\", \"user.mfa.attempt_bypass\"]);\nlet UserLoginNewCountryDevice = OktaSSO\n| where eventType_s == \"user.session.start\"\n| where outcome_result_s == \"SUCCESS\"\n| extend debugContext_debugData_logOnlySecurityData_s = column_ifexists('debugContext_debugData_logOnlySecurityData_s', '{}')\n| extend behaviors = parse_json(tostring(parse_json(debugContext_debugData_logOnlySecurityData_s).behaviors))\n| where tostring(behaviors.[\"New Country\"]) == \"POSITIVE\"\n| where tostring(behaviors.[\"New Geo-Location\"]) == \"POSITIVE\"\n| where tostring(behaviors.[\"New Device\"]) == \"POSITIVE\"\n| summarize by timekey = bin(TimeGenerated, timeframe), actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_userAgent_browser_s, client_device_s, client_userAgent_rawUserAgent_s, client_ipAddress_s, authenticationContext_externalSessionId_s, client_geographicalContext_country_s, client_geographicalContext_city_s, displayMessage_s, outcome_result_s, outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', \"\"), column_ifexists('debugContext_debugData_threatSuspected_s', \"\"), client_geographicalContext_geolocation_lat_d, client_geographicalContext_geolocation_lon_d\n| extend Location = strcat(client_geographicalContext_city_s, \"-\", client_geographicalContext_country_s);\nlet RiskyOperationsObserved = OktaSSO\n| where eventType_s in (RiskyOperations)\n| where outcome_result_s == \"SUCCESS\"\n| summarize by timekey = bin(TimeGenerated, timeframe), actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_userAgent_browser_s, client_device_s, client_userAgent_rawUserAgent_s, client_ipAddress_s, authenticationContext_externalSessionId_s, client_geographicalContext_country_s, client_geographicalContext_city_s, displayMessage_s, outcome_result_s, outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', \"\"), column_ifexists('debugContext_debugData_threatSuspected_s', \"\"), client_geographicalContext_geolocation_lat_d, client_geographicalContext_geolocation_lon_d;\nUserLoginNewCountryDevice\n| join kind=inner (RiskyOperationsObserved) on timekey, actor_displayName_s, client_ipAddress_s\n| project TimeGenerated = timekey, actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_userAgent_browser_s, client_device_s, client_userAgent_rawUserAgent_s, client_ipAddress_s, authenticationContext_externalSessionId_s, client_geographicalContext_country_s, client_geographicalContext_city_s, displayMessage_s, outcome_result_s, outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', \"\"), column_ifexists('debugContext_debugData_threatSuspected_s', \"\"), client_geographicalContext_geolocation_lat_d, client_geographicalContext_geolocation_lon_d, Location\n| extend AccountName = tostring(split(actor_alternateId_s, \"@\")[0]), AccountUPNSuffix = tostring(split(actor_alternateId_s, \"@\")[1])\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "PT1H",
        "severity": "Medium",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "InitialAccess",
          "Persistence",
          "PrivilegeEscalation"
        ],
        "techniques": [
          "T1078",
          "T1098",
          "T1556"
        ],
        "templateVersion": "1.1.3",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}