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

Attempt to bypass conditional access rule in Azure AD

Back
Id3af9285d-bb98-4a35-ad29-5ea39ba0c628
RulenameAttempt to bypass conditional access rule in Azure AD
DescriptionIdentifies an attempt to Bypass conditional access rule(s) in Azure Active Directory.

The ConditionalAccessStatus column value details if there was an attempt to bypass Conditional Access

or if the Conditional access rule was not satisfied (ConditionalAccessStatus == 1).

References:

https://docs.microsoft.com/azure/active-directory/conditional-access/overview

https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins

https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes

ConditionalAccessStatus == 0 // Success

ConditionalAccessStatus == 1 // Failure

ConditionalAccessStatus == 2 // Not Applied

ConditionalAccessStatus == 3 // unknown
SeverityLow
TacticsInitialAccess
Persistence
TechniquesT1078
T1098
Required data connectorsAzureActiveDirectory
KindScheduled
Query frequency1d
Query period1d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Active Directory/Analytic Rules/BypassCondAccessRule.yaml
Version1.0.3
Arm template3af9285d-bb98-4a35-ad29-5ea39ba0c628.json
Deploy To Azure
let threshold = 1;
let aadFunc = (tableName:string){
table(tableName)
| where ConditionalAccessStatus == 1 or ConditionalAccessStatus =~ "failure"
| extend CAP = parse_json(ConditionalAccessPolicies)
| mv-apply CAP on (
  project ConditionalAccessPoliciesName = CAP.displayName, result = CAP.result
  | where result =~ "failure"
)
| extend DeviceDetail = todynamic(DeviceDetail), Status = todynamic(Status), LocationDetails = todynamic(LocationDetails)
| extend OS = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser
| extend State = tostring(LocationDetails.state), City = tostring(LocationDetails.city), Region = tostring(LocationDetails.countryOrRegion)
| extend StatusCode = tostring(Status.errorCode), StatusDetails = tostring(Status.additionalDetails)
| extend Status = strcat(StatusCode, ": ", ResultDescription)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), Status = make_list(Status), StatusDetails = make_list(StatusDetails), IPAddresses = make_list(IPAddress), IPAddressCount = dcount(IPAddress), CorrelationIds = make_list(CorrelationId), ConditionalAccessPoliciesName = make_list(ConditionalAccessPoliciesName)
by UserPrincipalName, AppDisplayName, tostring(Browser), tostring(OS), City, State, Region, Type
| where IPAddressCount > threshold and StatusDetails !has "MFA successfully completed"
| mvexpand IPAddresses, Status, StatusDetails, CorrelationIds
| extend Status = strcat(Status, " ", StatusDetails)
| summarize IPAddresses = make_set(IPAddresses), Status = make_set(Status), CorrelationIds = make_set(CorrelationIds), ConditionalAccessPoliciesName = make_set(ConditionalAccessPoliciesName)
by StartTime, EndTime, UserPrincipalName, AppDisplayName, tostring(Browser), tostring(OS), City, State, Region, IPAddressCount, Type
| extend timestamp = StartTime, AccountCustomEntity = UserPrincipalName, IPCustomEntity = tostring(IPAddresses)
};
let aadSignin = aadFunc("SigninLogs");
let aadNonInt = aadFunc("AADNonInteractiveUserSignInLogs");
union isfuzzy=true aadSignin, aadNonInt
queryPeriod: 1d
version: 1.0.3
relevantTechniques:
- T1078
- T1098
queryFrequency: 1d
kind: Scheduled
name: Attempt to bypass conditional access rule in Azure AD
id: 3af9285d-bb98-4a35-ad29-5ea39ba0c628
entityMappings:
- fieldMappings:
  - columnName: AccountCustomEntity
    identifier: FullName
  entityType: Account
- fieldMappings:
  - columnName: IPCustomEntity
    identifier: Address
  entityType: IP
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Active Directory/Analytic Rules/BypassCondAccessRule.yaml
severity: Low
query: |
  let threshold = 1;
  let aadFunc = (tableName:string){
  table(tableName)
  | where ConditionalAccessStatus == 1 or ConditionalAccessStatus =~ "failure"
  | extend CAP = parse_json(ConditionalAccessPolicies)
  | mv-apply CAP on (
    project ConditionalAccessPoliciesName = CAP.displayName, result = CAP.result
    | where result =~ "failure"
  )
  | extend DeviceDetail = todynamic(DeviceDetail), Status = todynamic(Status), LocationDetails = todynamic(LocationDetails)
  | extend OS = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser
  | extend State = tostring(LocationDetails.state), City = tostring(LocationDetails.city), Region = tostring(LocationDetails.countryOrRegion)
  | extend StatusCode = tostring(Status.errorCode), StatusDetails = tostring(Status.additionalDetails)
  | extend Status = strcat(StatusCode, ": ", ResultDescription)
  | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), Status = make_list(Status), StatusDetails = make_list(StatusDetails), IPAddresses = make_list(IPAddress), IPAddressCount = dcount(IPAddress), CorrelationIds = make_list(CorrelationId), ConditionalAccessPoliciesName = make_list(ConditionalAccessPoliciesName)
  by UserPrincipalName, AppDisplayName, tostring(Browser), tostring(OS), City, State, Region, Type
  | where IPAddressCount > threshold and StatusDetails !has "MFA successfully completed"
  | mvexpand IPAddresses, Status, StatusDetails, CorrelationIds
  | extend Status = strcat(Status, " ", StatusDetails)
  | summarize IPAddresses = make_set(IPAddresses), Status = make_set(Status), CorrelationIds = make_set(CorrelationIds), ConditionalAccessPoliciesName = make_set(ConditionalAccessPoliciesName)
  by StartTime, EndTime, UserPrincipalName, AppDisplayName, tostring(Browser), tostring(OS), City, State, Region, IPAddressCount, Type
  | extend timestamp = StartTime, AccountCustomEntity = UserPrincipalName, IPCustomEntity = tostring(IPAddresses)
  };
  let aadSignin = aadFunc("SigninLogs");
  let aadNonInt = aadFunc("AADNonInteractiveUserSignInLogs");
  union isfuzzy=true aadSignin, aadNonInt  
