Detection rules › Kusto
AD user enabled and password not set within 48 hours
Identifies when an account is enabled with a default password and the password is not set by the user within 48 hours. Effectively, there is an event 4722 indicating an account was enabled and within 48 hours, no event 4723 occurs which indicates there was no attempt by the user to set the password. This will show any attempts (success or fail) that occur after 48 hours, which can indicate too long of a time period in setting the password to something that only the user knows. It is recommended that this time period is adjusted per your internal company policy.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Persistence |
Telemetry coverage
Rule body
id: 62085097-d113-459f-9ea7-30216f2ee6af
name: AD user enabled and password not set within 48 hours
description: |
'Identifies when an account is enabled with a default password and the password is not set by the user within 48 hours.
Effectively, there is an event 4722 indicating an account was enabled and within 48 hours, no event 4723 occurs which
indicates there was no attempt by the user to set the password. This will show any attempts (success or fail) that occur
after 48 hours, which can indicate too long of a time period in setting the password to something that only the user knows.
It is recommended that this time period is adjusted per your internal company policy.'
severity: Low
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsSecurityEvents
dataTypes:
- SecurityEvent
queryFrequency: 1d
queryPeriod: 3d
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- Persistence
relevantTechniques:
- T1098
query: |
let starttime = 3d;
let SecEvents = materialize ( SecurityEvent | where TimeGenerated >= ago(starttime)
| where EventID in (4722,4723) | where TargetUserName !endswith "$"
| project TimeGenerated, EventID, Activity, Computer, TargetAccount, TargetSid, SubjectAccount, SubjectUserSid);
let userEnable = SecEvents
| extend EventID4722Time = TimeGenerated
// 4722: User Account Enabled
| where EventID == 4722
| project Time_Event4722 = TimeGenerated, TargetAccount, TargetSid, SubjectAccount_Event4722 = SubjectAccount, SubjectUserSid_Event4722 = SubjectUserSid, Activity_4722 = Activity, Computer_4722 = Computer;
let userPwdSet = SecEvents
// 4723: Attempt made by user to set password
| where EventID == 4723
| project Time_Event4723 = TimeGenerated, TargetAccount, TargetSid, SubjectAccount_Event4723 = SubjectAccount, SubjectUserSid_Event4723 = SubjectUserSid, Activity_4723 = Activity, Computer_4723 = Computer;
userEnable | join kind=leftouter userPwdSet on TargetAccount, TargetSid
| extend PasswordSetAttemptDelta_Min = datetime_diff('minute', Time_Event4723, Time_Event4722)
| where PasswordSetAttemptDelta_Min > 2880 or isempty(PasswordSetAttemptDelta_Min)
| project-away TargetAccount1, TargetSid1
| extend Reason = @"User either has not yet attempted to set the initial password after account was enabled or it occurred after 48 hours"
| order by Time_Event4722 asc
| project-reorder Time_Event4722, Time_Event4723, PasswordSetAttemptDelta_Min, TargetAccount, TargetSid
| extend Computer = coalesce(Computer_4723, Computer_4722)
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
| extend AccountName = tostring(split(TargetAccount, "\\")[1]), AccountNTDomain = tostring(split(TargetAccount, "\\")[0])
| project-away DomainIndex
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: TargetAccount
- identifier: Name
columnName: AccountName
- identifier: NTDomain
columnName: AccountNTDomain
- entityType: Account
fieldMappings:
- identifier: Sid
columnName: TargetSid
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: Computer
- identifier: HostName
columnName: HostName
- identifier: DnsDomain
columnName: HostNameDomain
version: 1.0.4
kind: Scheduled
Stages and Predicates
Stage 0: let
let starttime = 3d;
let SecEvents = materialize(<inlined as stages below>);
let userEnable = SecEvents <inlined as stages below>;
let userPwdSet = SecEvents
| where EventID == 4723
| project Time_Event4723 = TimeGenerated, TargetAccount, TargetSid, SubjectAccount_Event4723 = SubjectAccount, SubjectUserSid_Event4723 = SubjectUserSid, Activity_4723 = Activity, Computer_4723 = Computer;
Stage 1: source
let SecEvents
Stage 2: source
let userEnable
Stage 3: source
let userPwdSet
Stage 4: source
SecurityEvent
Stage 5: where
| where TimeGenerated >= ago(starttime)
Stage 6: where
| where EventID in (4722,4723)
Stage 7: where
| where TargetUserName !endswith "$"
Stage 8: project
| project TimeGenerated, EventID, Activity, Computer, TargetAccount, TargetSid, SubjectAccount, SubjectUserSid
Stage 9: extend
| extend EventID4722Time = TimeGenerated
Stage 10: where
| where EventID == 4722
Stage 11: project
| project Time_Event4722 = TimeGenerated, TargetAccount, TargetSid, SubjectAccount_Event4722 = SubjectAccount, SubjectUserSid_Event4722 = SubjectUserSid, Activity_4722 = Activity, Computer_4722 = Computer
Stage 12: join
| join kind=leftouter userPwdSet on TargetAccount, TargetSid
Stage 13: extend
extend PasswordSetAttemptDelta_Min
Stage 14: where
where (PasswordSetAttemptDelta_Min > 2880 or isempty(PasswordSetAttemptDelta_Min))
Stage 15: project-away
project-away TargetAccount1, TargetSid1
Stage 16: extend
extend Reason
Stage 17: sort
sort by Time_Event4722
Stage 18: project-reorder
project-reorder
Stage 19: extend (4 consecutive steps)
extend AccountNTDomain, AccountName, Computer, DomainIndex, HostName, HostNameDomain
Stage 20: project-away
project-away DomainIndex
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventID | eq |
| field:"EventID" kind:eq |
EventID | in |
| field:"EventID" kind:in |
PasswordSetAttemptDelta_Min | gt |
| field:"PasswordSetAttemptDelta_Min" kind:gt value:"2880" |
PasswordSetAttemptDelta_Min | is_null | field:"PasswordSetAttemptDelta_Min" kind:is_null |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
TargetUserName | ends_with | $ | excludes:TargetUserName field:"TargetUserName" value:"$" |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Activity_4722 | project |
Computer_4722 | project |
SubjectAccount_Event4722 | project |
SubjectUserSid_Event4722 | project |
TargetAccount | project |
TargetSid | project |
Time_Event4722 | project |
PasswordSetAttemptDelta_Min | extend |
Reason | extend |
Computer | extend |
HostName | extend |
HostNameDomain | extend |
AccountNTDomain | extend |
AccountName | extend |