Detection rules › Kusto
User account created and deleted within 10 mins
Identifies when a user account is created and then deleted within 10 minutes. This can be an indication of compromise and an adversary attempting to hide in the noise.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Persistence | T1078 Valid Accounts, T1098 Account Manipulation |
| Privilege Escalation | T1078 Valid Accounts, T1098 Account Manipulation |
Event coverage
| Provider | Event | Title |
|---|---|---|
| Security-Auditing | Event ID 4720 | A user account was created. |
| Security-Auditing | Event ID 4726 | A user account was deleted. |
Rule body kusto
id: 4b93c5af-d20b-4236-b696-a28b8c51407f
name: User account created and deleted within 10 mins
description: |
'Identifies when a user account is created and then deleted within 10 minutes. This can be an indication of compromise and an adversary attempting to hide in the noise.'
severity: Medium
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsSecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsForwardedEvents
dataTypes:
- WindowsEvent
queryFrequency: 1d
queryPeriod: 25h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
- PrivilegeEscalation
relevantTechniques:
- T1098
- T1078
query: |
let timeframe = 1d;
let spanoftime = 10m;
let threshold = 0;
(union isfuzzy=true
(SecurityEvent
| where TimeGenerated > ago(timeframe+spanoftime)
// A user account was created
| where EventID == 4720
| where AccountType =~ "User"
| project creationTime = TimeGenerated, CreateEventID = EventID, CreateActivity = Activity, Computer = toupper(Computer),
TargetAccount = tolower(TargetAccount), TargetUserName, TargetDomainName, TargetSid,
AccountUsedToCreate = SubjectAccount, CreatedBySubjectUserName = SubjectUserName, CreatedBySubjectDomainName = SubjectDomainName, SIDofAccountUsedToCreate = SubjectUserSid, UserPrincipalName
),
(
WindowsEvent
| where TimeGenerated > ago(timeframe+spanoftime)
// A user account was created
| where EventID == 4720
| extend SubjectUserSid = tostring(EventData.SubjectUserSid)
| extend AccountType=case(EventData.SubjectUserName endswith "$" or SubjectUserSid in ("S-1-5-18", "S-1-5-19", "S-1-5-20"), "Machine", isempty(SubjectUserSid), "", "User")
| where AccountType =~ "User"
| extend SubjectAccount = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend SubjectDomainName = tostring(EventData.SubjectDomainName), SubjectUserName = tostring(EventData.SubjectUserName)
| extend TargetAccount = strcat(EventData.TargetDomainName,"\\", EventData.TargetUserName)
| extend TargetSid = tostring(EventData.TargetSid)
| extend UserPrincipalName = tostring(EventData.UserPrincipalName)
| extend Activity = "4720 - A user account was created."
| extend TargetUserName = tostring(EventData.TargetUserName), TargetDomainName = tostring(EventData.TargetDomainName)
| project creationTime = TimeGenerated, CreateEventID = EventID, CreateActivity = Activity, Computer = toupper(Computer),
TargetAccount = tolower(TargetAccount), TargetUserName, TargetDomainName, TargetSid,
AccountUsedToCreate = SubjectAccount, CreatedBySubjectUserName = SubjectUserName, CreatedBySubjectDomainName = SubjectDomainName, SIDofAccountUsedToCreate = SubjectUserSid, UserPrincipalName
)
)
| join kind = inner
(
(union isfuzzy=true
(SecurityEvent
| where TimeGenerated > ago(timeframe)
// A user account was deleted
| where EventID == 4726
| where AccountType == "User"
| project deletionTime = TimeGenerated, DeleteEventID = EventID, DeleteActivity = Activity, Computer = toupper(Computer),
TargetAccount = tolower(TargetAccount), TargetUserName, TargetDomainName, TargetSid,
AccountUsedToDelete = SubjectAccount, DeletedBySubjectUserName = SubjectUserName, DeletedBySubjectDomainName = SubjectDomainName, SIDofAccountUsedToDelete = SubjectUserSid, UserPrincipalName
),
(WindowsEvent
| where TimeGenerated > ago(timeframe)
// A user account was deleted
| where EventID == 4726
| extend SubjectUserSid = tostring(EventData.SubjectUserSid)
| extend SubjectAccount = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend AccountType=case(SubjectAccount endswith "$" or SubjectUserSid in ("S-1-5-18", "S-1-5-19", "S-1-5-20"), "Machine", isempty(SubjectUserSid), "", "User")
| where AccountType == "User"
| extend SubjectDomainName = tostring(EventData.SubjectDomainName), SubjectUserName = tostring(EventData.SubjectUserName)
| extend TargetSid = tostring(EventData.TargetSid)
| extend UserPrincipalName = tostring(EventData.UserPrincipalName)
| extend Activity = "4726 - A user account was deleted."
| extend TargetUserName = tostring(EventData.TargetUserName), TargetDomainName = tostring(EventData.TargetDomainName)
| extend TargetAccount = strcat(EventData.TargetDomainName,"\\", EventData.TargetUserName)
| project deletionTime = TimeGenerated, DeleteEventID = EventID, DeleteActivity = Activity, Computer = toupper(Computer),
TargetAccount = tolower(TargetAccount), TargetUserName, TargetDomainName, TargetSid,
AccountUsedToDelete = SubjectAccount, DeletedBySubjectUserName = SubjectUserName, DeletedBySubjectDomainName = SubjectDomainName, SIDofAccountUsedToDelete = SubjectUserSid, UserPrincipalName
)
)
) on Computer, TargetAccount
| where deletionTime - creationTime < spanoftime
| extend TimeDelta = deletionTime - creationTime
| where tolong(TimeDelta) >= threshold
| project TimeDelta, creationTime, CreateEventID, CreateActivity, Computer, TargetAccount, TargetSid, UserPrincipalName, AccountUsedToCreate, SIDofAccountUsedToCreate,
deletionTime, DeleteEventID, DeleteActivity, AccountUsedToDelete, SIDofAccountUsedToDelete, TargetUserName, TargetDomainName,
CreatedBySubjectUserName, CreatedBySubjectDomainName, DeletedBySubjectUserName, DeletedBySubjectDomainName
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
| project-away DomainIndex
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountUsedToCreate
- identifier: Name
columnName: CreatedBySubjectUserName
- identifier: NTDomain
columnName: CreatedBySubjectDomainName
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountUsedToDelete
- identifier: Name
columnName: DeletedBySubjectUserName
- identifier: NTDomain
columnName: DeletedBySubjectDomainName
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: TargetAccount
- identifier: Name
columnName: TargetUserName
- identifier: NTDomain
columnName: TargetDomainName
- entityType: Account
fieldMappings:
- identifier: Sid
columnName: TargetSid
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: Computer
- identifier: HostName
columnName: HostName
- identifier: NTDomain
columnName: HostNameDomain
version: 1.2.2
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Microsoft Security Research
support:
tier: Community
categories:
domains: [ "Security - Others", "Identity" ]
Stages and Predicates
Parameters
let timeframe = 1d;
let spanoftime = 10m;
let threshold = 0;
union isfuzzy=true (2 sources)
Each leg below queries one source; the rule matches if any leg does. Sources: SecurityEvent, WindowsEvent
Leg 1: SecurityEvent
SecurityEvent
| where TimeGenerated > ago(timeframe+spanoftime)
| where EventID == 4720
| where AccountType =~ "User"
| project creationTime = TimeGenerated, CreateEventID = EventID, CreateActivity = Activity, Computer = toupper(Computer),
TargetAccount = tolower(TargetAccount), TargetUserName, TargetDomainName, TargetSid,
AccountUsedToCreate = SubjectAccount, CreatedBySubjectUserName = SubjectUserName, CreatedBySubjectDomainName = SubjectDomainName, SIDofAccountUsedToCreate = SubjectUserSid, UserPrincipalName
Leg 2: WindowsEvent
WindowsEvent
| where TimeGenerated > ago(timeframe+spanoftime)
| where EventID == 4720
| extend SubjectUserSid = tostring(EventData.SubjectUserSid)
| extend AccountType=case(EventData.SubjectUserName endswith "$" or SubjectUserSid in ("S-1-5-18", "S-1-5-19", "S-1-5-20"), "Machine", isempty(SubjectUserSid), "", "User")
| where AccountType =~ "User"
| extend SubjectAccount = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend SubjectDomainName = tostring(EventData.SubjectDomainName), SubjectUserName = tostring(EventData.SubjectUserName)
| extend TargetAccount = strcat(EventData.TargetDomainName,"\\", EventData.TargetUserName)
| extend TargetSid = tostring(EventData.TargetSid)
| extend UserPrincipalName = tostring(EventData.UserPrincipalName)
| extend Activity = "4720 - A user account was created."
| extend TargetUserName = tostring(EventData.TargetUserName), TargetDomainName = tostring(EventData.TargetDomainName)
| project creationTime = TimeGenerated, CreateEventID = EventID, CreateActivity = Activity, Computer = toupper(Computer),
TargetAccount = tolower(TargetAccount), TargetUserName, TargetDomainName, TargetSid,
AccountUsedToCreate = SubjectAccount, CreatedBySubjectUserName = SubjectUserName, CreatedBySubjectDomainName = SubjectDomainName, SIDofAccountUsedToCreate = SubjectUserSid, UserPrincipalName
Applied to the combined result
| join kind = inner
(
(union isfuzzy=true
(SecurityEvent
| where TimeGenerated > ago(timeframe)
| where EventID == 4726
| where AccountType == "User"
| project deletionTime = TimeGenerated, DeleteEventID = EventID, DeleteActivity = Activity, Computer = toupper(Computer),
TargetAccount = tolower(TargetAccount), TargetUserName, TargetDomainName, TargetSid,
AccountUsedToDelete = SubjectAccount, DeletedBySubjectUserName = SubjectUserName, DeletedBySubjectDomainName = SubjectDomainName, SIDofAccountUsedToDelete = SubjectUserSid, UserPrincipalName
),
(WindowsEvent
| where TimeGenerated > ago(timeframe)
| where EventID == 4726
| extend SubjectUserSid = tostring(EventData.SubjectUserSid)
| extend SubjectAccount = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend AccountType=case(SubjectAccount endswith "$" or SubjectUserSid in ("S-1-5-18", "S-1-5-19", "S-1-5-20"), "Machine", isempty(SubjectUserSid), "", "User")
| where AccountType == "User"
| extend SubjectDomainName = tostring(EventData.SubjectDomainName), SubjectUserName = tostring(EventData.SubjectUserName)
| extend TargetSid = tostring(EventData.TargetSid)
| extend UserPrincipalName = tostring(EventData.UserPrincipalName)
| extend Activity = "4726 - A user account was deleted."
| extend TargetUserName = tostring(EventData.TargetUserName), TargetDomainName = tostring(EventData.TargetDomainName)
| extend TargetAccount = strcat(EventData.TargetDomainName,"\\", EventData.TargetUserName)
| project deletionTime = TimeGenerated, DeleteEventID = EventID, DeleteActivity = Activity, Computer = toupper(Computer),
TargetAccount = tolower(TargetAccount), TargetUserName, TargetDomainName, TargetSid,
AccountUsedToDelete = SubjectAccount, DeletedBySubjectUserName = SubjectUserName, DeletedBySubjectDomainName = SubjectDomainName, SIDofAccountUsedToDelete = SubjectUserSid, UserPrincipalName
)
)
) on Computer, TargetAccount
| where deletionTime - creationTime < spanoftime
| extend TimeDelta = deletionTime - creationTime
| where tolong(TimeDelta) >= threshold
| project TimeDelta, creationTime, CreateEventID, CreateActivity, Computer, TargetAccount, TargetSid, UserPrincipalName, AccountUsedToCreate, SIDofAccountUsedToCreate,
deletionTime, DeleteEventID, DeleteActivity, AccountUsedToDelete, SIDofAccountUsedToDelete, TargetUserName, TargetDomainName,
CreatedBySubjectUserName, CreatedBySubjectDomainName, DeletedBySubjectUserName, DeletedBySubjectDomainName
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
| project-away DomainIndex
Indicators
Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.
| Field | Kind | Values |
|---|---|---|
AccountType | eq |
|
EventID | eq |
|
TimeDelta | ge |
|
Output fields
Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.
| Field | Source |
|---|---|
AccountUsedToCreate | project |
AccountUsedToDelete | project |
Computer | project |
CreateActivity | project |
CreateEventID | project |
CreatedBySubjectDomainName | project |
CreatedBySubjectUserName | project |
DeleteActivity | project |
DeleteEventID | project |
DeletedBySubjectDomainName | project |
DeletedBySubjectUserName | project |
SIDofAccountUsedToCreate | project |
SIDofAccountUsedToDelete | project |
TargetAccount | project |
TargetDomainName | project |
TargetSid | project |
TargetUserName | project |
TimeDelta | project |
UserPrincipalName | project |
creationTime | project |
deletionTime | project |
HostName | extend |
HostNameDomain | extend |