tactics:
- InitialAccess
- Persistence
description: |
  'Identifies an attempt to Bypass conditional access rule(s) in Azure Active Directory.
  The ConditionalAccessStatus column value details if there was an attempt to bypass Conditional Access
  or if the Conditional access rule was not satisfied (ConditionalAccessStatus == 1).
  References:
  https://docs.microsoft.com/azure/active-directory/conditional-access/overview
  https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins
  https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes
  ConditionalAccessStatus == 0 // Success
  ConditionalAccessStatus == 1 // Failure
  ConditionalAccessStatus == 2 // Not Applied
  ConditionalAccessStatus == 3 // unknown'  
requiredDataConnectors:
- connectorId: AzureActiveDirectory
  dataTypes:
  - SigninLogs
- connectorId: AzureActiveDirectory
  dataTypes:
  - AADNonInteractiveUserSignInLogs
status: Available
triggerThreshold: 0
triggerOperator: gt
{
  "$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/3af9285d-bb98-4a35-ad29-5ea39ba0c628')]",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/3af9285d-bb98-4a35-ad29-5ea39ba0c628')]",
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules",
      "kind": "Scheduled",
      "apiVersion": "2022-11-01",
      "properties": {
        "displayName": "Attempt to bypass conditional access rule in Azure AD",
        "description": "'Identifies an attempt to Bypass conditional access rule(s) in Azure Active Directory.\nThe ConditionalAccessStatus column value details if there was an attempt to bypass Conditional Access\nor if the Conditional access rule was not satisfied (ConditionalAccessStatus == 1).\nReferences:\nhttps://docs.microsoft.com/azure/active-directory/conditional-access/overview\nhttps://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins\nhttps://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes\nConditionalAccessStatus == 0 // Success\nConditionalAccessStatus == 1 // Failure\nConditionalAccessStatus == 2 // Not Applied\nConditionalAccessStatus == 3 // unknown'\n",
        "severity": "Low",
        "enabled": true,
        "query": "let threshold = 1;\nlet aadFunc = (tableName:string){\ntable(tableName)\n| where ConditionalAccessStatus == 1 or ConditionalAccessStatus =~ \"failure\"\n| extend CAP = parse_json(ConditionalAccessPolicies)\n| mv-apply CAP on (\n  project ConditionalAccessPoliciesName = CAP.displayName, result = CAP.result\n  | where result =~ \"failure\"\n)\n| extend DeviceDetail = todynamic(DeviceDetail), Status = todynamic(Status), LocationDetails = todynamic(LocationDetails)\n| extend OS = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser\n| extend State = tostring(LocationDetails.state), City = tostring(LocationDetails.city), Region = tostring(LocationDetails.countryOrRegion)\n| extend StatusCode = tostring(Status.errorCode), StatusDetails = tostring(Status.additionalDetails)\n| extend Status = strcat(StatusCode, \": \", ResultDescription)\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), Status = make_list(Status), StatusDetails = make_list(StatusDetails), IPAddresses = make_list(IPAddress), IPAddressCount = dcount(IPAddress), CorrelationIds = make_list(CorrelationId), ConditionalAccessPoliciesName = make_list(ConditionalAccessPoliciesName)\nby UserPrincipalName, AppDisplayName, tostring(Browser), tostring(OS), City, State, Region, Type\n| where IPAddressCount > threshold and StatusDetails !has \"MFA successfully completed\"\n| mvexpand IPAddresses, Status, StatusDetails, CorrelationIds\n| extend Status = strcat(Status, \" \", StatusDetails)\n| summarize IPAddresses = make_set(IPAddresses), Status = make_set(Status), CorrelationIds = make_set(CorrelationIds), ConditionalAccessPoliciesName = make_set(ConditionalAccessPoliciesName)\nby StartTime, EndTime, UserPrincipalName, AppDisplayName, tostring(Browser), tostring(OS), City, State, Region, IPAddressCount, Type\n| extend timestamp = StartTime, AccountCustomEntity = UserPrincipalName, IPCustomEntity = tostring(IPAddresses)\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P1D",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0,
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "InitialAccess",
          "Persistence"
        ],
        "techniques": [
          "T1078",
          "T1098"
        ],
        "alertRuleTemplateName": "3af9285d-bb98-4a35-ad29-5ea39ba0c628",
        "customDetails": null,
        "entityMappings": [
          {
            "fieldMappings": [
              {
                "identifier": "FullName",
                "columnName": "AccountCustomEntity"
              }
            ],
            "entityType": "Account"
          },
          {
            "fieldMappings": [
              {
                "identifier": "Address",
                "columnName": "IPCustomEntity"
              }
            ],
            "entityType": "IP"
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Active Directory/Analytic Rules/BypassCondAccessRule.yaml",
        "status": "Available",
        "templateVersion": "1.0.3"
      }
    }
  ]
}