Multiple Password Reset by user
Id | 0b9ae89d-8cad-461c-808f-0494f70ad5c4 |
Rulename | Multiple Password Reset by user |
Description | This query will determine multiple password resets by user across multiple data sources. Account manipulation including password reset may aid adversaries in maintaining access to credentials and certain permission levels within an environment. |
Severity | Low |
Tactics | InitialAccess CredentialAccess |
Techniques | T1078 T1110 |
Required data connectors | AzureActiveDirectory Office365 SecurityEvents Syslog WindowsForwardedEvents WindowsSecurityEvents |
Kind | Scheduled |
Query frequency | 1d |
Query period | 1d |
Trigger threshold | 0 |
Trigger operator | gt |
Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Detections/MultipleDataSources/MultiplePasswordresetsbyUser.yaml |
Version | 2.1.7 |
Arm template | 0b9ae89d-8cad-461c-808f-0494f70ad5c4.json |
let selfServicePasswordReset = dynamic(["Self-service password reset flow activity progress", "Change password (self-service)", "Reset password (self-service)"]);
//Self-service password reset flow activity progress is typically caused by a password policy which requires users to rotate passwords. This operation already implies the user has signed in successfully and therefore the password reset is non-malicious.
let PerUserThreshold = 5;
let TotalThreshold = 100;
let action = dynamic(["change", "changed", "reset"]);
let pWord = dynamic(["password", "credentials"]);
let PasswordResetMultiDataSource =
(union isfuzzy=true
(//Password reset events
//4723: An attempt was made to change an account's password
//4724: An attempt was made to reset an accounts password
SecurityEvent
| where EventID in ("4723","4724")
| project TimeGenerated, Computer, AccountType, Account, Type, TargetUserName),
(//Password reset events
//4723: An attempt was made to change an account's password
//4724: An attempt was made to reset an accounts password
WindowsEvent
| where EventID in ("4723","4724")
| extend SubjectUserSid = tostring(EventData.SubjectUserSid)
| extend TargetUserName = tostring(EventData.TargetUserName)
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend AccountType=case(Account endswith "$" or SubjectUserSid in ("S-1-5-18", "S-1-5-19", "S-1-5-20"), "Machine", isempty(SubjectUserSid), "", "User")
| project TimeGenerated, Computer, AccountType, Account, Type, TargetUserName),
(//Azure Active Directory Password reset events
AuditLogs
| where OperationName has_any (pWord) and OperationName has_any (action) and Result =~ "success"
| where OperationName !in (selfServicePasswordReset)
| mv-apply TargetResource = TargetResources on
(
where TargetResource.type =~ "User"
| extend AccountType = tostring(TargetResource.type),
Account = tostring(InitiatedBy.user.userPrincipalName),
TargetUserName = tolower(tostring(TargetResource.userPrincipalName))
)
| project TimeGenerated, AccountType, Account, TargetUserName, Computer = "", Type),
(//OfficeActive ActiveDirectory Password reset events
OfficeActivity
| where OfficeWorkload == "AzureActiveDirectory"
| where (ExtendedProperties has_any (pWord) or ModifiedProperties has_any (pWord)) and (ExtendedProperties has_any (action) or ModifiedProperties has_any (action))
| extend AccountType = UserType, Account = OfficeObjectId
| project TimeGenerated, AccountType, Account, Type, Computer = ""),
(// Unix syslog password reset events
Syslog
| where Facility in ("auth","authpriv")
| where SyslogMessage has_any (pWord) and SyslogMessage has_any (action)
| extend AccountType = iif(SyslogMessage contains "root", "Root", "Non-Root")
| where SyslogMessage matches regex ".*password changed for.*"
| parse SyslogMessage with * "password changed for" Account
| project TimeGenerated, AccountType, Account, Computer = HostName, Type)
);
let pwrmd = PasswordResetMultiDataSource
| project TimeGenerated, Computer, AccountType, Account, Type, TargetUserName;
(union isfuzzy=true
(pwrmd
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), Computerlist = make_set(Computer, 25), AccountType = make_set(AccountType, 25), Computer = arg_max(Computer , TimeGenerated), TargetUserList = make_set(TargetUserName, 25), TargetUserName = arg_max(TargetUserName, TimeGenerated), Total=count() by Account, Type
| where Total > PerUserThreshold
| extend ResetPivot = "PerUserReset"),
(pwrmd
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ComputerList = make_set(Computer, 25), AccountList = make_set(Account, 25), AccountType = make_set(AccountType, 25), Computer = arg_max(Computer , TimeGenerated), TargetUserList = make_set(TargetUserName, 25), TargetUserName = arg_max(TargetUserName, TimeGenerated), Total=count() by Type
| where Total > TotalThreshold
| extend ResetPivot = "TotalUserReset")
)
| extend timestamp = StartTimeUtc, HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.')), Name = tostring(split(Account, '@', 0)[0]), UPNSuffix = tostring(split(Account, '@', 1)[0]), TargetName = tostring(split(TargetUserName,'@',0)[0]), TargetUPNSuffix = tostring(split(TargetUserName,'@',1)[0])
relevantTechniques:
- T1078
- T1110
name: Multiple Password Reset by user
requiredDataConnectors:
- dataTypes:
- AuditLogs
connectorId: AzureActiveDirectory
- dataTypes:
- SecurityEvent
connectorId: SecurityEvents
- dataTypes:
- Syslog
connectorId: Syslog
- dataTypes:
- OfficeActivity
connectorId: Office365
- dataTypes:
- SecurityEvents
connectorId: WindowsSecurityEvents
- dataTypes:
- WindowsEvent
connectorId: WindowsForwardedEvents
entityMappings:
- fieldMappings:
- identifier: FullName
columnName: Account
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
entityType: Account
- fieldMappings:
- identifier: FullName
columnName: Computer
- identifier: HostName
columnName: HostName
- identifier: DnsDomain
columnName: DnsDomain
entityType: Host
- fieldMappings:
- identifier: FullName
columnName: TargetUserName
- identifier: Name
columnName: TargetName
- identifier: UPNSuffix
columnName: TargetUPNSuffix
entityType: Account
triggerThreshold: 0
id: 0b9ae89d-8cad-461c-808f-0494f70ad5c4
tactics:
- InitialAccess
- CredentialAccess
version: 2.1.7
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/MultipleDataSources/MultiplePasswordresetsbyUser.yaml
queryPeriod: 1d
kind: Scheduled
metadata:
categories:
domains:
- Security - Others
- Identity
author:
name: Microsoft Security Research
support:
tier: Community
source:
kind: Community
queryFrequency: 1d
severity: Low
description: |
'This query will determine multiple password resets by user across multiple data sources.
Account manipulation including password reset may aid adversaries in maintaining access to credentials and certain permission levels within an environment.'
query: |
let selfServicePasswordReset = dynamic(["Self-service password reset flow activity progress", "Change password (self-service)", "Reset password (self-service)"]);
//Self-service password reset flow activity progress is typically caused by a password policy which requires users to rotate passwords. This operation already implies the user has signed in successfully and therefore the password reset is non-malicious.
let PerUserThreshold = 5;
let TotalThreshold = 100;
let action = dynamic(["change", "changed", "reset"]);
let pWord = dynamic(["password", "credentials"]);
let PasswordResetMultiDataSource =
(union isfuzzy=true
(//Password reset events
//4723: An attempt was made to change an account's password
//4724: An attempt was made to reset an accounts password
SecurityEvent
| where EventID in ("4723","4724")
| project TimeGenerated, Computer, AccountType, Account, Type, TargetUserName),
(//Password reset events
//4723: An attempt was made to change an account's password
//4724: An attempt was made to reset an accounts password
WindowsEvent
| where EventID in ("4723","4724")
| extend SubjectUserSid = tostring(EventData.SubjectUserSid)
| extend TargetUserName = tostring(EventData.TargetUserName)
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend AccountType=case(Account endswith "$" or SubjectUserSid in ("S-1-5-18", "S-1-5-19", "S-1-5-20"), "Machine", isempty(SubjectUserSid), "", "User")
| project TimeGenerated, Computer, AccountType, Account, Type, TargetUserName),
(//Azure Active Directory Password reset events
AuditLogs
| where OperationName has_any (pWord) and OperationName has_any (action) and Result =~ "success"
| where OperationName !in (selfServicePasswordReset)
| mv-apply TargetResource = TargetResources on
(
where TargetResource.type =~ "User"
| extend AccountType = tostring(TargetResource.type),
Account = tostring(InitiatedBy.user.userPrincipalName),
TargetUserName = tolower(tostring(TargetResource.userPrincipalName))
)
| project TimeGenerated, AccountType, Account, TargetUserName, Computer = "", Type),
(//OfficeActive ActiveDirectory Password reset events
OfficeActivity
| where OfficeWorkload == "AzureActiveDirectory"
| where (ExtendedProperties has_any (pWord) or ModifiedProperties has_any (pWord)) and (ExtendedProperties has_any (action) or ModifiedProperties has_any (action))
| extend AccountType = UserType, Account = OfficeObjectId
| project TimeGenerated, AccountType, Account, Type, Computer = ""),
(// Unix syslog password reset events
Syslog
| where Facility in ("auth","authpriv")
| where SyslogMessage has_any (pWord) and SyslogMessage has_any (action)
| extend AccountType = iif(SyslogMessage contains "root", "Root", "Non-Root")
| where SyslogMessage matches regex ".*password changed for.*"
| parse SyslogMessage with * "password changed for" Account
| project TimeGenerated, AccountType, Account, Computer = HostName, Type)
);
let pwrmd = PasswordResetMultiDataSource
| project TimeGenerated, Computer, AccountType, Account, Type, TargetUserName;
(union isfuzzy=true
(pwrmd
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), Computerlist = make_set(Computer, 25), AccountType = make_set(AccountType, 25), Computer = arg_max(Computer , TimeGenerated), TargetUserList = make_set(TargetUserName, 25), TargetUserName = arg_max(TargetUserName, TimeGenerated), Total=count() by Account, Type
| where Total > PerUserThreshold
| extend ResetPivot = "PerUserReset"),
(pwrmd
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ComputerList = make_set(Computer, 25), AccountList = make_set(Account, 25), AccountType = make_set(AccountType, 25), Computer = arg_max(Computer , TimeGenerated), TargetUserList = make_set(TargetUserName, 25), TargetUserName = arg_max(TargetUserName, TimeGenerated), Total=count() by Type
| where Total > TotalThreshold
| extend ResetPivot = "TotalUserReset")
)
| extend timestamp = StartTimeUtc, HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.')), Name = tostring(split(Account, '@', 0)[0]), UPNSuffix = tostring(split(Account, '@', 1)[0]), TargetName = tostring(split(TargetUserName,'@',0)[0]), TargetUPNSuffix = tostring(split(TargetUserName,'@',1)[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": [
{
"apiVersion": "2024-01-01-preview",
"id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/0b9ae89d-8cad-461c-808f-0494f70ad5c4')]",
"kind": "Scheduled",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/0b9ae89d-8cad-461c-808f-0494f70ad5c4')]",
"properties": {
"alertRuleTemplateName": "0b9ae89d-8cad-461c-808f-0494f70ad5c4",
"customDetails": null,
"description": "'This query will determine multiple password resets by user across multiple data sources.\nAccount manipulation including password reset may aid adversaries in maintaining access to credentials and certain permission levels within an environment.'\n",
"displayName": "Multiple Password Reset by user",
"enabled": true,
"entityMappings": [
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "Account",
"identifier": "FullName"
},
{
"columnName": "Name",
"identifier": "Name"
},
{
"columnName": "UPNSuffix",
"identifier": "UPNSuffix"
}
]
},
{
"entityType": "Host",
"fieldMappings": [
{
"columnName": "Computer",
"identifier": "FullName"
},
{
"columnName": "HostName",
"identifier": "HostName"
},
{
"columnName": "DnsDomain",
"identifier": "DnsDomain"
}
]
},
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "TargetUserName",
"identifier": "FullName"
},
{
"columnName": "TargetName",
"identifier": "Name"
},
{
"columnName": "TargetUPNSuffix",
"identifier": "UPNSuffix"
}
]
}
],
"OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Detections/MultipleDataSources/MultiplePasswordresetsbyUser.yaml",
"query": "let selfServicePasswordReset = dynamic([\"Self-service password reset flow activity progress\", \"Change password (self-service)\", \"Reset password (self-service)\"]); \n//Self-service password reset flow activity progress is typically caused by a password policy which requires users to rotate passwords. This operation already implies the user has signed in successfully and therefore the password reset is non-malicious.\nlet PerUserThreshold = 5;\nlet TotalThreshold = 100;\nlet action = dynamic([\"change\", \"changed\", \"reset\"]);\nlet pWord = dynamic([\"password\", \"credentials\"]);\nlet PasswordResetMultiDataSource =\n(union isfuzzy=true\n(//Password reset events\n//4723: An attempt was made to change an account's password\n//4724: An attempt was made to reset an accounts password\nSecurityEvent\n| where EventID in (\"4723\",\"4724\")\n| project TimeGenerated, Computer, AccountType, Account, Type, TargetUserName),\n(//Password reset events\n//4723: An attempt was made to change an account's password\n//4724: An attempt was made to reset an accounts password\nWindowsEvent\n| where EventID in (\"4723\",\"4724\")\n| extend SubjectUserSid = tostring(EventData.SubjectUserSid)\n| extend TargetUserName = tostring(EventData.TargetUserName)\n| extend Account = strcat(tostring(EventData.SubjectDomainName),\"\\\\\", tostring(EventData.SubjectUserName))\n| extend AccountType=case(Account endswith \"$\" or SubjectUserSid in (\"S-1-5-18\", \"S-1-5-19\", \"S-1-5-20\"), \"Machine\", isempty(SubjectUserSid), \"\", \"User\")\n| project TimeGenerated, Computer, AccountType, Account, Type, TargetUserName),\n(//Azure Active Directory Password reset events\nAuditLogs\n| where OperationName has_any (pWord) and OperationName has_any (action) and Result =~ \"success\"\n| where OperationName !in (selfServicePasswordReset)\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend AccountType = tostring(TargetResource.type),\n Account = tostring(InitiatedBy.user.userPrincipalName),\n TargetUserName = tolower(tostring(TargetResource.userPrincipalName))\n )\n| project TimeGenerated, AccountType, Account, TargetUserName, Computer = \"\", Type),\n(//OfficeActive ActiveDirectory Password reset events\nOfficeActivity\n| where OfficeWorkload == \"AzureActiveDirectory\"\n| where (ExtendedProperties has_any (pWord) or ModifiedProperties has_any (pWord)) and (ExtendedProperties has_any (action) or ModifiedProperties has_any (action))\n| extend AccountType = UserType, Account = OfficeObjectId\n| project TimeGenerated, AccountType, Account, Type, Computer = \"\"),\n(// Unix syslog password reset events\nSyslog\n| where Facility in (\"auth\",\"authpriv\")\n| where SyslogMessage has_any (pWord) and SyslogMessage has_any (action)\n| extend AccountType = iif(SyslogMessage contains \"root\", \"Root\", \"Non-Root\")\n| where SyslogMessage matches regex \".*password changed for.*\"\n| parse SyslogMessage with * \"password changed for\" Account\n| project TimeGenerated, AccountType, Account, Computer = HostName, Type)\n);\nlet pwrmd = PasswordResetMultiDataSource\n| project TimeGenerated, Computer, AccountType, Account, Type, TargetUserName;\n(union isfuzzy=true\n(pwrmd\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), Computerlist = make_set(Computer, 25), AccountType = make_set(AccountType, 25), Computer = arg_max(Computer , TimeGenerated), TargetUserList = make_set(TargetUserName, 25), TargetUserName = arg_max(TargetUserName, TimeGenerated), Total=count() by Account, Type\n| where Total > PerUserThreshold\n| extend ResetPivot = \"PerUserReset\"),\n(pwrmd\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ComputerList = make_set(Computer, 25), AccountList = make_set(Account, 25), AccountType = make_set(AccountType, 25), Computer = arg_max(Computer , TimeGenerated), TargetUserList = make_set(TargetUserName, 25), TargetUserName = arg_max(TargetUserName, TimeGenerated), Total=count() by Type\n| where Total > TotalThreshold\n| extend ResetPivot = \"TotalUserReset\")\n)\n| extend timestamp = StartTimeUtc, HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.')), Name = tostring(split(Account, '@', 0)[0]), UPNSuffix = tostring(split(Account, '@', 1)[0]), TargetName = tostring(split(TargetUserName,'@',0)[0]), TargetUPNSuffix = tostring(split(TargetUserName,'@',1)[0])\n",
"queryFrequency": "P1D",
"queryPeriod": "P1D",
"severity": "Low",
"subTechniques": [],
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"tactics": [
"CredentialAccess",
"InitialAccess"
],
"techniques": [
"T1078",
"T1110"
],
"templateVersion": "2.1.7",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0
},
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
}
]
}