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

Expired access credentials being used in Azure

Back
Id433c3b0a-7278-4d74-b137-963ac6f9a7e7
RulenameExpired access credentials being used in Azure
DescriptionThis query searches for logins with an expired access credential (for example an expired cookie). It then matches the IP address from which the expired credential access occurred with the IP addresses of successful logins.

If there are logins with expired credentials, but no successful logins from an IP, this might indicate an attacker has copied the authentication cookie and is re-using it on another machine.
SeverityMedium
TacticsCredentialAccess
TechniquesT1528
Required data connectorsAzureActiveDirectory
KindScheduled
Query frequency1d
Query period7d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/FalconFriday/Analytic Rules/ExpiredAccessCredentials.yaml
Version1.0.0
Arm template433c3b0a-7278-4d74-b137-963ac6f9a7e7.json
Deploy To Azure
// Timeframe to search for failed logins.
let timeframe=1d;
// Timeframe to look back for successful logins from the same user by IP.
let lookback=7d;
let SuspiciousSignings=(
    SigninLogs
    | where TimeGenerated >= ago(timeframe)
    | where ResourceDisplayName contains "Windows Azure Active Directory"
    // 50132 = SsoArtifactInvalidOrExpired - The session is not valid due to password expiration or recent password change.
    // 50173 = FreshTokenNeeded - The provided grant has expired due to it being revoked, and a fresh auth token is needed. 
    // 70008 = ExpiredOrRevokedGrant - The refresh token has expired due to inactivity. The token was issued on XXX and was inactive for a certain period of time.
    // 81010 = DesktopSsoAuthTokenInvalid - Seamless SSO failed because the user's Kerberos ticket has expired or is invalid.
    | where ResultType in (50173, 50132, 70008, 81010)
    | summarize FailedCountPerDay=count(),FailedUserAgents=make_set(UserAgent), FailedCountries=make_set(LocationDetails.countryOrRegion),FailedIps=make_set(IPAddress) by UserPrincipalName, Day=bin(TimeGenerated, 1d)
    | where FailedCountPerDay >= 1
);
let SuccessLogins=(
    SigninLogs
    | where TimeGenerated >= ago(lookback)
    | where UserPrincipalName in ((SuspiciousSignings | project UserPrincipalName))
    | where ResultType == 0
    | summarize count() by UserPrincipalName, IPAddress
);
SuspiciousSignings
| mv-expand FailedIp=FailedIps
| extend FailedIp=tostring(FailedIp)
| join kind=leftanti SuccessLogins on $left.FailedIp==$right.IPAddress, UserPrincipalName
status: Available
id: 433c3b0a-7278-4d74-b137-963ac6f9a7e7
name: Expired access credentials being used in Azure
requiredDataConnectors:
- connectorId: AzureActiveDirectory
  dataTypes:
  - SigninLogs
severity: Medium
triggerThreshold: 0
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/FalconFriday/Analytic Rules/ExpiredAccessCredentials.yaml
kind: Scheduled
description: |
  This query searches for logins with an expired access credential (for example an expired cookie). It then matches the IP address from which the expired credential access occurred with the IP addresses of successful logins.
  If there are logins with expired credentials, but no successful logins from an IP, this might indicate an attacker has copied the authentication cookie and is re-using it on another machine.  
