Potential Remote Desktop Shadowing Activity
Identifies the modification of the Remote Desktop Protocol (RDP) Shadow registry or the execution of processes indicative of an active RDP shadowing session. An adversary may abuse the RDP Shadowing feature to spy on or control other users active RDP sessions.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2021/04/12"
3integration = ["endpoint", "windows", "m365_defender", "sentinel_one_cloud_funnel"]
4maturity = "production"
5updated_date = "2026/05/03"
6
7[rule]
8author = ["Elastic"]
9description = """
10Identifies the modification of the Remote Desktop Protocol (RDP) Shadow registry or the execution of processes
11indicative of an active RDP shadowing session. An adversary may abuse the RDP Shadowing feature to spy on or control
12other users active RDP sessions.
13"""
14from = "now-9m"
15index = [
16 "logs-endpoint.events.process-*",
17 "logs-endpoint.events.registry-*",
18 "winlogbeat-*",
19 "logs-windows.sysmon_operational-*",
20 "endgame-*",
21 "logs-m365_defender.event-*",
22 "logs-sentinel_one_cloud_funnel.*",
23]
24language = "eql"
25license = "Elastic License v2"
26name = "Potential Remote Desktop Shadowing Activity"
27references = [
28 "https://blog.bitsadmin.com/spying-on-users-using-rdp-shadowing",
29 "https://swarm.ptsecurity.com/remote-desktop-services-shadowing/",
30]
31risk_score = 73
32rule_id = "c57f8579-e2a5-4804-847f-f2732edc5156"
33severity = "high"
34tags = [
35 "Domain: Endpoint",
36 "OS: Windows",
37 "Use Case: Threat Detection",
38 "Tactic: Lateral Movement",
39 "Data Source: Elastic Endgame",
40 "Data Source: Elastic Defend",
41 "Data Source: Sysmon",
42 "Data Source: Microsoft Defender XDR",
43 "Data Source: SentinelOne",
44 "Resources: Investigation Guide",
45]
46timestamp_override = "event.ingested"
47type = "eql"
48
49query = '''
50/* Identifies the modification of RDP Shadow registry or
51 the execution of processes indicative of active shadow RDP session */
52
53any where host.os.type == "windows" and
54(
55 (event.category == "registry" and event.type == "change" and
56 registry.value : "Shadow" and
57 registry.path : (
58 "*\\Software\\Policies\\Microsoft\\Windows NT\\Terminal Services\\Shadow"
59 ) and
60 registry.data.strings : ("1", "0x00000001", "2", "0x00000002", "3", "0x00000003", "4", "0x00000004")
61
62 ) or
63 (event.category == "process" and event.type == "start" and
64 (
65 (process.name : ("RdpSaUacHelper.exe", "RdpSaProxy.exe") and process.parent.name : "svchost.exe") or
66 (?process.pe.original_file_name : "mstsc.exe" and process.args : "/shadow:*")
67 )
68 )
69)
70'''
71
72note = """## Triage and analysis
73
74### Investigating Potential Remote Desktop Shadowing Activity
75
76#### Possible investigation steps
77
78- Which RDP shadowing path fired?
79 - Focus: `event.category`, `process.name`, `process.command_line`, `registry.path`, `registry.data.strings`.
80 - Implication: escalate faster for active "mstsc.exe /shadow" use or a `Shadow` policy value that removes consent; lower suspicion only when alert-local evidence matches recognized helpdesk, training, or policy-setting activity with consent retained.
81- Do process identity and lineage fit RDP shadowing components?
82 - Focus: `process.executable`, `process.pe.original_file_name`, `process.code_signature.subject_name`, `process.code_signature.trusted`, `process.parent.command_line`.
83 - Hint: for registry alerts, recover same-process starts for lineage or command-line detail. $investigate_0
84 - Implication: escalate when "mstsc.exe", "RdpSaUacHelper.exe", or "RdpSaProxy.exe" runs from a user-writable path, has an unexpected signer, or has a parent inconsistent with Remote Desktop Services or a support launcher. A trusted Microsoft binary confirms identity, not authorization.
85- If the `Shadow` registry value fired, did the new setting remove consent or allow control?
86 - Focus: `registry.path`, `registry.data.strings` (decimal or hex: `1`/`0x00000001` = full control with consent, `2`/`0x00000002` = full control without consent, `3`/`0x00000003` = view only with consent, `4`/`0x00000004` = view only without consent), and `process.executable`.
87 - Implication: escalate when `registry.data.strings` is `2`/`0x00000002` (full control, no consent) or `4`/`0x00000004` (view, no consent) because these allow silent shadowing; treat `1`/`0x00000001` or `3`/`0x00000003` as weaker setup evidence because the user is prompted, unless active shadowing or unexplained lineage appears.
88- If a process event fired, does it show active session shadowing?
89 - Focus: `process.name`, `process.command_line`, `process.parent.name`, `process.parent.executable`.
90 - Hint: if `process.command_line` is truncated or normalized, verify "/shadow", "/control", and "/noConsentPrompt" boundaries with `process.args` before lowering suspicion.
91 - Implication: escalate when "mstsc.exe" includes "/shadow" with "/control" or "/noConsentPrompt". Treat "RdpSaUacHelper.exe" or "RdpSaProxy.exe" under a service host as active target-side shadowing that escalates when paired with no-consent/control, unexplained lineage, or unrecognized user-host context; a plain "mstsc.exe" launch without shadowing arguments is not enough.
92- Does user, host, and session context fit recognized support or training?
93 - Focus: `user.id`, `user.name`, `user.domain`, `host.id`, `process.Ext.session_info.logon_type`.
94 - Implication: escalate when `user.id` targets an unusual workstation, privileged session, or host with no matching shadow-support pattern; lower suspicion only when user-host pairing, session type, and branch evidence match the same recognized workflow.
95- Did the same actor prepare, persist, or extend the host-side shadowing activity?
96 - Focus: `user.id`, `process.entity_id`, `process.command_line`, `registry.path`, `registry.data.strings`.
97 - Hint: start with recovered same-process events; expand to same-host process and registry events only when local capability or context remains suspicious. $investigate_1
98 - Implication: escalate when the same user or lineage enumerates sessions, prepares alternate-token launch, changes Terminal Services or RDP state, launches admin tooling, or persists shadow settings; absent process or registry evidence narrows the case but does not clear the alert.
99- If local findings stay suspicious or unresolved, do related alerts expand scope?
100 - Focus: related alerts for the same `user.id` and `host.id`, especially remote-access, credential, remote-service, and persistence alerts.
101 - Hint: review same-user alerts when local branch and capability questions remain suspicious. $investigate_2
102 - Hint: review same-host alerts when host preparation or follow-on activity remains unresolved. $investigate_3
103 - Implication: broaden scope when related alerts show the same user or host in remote-access, credential, or persistence activity; keep scope narrow only when local evidence fits a recognized workflow and related alerts do not contradict it.
104
105- Using branch, capability, identity, lineage, user-host fit, host-side activity, and related alerts, escalate unauthorized no-consent/control shadowing or stealthy policy relaxation; close only when evidence binds to one recognized support, training, or policy workflow with no contradictions; if mixed or incomplete, preserve process and registry artifacts and escalate.
106
107### False positive analysis
108
109- Helpdesk support, training labs, and supervised administration can legitimately use "mstsc.exe /shadow" or target-side "RdpSa*" helpers. Confirm `process.command_line`, `process.name`, `process.parent.name`, `user.id`, `host.id`, and any `Shadow` value align with the same authorized workflow, without contradictory `process.command_line` or `registry.path` evidence. Without ticketing or support rosters, require telemetry-only recurrence of the same command pattern, user-host pairing, consent mode, and quiet follow-on profile before closing as benign.
110- Group Policy or endpoint management tooling can legitimately change `Shadow`. Confirm stable `process.executable`, `process.code_signature.subject_name`, `process.parent.command_line`, exact `registry.path`, and resulting `registry.data.strings` match the host class. Without change records or GPO inventories, require quiet recurrence of the same process and registry pattern for the same management scope before closing.
111- Before creating an exception, anchor it on the minimum confirmed workflow: `event.category`, exact `process.command_line` or `registry.path`, `registry.data.strings`, `user.id`, and `host.id`. Avoid exceptions on `process.name`, `registry.value`, or `Shadow` alone.
112
113### Response and remediation
114
115- If confirmed benign, reverse temporary containment and document the exact `event.category`, `process.command_line` or `registry.path`, `registry.data.strings`, `user.id`, and `host.id` that proved the support, training, or policy workflow. Create an exception only after the same narrow pattern recurs.
116- If suspicious but unconfirmed, preserve a case export with the process tree, `process.entity_id`, `process.command_line`, `process.parent.command_line`, `registry.path`, `registry.value`, `registry.data.strings`, affected `user.id`, affected `host.id`, and surrounding preparation or follow-on evidence before changing host state.
117- Apply reversible containment next: restore the `Shadow` policy to the pre-change value, disable shadowing with `0`, require consent with `1` or `3`, or restrict the involved account on the affected `host.id`. Escalate to host isolation only when shadowing is part of broader session abuse and the host role can tolerate isolation.
118- If confirmed malicious, isolate the host when feasible, then terminate active "mstsc.exe" or "RdpSa*" shadowing processes after recording their process identifiers and command lines. Revert unauthorized `Shadow` and related Terminal Services or RDP shadow permission changes after preservation.
119- Scope other hosts and users tied to the same `user.id`, `process.command_line`, `registry.path`, or `registry.data.strings` before removing artifacts or resetting access.
120- Remove malicious helper scripts or tooling found during scoping, revert unauthorized RDP service or policy changes, and reset credentials that may have been exposed in the shadowed session.
121- Post-incident hardening: keep `Shadow` at the least permissive accepted setting, restrict who can shadow sessions, review RDP-Tcp shadow permissions, and retain process and registry telemetry needed to distinguish support use from no-consent shadowing."""
122
123setup = """## Setup
124
125This 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.
126
127Setup instructions: https://ela.st/install-elastic-defend
128
129### Additional data sources
130
131This rule also supports the following third-party data sources. For setup instructions, refer to the links below:
132
133- [Microsoft Defender XDR](https://ela.st/m365-defender)
134- [SentinelOne Cloud Funnel](https://ela.st/sentinel-one-cloud-funnel)
135- [Sysmon Event ID 1 - Process Creation](https://ela.st/sysmon-event-1-setup)
136- [Sysmon Registry Events](https://ela.st/sysmon-event-reg-setup)
137"""
138
139[rule.investigation_fields]
140field_names = [
141 "@timestamp",
142 "event.category",
143 "host.id",
144 "user.id",
145 "process.entity_id",
146 "process.pid",
147 "process.executable",
148 "process.command_line",
149 "process.args",
150 "process.parent.name",
151 "process.pe.original_file_name",
152 "process.code_signature.trusted",
153 "registry.path",
154 "registry.value",
155 "registry.data.strings",
156]
157
158[transform]
159
160[[transform.investigate]]
161label = "Process events for the same process"
162description = ""
163providers = [
164 [
165 { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" },
166 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
167 { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" }
168 ],
169 [
170 { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" },
171 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
172 { excluded = false, field = "process.pid", queryType = "phrase", value = "{{process.pid}}", valueType = "string" }
173 ]
174]
175relativeFrom = "now-1h"
176relativeTo = "now"
177
178[[transform.investigate]]
179label = "Registry events on the host near the alert"
180description = ""
181providers = [
182 [
183 { excluded = false, field = "event.category", queryType = "phrase", value = "registry", valueType = "string" },
184 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" }
185 ]
186]
187relativeFrom = "now-1h"
188relativeTo = "now"
189
190[[transform.investigate]]
191label = "Alerts associated with the user"
192description = ""
193providers = [
194 [
195 { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
196 { excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" }
197 ]
198]
199relativeFrom = "now-48h/h"
200relativeTo = "now"
201
202[[transform.investigate]]
203label = "Alerts associated with the host"
204description = ""
205providers = [
206 [
207 { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
208 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" }
209 ]
210]
211relativeFrom = "now-48h/h"
212relativeTo = "now"
213
214[[rule.threat]]
215framework = "MITRE ATT&CK"
216
217[[rule.threat.technique]]
218id = "T1021"
219name = "Remote Services"
220reference = "https://attack.mitre.org/techniques/T1021/"
221
222[[rule.threat.technique.subtechnique]]
223id = "T1021.001"
224name = "Remote Desktop Protocol"
225reference = "https://attack.mitre.org/techniques/T1021/001/"
226
227[[rule.threat.technique]]
228id = "T1563"
229name = "Remote Service Session Hijacking"
230reference = "https://attack.mitre.org/techniques/T1563/"
231
232[[rule.threat.technique.subtechnique]]
233id = "T1563.002"
234name = "RDP Hijacking"
235reference = "https://attack.mitre.org/techniques/T1563/002/"
236
237[rule.threat.tactic]
238id = "TA0008"
239name = "Lateral Movement"
240reference = "https://attack.mitre.org/tactics/TA0008/"
241
242[[rule.threat]]
243framework = "MITRE ATT&CK"
244
245[[rule.threat.technique]]
246id = "T1113"
247name = "Screen Capture"
248reference = "https://attack.mitre.org/techniques/T1113/"
249
250[rule.threat.tactic]
251id = "TA0009"
252name = "Collection"
253reference = "https://attack.mitre.org/tactics/TA0009/"
Triage and analysis
Investigating Potential Remote Desktop Shadowing Activity
Possible investigation steps
-
Which RDP shadowing path fired?
- Focus:
event.category,process.name,process.command_line,registry.path,registry.data.strings. - Implication: escalate faster for active "mstsc.exe /shadow" use or a
Shadowpolicy value that removes consent; lower suspicion only when alert-local evidence matches recognized helpdesk, training, or policy-setting activity with consent retained.
- Focus:
-
Do process identity and lineage fit RDP shadowing components?
- Focus:
process.executable,process.pe.original_file_name,process.code_signature.subject_name,process.code_signature.trusted,process.parent.command_line. - Hint: for registry alerts, recover same-process starts for lineage or command-line detail. $investigate_0
- Implication: escalate when "mstsc.exe", "RdpSaUacHelper.exe", or "RdpSaProxy.exe" runs from a user-writable path, has an unexpected signer, or has a parent inconsistent with Remote Desktop Services or a support launcher. A trusted Microsoft binary confirms identity, not authorization.
- Focus:
-
If the
Shadowregistry value fired, did the new setting remove consent or allow control?- Focus:
registry.path,registry.data.strings(decimal or hex:1/0x00000001= full control with consent,2/0x00000002= full control without consent,3/0x00000003= view only with consent,4/0x00000004= view only without consent), andprocess.executable. - Implication: escalate when
registry.data.stringsis2/0x00000002(full control, no consent) or4/0x00000004(view, no consent) because these allow silent shadowing; treat1/0x00000001or3/0x00000003as weaker setup evidence because the user is prompted, unless active shadowing or unexplained lineage appears.
- Focus:
-
If a process event fired, does it show active session shadowing?
- Focus:
process.name,process.command_line,process.parent.name,process.parent.executable. - Hint: if
process.command_lineis truncated or normalized, verify "/shadow", "/control", and "/noConsentPrompt" boundaries withprocess.argsbefore lowering suspicion. - Implication: escalate when "mstsc.exe" includes "/shadow" with "/control" or "/noConsentPrompt". Treat "RdpSaUacHelper.exe" or "RdpSaProxy.exe" under a service host as active target-side shadowing that escalates when paired with no-consent/control, unexplained lineage, or unrecognized user-host context; a plain "mstsc.exe" launch without shadowing arguments is not enough.
- Focus:
-
Does user, host, and session context fit recognized support or training?
- Focus:
user.id,user.name,user.domain,host.id,process.Ext.session_info.logon_type. - Implication: escalate when
user.idtargets an unusual workstation, privileged session, or host with no matching shadow-support pattern; lower suspicion only when user-host pairing, session type, and branch evidence match the same recognized workflow.
- Focus:
-
Did the same actor prepare, persist, or extend the host-side shadowing activity?
- Focus:
user.id,process.entity_id,process.command_line,registry.path,registry.data.strings. - Hint: start with recovered same-process events; expand to same-host process and registry events only when local capability or context remains suspicious. $investigate_1
- Implication: escalate when the same user or lineage enumerates sessions, prepares alternate-token launch, changes Terminal Services or RDP state, launches admin tooling, or persists shadow settings; absent process or registry evidence narrows the case but does not clear the alert.
- Focus:
-
If local findings stay suspicious or unresolved, do related alerts expand scope?
- Focus: related alerts for the same
user.idandhost.id, especially remote-access, credential, remote-service, and persistence alerts. - Hint: review same-user alerts when local branch and capability questions remain suspicious. $investigate_2
- Hint: review same-host alerts when host preparation or follow-on activity remains unresolved. $investigate_3
- Implication: broaden scope when related alerts show the same user or host in remote-access, credential, or persistence activity; keep scope narrow only when local evidence fits a recognized workflow and related alerts do not contradict it.
- Focus: related alerts for the same
-
Using branch, capability, identity, lineage, user-host fit, host-side activity, and related alerts, escalate unauthorized no-consent/control shadowing or stealthy policy relaxation; close only when evidence binds to one recognized support, training, or policy workflow with no contradictions; if mixed or incomplete, preserve process and registry artifacts and escalate.
False positive analysis
- Helpdesk support, training labs, and supervised administration can legitimately use "mstsc.exe /shadow" or target-side "RdpSa*" helpers. Confirm
process.command_line,process.name,process.parent.name,user.id,host.id, and anyShadowvalue align with the same authorized workflow, without contradictoryprocess.command_lineorregistry.pathevidence. Without ticketing or support rosters, require telemetry-only recurrence of the same command pattern, user-host pairing, consent mode, and quiet follow-on profile before closing as benign. - Group Policy or endpoint management tooling can legitimately change
Shadow. Confirm stableprocess.executable,process.code_signature.subject_name,process.parent.command_line, exactregistry.path, and resultingregistry.data.stringsmatch the host class. Without change records or GPO inventories, require quiet recurrence of the same process and registry pattern for the same management scope before closing. - Before creating an exception, anchor it on the minimum confirmed workflow:
event.category, exactprocess.command_lineorregistry.path,registry.data.strings,user.id, andhost.id. Avoid exceptions onprocess.name,registry.value, orShadowalone.
Response and remediation
- If confirmed benign, reverse temporary containment and document the exact
event.category,process.command_lineorregistry.path,registry.data.strings,user.id, andhost.idthat proved the support, training, or policy workflow. Create an exception only after the same narrow pattern recurs. - If suspicious but unconfirmed, preserve a case export with the process tree,
process.entity_id,process.command_line,process.parent.command_line,registry.path,registry.value,registry.data.strings, affecteduser.id, affectedhost.id, and surrounding preparation or follow-on evidence before changing host state. - Apply reversible containment next: restore the
Shadowpolicy to the pre-change value, disable shadowing with0, require consent with1or3, or restrict the involved account on the affectedhost.id. Escalate to host isolation only when shadowing is part of broader session abuse and the host role can tolerate isolation. - If confirmed malicious, isolate the host when feasible, then terminate active "mstsc.exe" or "RdpSa*" shadowing processes after recording their process identifiers and command lines. Revert unauthorized
Shadowand related Terminal Services or RDP shadow permission changes after preservation. - Scope other hosts and users tied to the same
user.id,process.command_line,registry.path, orregistry.data.stringsbefore removing artifacts or resetting access. - Remove malicious helper scripts or tooling found during scoping, revert unauthorized RDP service or policy changes, and reset credentials that may have been exposed in the shadowed session.
- Post-incident hardening: keep
Shadowat the least permissive accepted setting, restrict who can shadow sessions, review RDP-Tcp shadow permissions, and retain process and registry telemetry needed to distinguish support use from no-consent shadowing.
References
Related rules
- Execution via TSClient Mountpoint
- Lateral Movement via Startup Folder
- Unusual Child Process of dns.exe
- Local Account TokenFilter Policy Disabled
- Microsoft Exchange Server UM Spawning Suspicious Processes