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

Sign-ins from IPs that attempt sign-ins to disabled accounts

Back
Id500c103a-0319-4d56-8e99-3cec8d860757
RulenameSign-ins from IPs that attempt sign-ins to disabled accounts
DescriptionIdentifies IPs with failed attempts to sign in to one or more disabled accounts and where that same IP has had successful signins from other accounts.

This could indicate an attacker who obtained credentials for a list of accounts and is attempting to login with those accounts, some of which may have already been disabled.

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

50057 - User account is disabled. The account has been disabled by an administrator.
SeverityMedium
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/SigninAttemptsByIPviaDisabledAccounts.yaml
Version1.1.1
Arm template500c103a-0319-4d56-8e99-3cec8d860757.json
Deploy To Azure
let aadFunc = (tableName:string){
table(tableName)
| where ResultType == "50057"
| where ResultDescription == "User account is disabled. The account has been disabled by an administrator."
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), disabledAccountLoginAttempts = count(),
disabledAccountsTargeted = dcount(UserPrincipalName), applicationsTargeted = dcount(AppDisplayName), disabledAccountSet = make_set(UserPrincipalName),
applicationSet = make_set(AppDisplayName) by IPAddress, Type
| order by disabledAccountLoginAttempts desc
| join kind= leftouter (
    // Consider these IPs suspicious - and alert any related  successful sign-ins
    table(tableName)
    | where ResultType == 0
    | summarize successfulAccountSigninCount = dcount(UserPrincipalName), successfulAccountSigninSet = make_set(UserPrincipalName, 15) by IPAddress, Type
    // Assume IPs associated with sign-ins from 100+ distinct user accounts are safe
    | where successfulAccountSigninCount < 100
) on IPAddress
// IPs from which attempts to authenticate as disabled user accounts originated, and had a non-zero success rate for some other account
| where isnotempty(successfulAccountSigninCount)
| project StartTime, EndTime, IPAddress, disabledAccountLoginAttempts, disabledAccountsTargeted, disabledAccountSet, applicationSet,
successfulAccountSigninCount, successfulAccountSigninSet, Type
| order by disabledAccountLoginAttempts
| extend timestamp = StartTime, IPCustomEntity = IPAddress
};
let aadSignin = aadFunc("SigninLogs");
let aadNonInt = aadFunc("AADNonInteractiveUserSignInLogs");
union isfuzzy=true aadSignin, aadNonInt
queryPeriod: 1d
version: 1.1.1
relevantTechniques:
- T1078
- T1098
queryFrequency: 1d
kind: Scheduled
name: Sign-ins from IPs that attempt sign-ins to disabled accounts
id: 500c103a-0319-4d56-8e99-3cec8d860757
entityMappings:
- fieldMappings:
  - columnName: IPCustomEntity
    identifier: Address
  entityType: IP
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Active Directory/Analytic Rules/SigninAttemptsByIPviaDisabledAccounts.yaml
severity: Medium
query: |
  let aadFunc = (tableName:string){
  table(tableName)
  | where ResultType == "50057"
  | where ResultDescription == "User account is disabled. The account has been disabled by an administrator."
  | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), disabledAccountLoginAttempts = count(),
  disabledAccountsTargeted = dcount(UserPrincipalName), applicationsTargeted = dcount(AppDisplayName), disabledAccountSet = make_set(UserPrincipalName),
  applicationSet = make_set(AppDisplayName) by IPAddress, Type
  | order by disabledAccountLoginAttempts desc
  | join kind= leftouter (
      // Consider these IPs suspicious - and alert any related  successful sign-ins
      table(tableName)
      | where ResultType == 0
      | summarize successfulAccountSigninCount = dcount(UserPrincipalName), successfulAccountSigninSet = make_set(UserPrincipalName, 15) by IPAddress, Type
      // Assume IPs associated with sign-ins from 100+ distinct user accounts are safe
      | where successfulAccountSigninCount < 100
  ) on IPAddress
  // IPs from which attempts to authenticate as disabled user accounts originated, and had a non-zero success rate for some other account
  | where isnotempty(successfulAccountSigninCount)
  | project StartTime, EndTime, IPAddress, disabledAccountLoginAttempts, disabledAccountsTargeted, disabledAccountSet, applicationSet,
  successfulAccountSigninCount, successfulAccountSigninSet, Type
  | order by disabledAccountLoginAttempts
  | extend timestamp = StartTime, IPCustomEntity = IPAddress
  };
  let aadSignin = aadFunc("SigninLogs");
  let aadNonInt = aadFunc("AADNonInteractiveUserSignInLogs");
  union isfuzzy=true aadSignin, aadNonInt  