relevantTechniques:
- T1528
queryPeriod: 7d
triggerOperator: gt
queryFrequency: 1d
query: |
  // Timeframe to search for failed logins.
  let timeframe=1d;
  // Timeframe to look back for successful logins from the same user by IP.
  let lookback=7d;
  let SuspiciousSignings=(
      SigninLogs
      | where TimeGenerated >= ago(timeframe)
      | where ResourceDisplayName contains "Windows Azure Active Directory"
      // 50132 = SsoArtifactInvalidOrExpired - The session is not valid due to password expiration or recent password change.
      // 50173 = FreshTokenNeeded - The provided grant has expired due to it being revoked, and a fresh auth token is needed. 
      // 70008 = ExpiredOrRevokedGrant - The refresh token has expired due to inactivity. The token was issued on XXX and was inactive for a certain period of time.
      // 81010 = DesktopSsoAuthTokenInvalid - Seamless SSO failed because the user's Kerberos ticket has expired or is invalid.
      | where ResultType in (50173, 50132, 70008, 81010)
      | summarize FailedCountPerDay=count(),FailedUserAgents=make_set(UserAgent), FailedCountries=make_set(LocationDetails.countryOrRegion),FailedIps=make_set(IPAddress) by UserPrincipalName, Day=bin(TimeGenerated, 1d)
      | where FailedCountPerDay >= 1
  );
  let SuccessLogins=(
      SigninLogs
      | where TimeGenerated >= ago(lookback)
      | where UserPrincipalName in ((SuspiciousSignings | project UserPrincipalName))
      | where ResultType == 0
      | summarize count() by UserPrincipalName, IPAddress
  );
  SuspiciousSignings
  | mv-expand FailedIp=FailedIps
  | extend FailedIp=tostring(FailedIp)
  | join kind=leftanti SuccessLogins on $left.FailedIp==$right.IPAddress, UserPrincipalName  
version: 1.0.0
tactics:
- CredentialAccess
entityMappings:
- fieldMappings:
  - identifier: FullName
    columnName: UserPrincipalName
  entityType: Account
- fieldMappings:
  - identifier: Address
    columnName: FailedIp
  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": "2023-02-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/433c3b0a-7278-4d74-b137-963ac6f9a7e7')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/433c3b0a-7278-4d74-b137-963ac6f9a7e7')]",
      "properties": {
        "alertRuleTemplateName": "433c3b0a-7278-4d74-b137-963ac6f9a7e7",
        "customDetails": null,
        "description": "This query searches for logins with an expired access credential (for example an expired cookie). It then matches the IP address from which the expired credential access occurred with the IP addresses of successful logins.\nIf there are logins with expired credentials, but no successful logins from an IP, this might indicate an attacker has copied the authentication cookie and is re-using it on another machine.\n",
        "displayName": "Expired access credentials being used in Azure",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "UserPrincipalName",
                "identifier": "FullName"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "FailedIp",
                "identifier": "Address"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/FalconFriday/Analytic Rules/ExpiredAccessCredentials.yaml",
        "query": "// Timeframe to search for failed logins.\nlet timeframe=1d;\n// Timeframe to look back for successful logins from the same user by IP.\nlet lookback=7d;\nlet SuspiciousSignings=(\n    SigninLogs\n    | where TimeGenerated >= ago(timeframe)\n    | where ResourceDisplayName contains \"Windows Azure Active Directory\"\n    // 50132 = SsoArtifactInvalidOrExpired - The session is not valid due to password expiration or recent password change.\n    // 50173 = FreshTokenNeeded - The provided grant has expired due to it being revoked, and a fresh auth token is needed. \n    // 70008 = ExpiredOrRevokedGrant - The refresh token has expired due to inactivity. The token was issued on XXX and was inactive for a certain period of time.\n    // 81010 = DesktopSsoAuthTokenInvalid - Seamless SSO failed because the user's Kerberos ticket has expired or is invalid.\n    | where ResultType in (50173, 50132, 70008, 81010)\n    | summarize FailedCountPerDay=count(),FailedUserAgents=make_set(UserAgent), FailedCountries=make_set(LocationDetails.countryOrRegion),FailedIps=make_set(IPAddress) by UserPrincipalName, Day=bin(TimeGenerated, 1d)\n    | where FailedCountPerDay >= 1\n);\nlet SuccessLogins=(\n    SigninLogs\n    | where TimeGenerated >= ago(lookback)\n    | where UserPrincipalName in ((SuspiciousSignings | project UserPrincipalName))\n    | where ResultType == 0\n    | summarize count() by UserPrincipalName, IPAddress\n);\nSuspiciousSignings\n| mv-expand FailedIp=FailedIps\n| extend FailedIp=tostring(FailedIp)\n| join kind=leftanti SuccessLogins on $left.FailedIp==$right.IPAddress, UserPrincipalName\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P7D",
        "severity": "Medium",
        "status": "Available",
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CredentialAccess"
        ],
        "techniques": [
          "T1528"
        ],
        "templateVersion": "1.0.0",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}