Creation of a Hidden Local User Account
Identifies the creation of a hidden local user account by appending the dollar sign to the account name. This is sometimes done by attackers to increase access to a system and avoid appearing in the results of accounts listing using the net users command.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2020/12/18"
3integration = ["endpoint", "windows", "m365_defender", "sentinel_one_cloud_funnel", "crowdstrike"]
4maturity = "production"
5updated_date = "2026/05/03"
6
7[rule]
8author = ["Elastic"]
9description = """
10Identifies the creation of a hidden local user account by appending the dollar sign to the account name. This is
11sometimes done by attackers to increase access to a system and avoid appearing in the results of accounts listing using
12the net users command.
13"""
14from = "now-9m"
15index = [
16 "winlogbeat-*",
17 "logs-endpoint.events.registry-*",
18 "logs-windows.sysmon_operational-*",
19 "endgame-*",
20 "logs-m365_defender.event-*",
21 "logs-sentinel_one_cloud_funnel.*",
22 "logs-crowdstrike.fdr*",
23]
24language = "eql"
25license = "Elastic License v2"
26name = "Creation of a Hidden Local User Account"
27references = [
28 "http://web.archive.org/web/20230329153858/https://blog.menasec.net/2019/02/threat-hunting-6-hiding-in-plain-sights_8.html",
29 "https://github.com/CyberMonitor/APT_CyberCriminal_Campagin_Collections/tree/master/2020/2020.12.15.Lazarus_Campaign",
30]
31risk_score = 73
32rule_id = "2edc8076-291e-41e9-81e4-e3fcbc97ae5e"
33severity = "high"
34tags = [
35 "Domain: Endpoint",
36 "OS: Windows",
37 "Use Case: Threat Detection",
38 "Tactic: Persistence",
39 "Resources: Investigation Guide",
40 "Data Source: Elastic Endgame",
41 "Data Source: Elastic Defend",
42 "Data Source: Sysmon",
43 "Data Source: Microsoft Defender XDR",
44 "Data Source: SentinelOne",
45 "Data Source: Crowdstrike",
46]
47timestamp_override = "event.ingested"
48type = "eql"
49
50query = '''
51registry where host.os.type == "windows" and event.type in ("change", "creation") and
52 registry.path : (
53 "HKLM\\SAM\\SAM\\Domains\\Account\\Users\\Names\\*$\\",
54 "\\REGISTRY\\MACHINE\\SAM\\SAM\\Domains\\Account\\Users\\Names\\*$\\",
55 "MACHINE\\SAM\\SAM\\Domains\\Account\\Users\\Names\\*$\\"
56)
57'''
58
59note = """## Triage and analysis
60
61### Investigating Creation of a Hidden Local User Account
62
63#### Possible investigation steps
64
65- What hidden local account did the SAM write create?
66 - Why: a `$` suffix is ambiguous in many logs, but `registry.path` under `SAM\\SAM\\Domains\\Account\\Users\\Names` is a local account-name entry and can be omitted from casual `net user` review.
67 - Focus: `registry.hive`, `registry.path`, `registry.key`, and `@timestamp` for the exact account name and creation time.
68 - Implication: high concern unless the exact `$`-suffixed account, `host.id`, and time fit one narrowly recognized provisioning or recovery workflow; lower concern only when creator, use, and scope checks do not contradict it.
69
70- Which process and parent caused the SAM entry?
71 - Focus: `process.entity_id`, `process.executable`, `process.command_line`, `process.parent.executable`, and `process.parent.command_line`.
72 - Implication: escalate for shells, script interpreters, remote-service launchers such as sc.exe, service-created cmd/net user chains, PsExec-like tools, user-writable binaries, or mismatched parents; lower concern only when creator path, parent, and arguments match one recognized account-management workflow.
73
74- Did the creator or its children perform other account, privilege, or persistence actions?
75 - Why: remote account creation can surface as a service-launched command, and the decisive `net user`, local-group, or cleanup action may be in the creator's process tree rather than the registry event alone.
76 - Focus: same-host registry and process activity for creator `process.entity_id` and child `process.parent.entity_id`: `process.command_line`, `registry.path`, `registry.value`, and `registry.data.strings`. $investigate_0
77 - Hint: if the parent is service-control or PsExec-like, keep service-created cmd/net user children in scope even when signed.
78 - Implication: escalate when the tree adds local-group membership, touches extra SAM or LSA paths, deletes staging commands, or creates other persistence; lower concern when activity stays limited to the recovered account inside the same recognized workflow.
79
80- Was the hidden account used by later process activity after creation?
81 - Why: remote or service use of `$`-suffixed accounts may leave little profile evidence, so process and session context carries more weight than profile artifacts.
82 - Focus: extract the account leaf from `registry.path`, then search same-host process starts after `@timestamp` where `user.name` matches it, reading `process.Ext.session_info.logon_type`, `process.executable`, and `process.command_line`.
83 - Hint: this pivot is manual unless the account name is normalized into a standalone alert field; avoid using the full SAM registry path as an account value.
84 - Implication: account use after creation strongly escalates when the account runs processes, appears in remote-interactive, network, service, or batch sessions, or launches administrative tooling; lower concern only when no process use appears and creator evidence fits a recognized provisioning path.
85
86- If local evidence is suspicious or unresolved, do recent same-actor or same-host alerts change scope?
87 - Focus: related alerts for creating `user.id` and `host.id`: account abuse, privilege escalation, remote execution, credential access, or additional persistence.
88 - Hint: use the creating-identity alert pivot. $investigate_1
89 - Hint: use the host alert pivot. $investigate_2
90 - Implication: broaden response when the same actor or host has related account, persistence, or privilege alerts; keep local when history is clean and local evidence already fits one recognized workflow.
91
92- What disposition is supported?
93 - Escalate for unexpected account or creator lineage, privilege or cleanup activity, later account use, or wider scope; close only when same-host telemetry proves one exact recognized workflow, using records only as corroboration; preserve evidence and escalate when answers stay mixed or incomplete.
94
95### False positive analysis
96
97- A pre-established local support-account provisioning or recovery workflow can create a `$`-suffixed local account, but close only on a complete telemetry match: exact `registry.path`, creator `process.executable`, `process.command_line`, parent process, `user.id`, and `host.id`, with no extra SAM, LSA, privilege-grant, or cleanup activity outside it. Use build, vendor, or maintenance records only to corroborate that match; never close or exception on records alone.
98- Treat one-off interactive creation, remote service-created cmd.exe or net.exe, script-driven creation, and creation on ordinary workstations or servers as suspicious by default. Hidden support accounts elsewhere or a signed creator binary are not enough to close.
99- Build exceptions only from the minimum confirmed workflow: exact hidden-account `registry.path`, stable creator executable and command pattern, parent workflow, `user.id`, and bounded `host.id` cohort. Avoid exceptions on all `$`-suffixed names, the SAM hive, `process.name` alone, or the rule name.
100
101### Response and remediation
102
103- If confirmed benign, reverse temporary containment and record the exact account path, creator lineage, user, and host cohort that proved the recurring workflow. Keep any exception as narrow as that confirmed pattern.
104- If suspicious but unconfirmed, export the alert, the triggering registry event, creator process details, current hidden-account state, privilege evidence found in process or registry review, and any process or session use by the hidden account before containment. Apply reversible actions first: disable the account, restrict its logon rights, or increase monitoring on the affected `host.id` and creating `user.id`; avoid deleting the account until evidence is preserved.
105- If confirmed malicious, preserve account state, creator process lineage, and related registry or process artifacts first. Then isolate the host when its role allows, disable the hidden account, and contain the creating identity or remote source when the evidence identifies one. After preservation and containment, remove unauthorized privilege, SAM, LSA, service, or scheduled-task changes introduced around the same time.
106- Post-incident hardening: restrict hidden support-account creation to controlled management tooling, audit the host for other local accounts ending in `$`, retain registry and process telemetry needed to reconstruct future account creation, and document blind spots around preexisting hidden accounts or later privilege grants.
107"""
108
109setup = """## Setup
110
111This rule is designed for data generated by [Elastic Defend](https://www.elastic.co/security/endpoint-security), which provides native endpoint detection and response, along with event enrichments designed to work with our detection rules.
112
113Setup instructions: https://ela.st/install-elastic-defend
114
115### Additional data sources
116
117This rule also supports the following third-party data sources. For setup instructions, refer to the links below:
118
119- [CrowdStrike](https://ela.st/crowdstrike-integration)
120- [Microsoft Defender XDR](https://ela.st/m365-defender)
121- [SentinelOne Cloud Funnel](https://ela.st/sentinel-one-cloud-funnel)
122- [Sysmon Registry Events](https://ela.st/sysmon-event-reg-setup)
123"""
124
125[rule.investigation_fields]
126field_names = [
127 "@timestamp",
128 "host.name",
129 "host.id",
130 "user.id",
131 "process.entity_id",
132 "process.pid",
133 "process.executable",
134 "process.command_line",
135 "process.parent.name",
136 "process.parent.executable",
137 "process.parent.command_line",
138 "registry.hive",
139 "registry.path",
140 "registry.key",
141 "registry.value",
142]
143
144[transform]
145
146[[transform.investigate]]
147label = "Creator process and child activity on this host"
148description = ""
149providers = [
150 [
151 { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" },
152 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
153 { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" }
154 ],
155 [
156 { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" },
157 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
158 { excluded = false, field = "process.parent.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" }
159 ],
160 [
161 { excluded = false, field = "event.category", queryType = "phrase", value = "registry", valueType = "string" },
162 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
163 { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" }
164 ],
165 [
166 { excluded = false, field = "event.category", queryType = "phrase", value = "registry", valueType = "string" },
167 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
168 { excluded = false, field = "process.parent.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" }
169 ]
170]
171relativeFrom = "now-24h/h"
172relativeTo = "now"
173
174[[transform.investigate]]
175label = "Alerts associated with the creating identity"
176description = ""
177providers = [
178 [
179 { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
180 { excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" }
181 ]
182]
183relativeFrom = "now-48h/h"
184relativeTo = "now"
185
186[[transform.investigate]]
187label = "Alerts associated with the host"
188description = ""
189providers = [
190 [
191 { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
192 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" }
193 ]
194]
195relativeFrom = "now-48h/h"
196relativeTo = "now"
197
198[[rule.threat]]
199framework = "MITRE ATT&CK"
200
201[[rule.threat.technique]]
202id = "T1136"
203name = "Create Account"
204reference = "https://attack.mitre.org/techniques/T1136/"
205
206[[rule.threat.technique.subtechnique]]
207id = "T1136.001"
208name = "Local Account"
209reference = "https://attack.mitre.org/techniques/T1136/001/"
210
211[rule.threat.tactic]
212id = "TA0003"
213name = "Persistence"
214reference = "https://attack.mitre.org/tactics/TA0003/"
215
216[[rule.threat]]
217framework = "MITRE ATT&CK"
218
219[[rule.threat.technique]]
220id = "T1564"
221name = "Hide Artifacts"
222reference = "https://attack.mitre.org/techniques/T1564/"
223
224[[rule.threat.technique.subtechnique]]
225id = "T1564.002"
226name = "Hidden Users"
227reference = "https://attack.mitre.org/techniques/T1564/002/"
228
229[rule.threat.tactic]
230id = "TA0005"
231name = "Defense Evasion"
232reference = "https://attack.mitre.org/tactics/TA0005/"
Triage and analysis
Investigating Creation of a Hidden Local User Account
Possible investigation steps
-
What hidden local account did the SAM write create?
- Why: a
$suffix is ambiguous in many logs, butregistry.pathunderSAM\SAM\Domains\Account\Users\Namesis a local account-name entry and can be omitted from casualnet userreview. - Focus:
registry.hive,registry.path,registry.key, and@timestampfor the exact account name and creation time. - Implication: high concern unless the exact
$-suffixed account,host.id, and time fit one narrowly recognized provisioning or recovery workflow; lower concern only when creator, use, and scope checks do not contradict it.
- Why: a
-
Which process and parent caused the SAM entry?
- Focus:
process.entity_id,process.executable,process.command_line,process.parent.executable, andprocess.parent.command_line. - Implication: escalate for shells, script interpreters, remote-service launchers such as sc.exe, service-created cmd/net user chains, PsExec-like tools, user-writable binaries, or mismatched parents; lower concern only when creator path, parent, and arguments match one recognized account-management workflow.
- Focus:
-
Did the creator or its children perform other account, privilege, or persistence actions?
- Why: remote account creation can surface as a service-launched command, and the decisive
net user, local-group, or cleanup action may be in the creator's process tree rather than the registry event alone. - Focus: same-host registry and process activity for creator
process.entity_idand childprocess.parent.entity_id:process.command_line,registry.path,registry.value, andregistry.data.strings. $investigate_0 - Hint: if the parent is service-control or PsExec-like, keep service-created cmd/net user children in scope even when signed.
- Implication: escalate when the tree adds local-group membership, touches extra SAM or LSA paths, deletes staging commands, or creates other persistence; lower concern when activity stays limited to the recovered account inside the same recognized workflow.
- Why: remote account creation can surface as a service-launched command, and the decisive
-
Was the hidden account used by later process activity after creation?
- Why: remote or service use of
$-suffixed accounts may leave little profile evidence, so process and session context carries more weight than profile artifacts. - Focus: extract the account leaf from
registry.path, then search same-host process starts after@timestampwhereuser.namematches it, readingprocess.Ext.session_info.logon_type,process.executable, andprocess.command_line. - Hint: this pivot is manual unless the account name is normalized into a standalone alert field; avoid using the full SAM registry path as an account value.
- Implication: account use after creation strongly escalates when the account runs processes, appears in remote-interactive, network, service, or batch sessions, or launches administrative tooling; lower concern only when no process use appears and creator evidence fits a recognized provisioning path.
- Why: remote or service use of
-
If local evidence is suspicious or unresolved, do recent same-actor or same-host alerts change scope?
- Focus: related alerts for creating
user.idandhost.id: account abuse, privilege escalation, remote execution, credential access, or additional persistence. - Hint: use the creating-identity alert pivot. $investigate_1
- Hint: use the host alert pivot. $investigate_2
- Implication: broaden response when the same actor or host has related account, persistence, or privilege alerts; keep local when history is clean and local evidence already fits one recognized workflow.
- Focus: related alerts for creating
-
What disposition is supported?
- Escalate for unexpected account or creator lineage, privilege or cleanup activity, later account use, or wider scope; close only when same-host telemetry proves one exact recognized workflow, using records only as corroboration; preserve evidence and escalate when answers stay mixed or incomplete.
False positive analysis
- A pre-established local support-account provisioning or recovery workflow can create a
$-suffixed local account, but close only on a complete telemetry match: exactregistry.path, creatorprocess.executable,process.command_line, parent process,user.id, andhost.id, with no extra SAM, LSA, privilege-grant, or cleanup activity outside it. Use build, vendor, or maintenance records only to corroborate that match; never close or exception on records alone. - Treat one-off interactive creation, remote service-created cmd.exe or net.exe, script-driven creation, and creation on ordinary workstations or servers as suspicious by default. Hidden support accounts elsewhere or a signed creator binary are not enough to close.
- Build exceptions only from the minimum confirmed workflow: exact hidden-account
registry.path, stable creator executable and command pattern, parent workflow,user.id, and boundedhost.idcohort. Avoid exceptions on all$-suffixed names, the SAM hive,process.namealone, or the rule name.
Response and remediation
- If confirmed benign, reverse temporary containment and record the exact account path, creator lineage, user, and host cohort that proved the recurring workflow. Keep any exception as narrow as that confirmed pattern.
- If suspicious but unconfirmed, export the alert, the triggering registry event, creator process details, current hidden-account state, privilege evidence found in process or registry review, and any process or session use by the hidden account before containment. Apply reversible actions first: disable the account, restrict its logon rights, or increase monitoring on the affected
host.idand creatinguser.id; avoid deleting the account until evidence is preserved. - If confirmed malicious, preserve account state, creator process lineage, and related registry or process artifacts first. Then isolate the host when its role allows, disable the hidden account, and contain the creating identity or remote source when the evidence identifies one. After preservation and containment, remove unauthorized privilege, SAM, LSA, service, or scheduled-task changes introduced around the same time.
- Post-incident hardening: restrict hidden support-account creation to controlled management tooling, audit the host for other local accounts ending in
$, retain registry and process telemetry needed to reconstruct future account creation, and document blind spots around preexisting hidden accounts or later privilege grants.
References
Related rules
- Persistence via Hidden Run Key Detected
- Persistence via Microsoft Office AddIns
- Persistence via TelemetryController Scheduled Task Hijack
- Suspicious ImagePath Service Creation
- Suspicious Startup Shell Folder Modification