tactics:
- InitialAccess
- Persistence
description: |
  'Identifies IPs with failed attempts to sign in to one or more disabled accounts and where that same IP has had successful signins from other accounts.
  This could indicate an attacker who obtained credentials for a list of accounts and is attempting to login with those accounts, some of which may have already been disabled.
  References: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes
  50057 - User account is disabled. The account has been disabled by an administrator.'  
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/500c103a-0319-4d56-8e99-3cec8d860757')]",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/500c103a-0319-4d56-8e99-3cec8d860757')]",
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules",
      "kind": "Scheduled",
      "apiVersion": "2022-11-01",
      "properties": {
        "displayName": "Sign-ins from IPs that attempt sign-ins to disabled accounts",
        "description": "'Identifies IPs with failed attempts to sign in to one or more disabled accounts and where that same IP has had successful signins from other accounts.\nThis could indicate an attacker who obtained credentials for a list of accounts and is attempting to login with those accounts, some of which may have already been disabled.\nReferences: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes\n50057 - User account is disabled. The account has been disabled by an administrator.'\n",
        "severity": "Medium",
        "enabled": true,
        "query": "let aadFunc = (tableName:string){\ntable(tableName)\n| where ResultType == \"50057\"\n| where ResultDescription == \"User account is disabled. The account has been disabled by an administrator.\"\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), disabledAccountLoginAttempts = count(),\ndisabledAccountsTargeted = dcount(UserPrincipalName), applicationsTargeted = dcount(AppDisplayName), disabledAccountSet = make_set(UserPrincipalName),\napplicationSet = make_set(AppDisplayName) by IPAddress, Type\n| order by disabledAccountLoginAttempts desc\n| join kind= leftouter (\n    // Consider these IPs suspicious - and alert any related  successful sign-ins\n    table(tableName)\n    | where ResultType == 0\n    | summarize successfulAccountSigninCount = dcount(UserPrincipalName), successfulAccountSigninSet = make_set(UserPrincipalName, 15) by IPAddress, Type\n    // Assume IPs associated with sign-ins from 100+ distinct user accounts are safe\n    | where successfulAccountSigninCount < 100\n) on IPAddress\n// IPs from which attempts to authenticate as disabled user accounts originated, and had a non-zero success rate for some other account\n| where isnotempty(successfulAccountSigninCount)\n| project StartTime, EndTime, IPAddress, disabledAccountLoginAttempts, disabledAccountsTargeted, disabledAccountSet, applicationSet,\nsuccessfulAccountSigninCount, successfulAccountSigninSet, Type\n| order by disabledAccountLoginAttempts\n| extend timestamp = StartTime, IPCustomEntity = IPAddress\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": "500c103a-0319-4d56-8e99-3cec8d860757",
        "customDetails": null,
        "entityMappings": [
          {
            "fieldMappings": [
              {
                "identifier": "Address",
                "columnName": "IPCustomEntity"
              }
            ],
            "entityType": "IP"
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Active Directory/Analytic Rules/SigninAttemptsByIPviaDisabledAccounts.yaml",
        "status": "Available",
        "templateVersion": "1.1.1"
      }
    }
  ]
}