Potential privilege escalation via CVE-2022-38028

Identifies a potential privilege escalation attempt via CVE-2022-38028 through modification of the protected Print to PDF MPDW constraints script.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2024/04/23"
  3integration = ["endpoint", "windows", "m365_defender", "sentinel_one_cloud_funnel", "crowdstrike"]
  4maturity = "production"
  5updated_date = "2026/05/03"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Identifies a potential privilege escalation attempt via CVE-2022-38028 through modification of the protected Print to PDF
 11MPDW constraints script.
 12"""
 13from = "now-9m"
 14index = [
 15    "logs-endpoint.events.file-*",
 16    "logs-windows.sysmon_operational-*",
 17    "endgame-*",
 18    "winlogbeat-*",
 19    "logs-m365_defender.event-*",
 20    "logs-sentinel_one_cloud_funnel.*",
 21    "logs-crowdstrike.fdr*",
 22]
 23language = "eql"
 24license = "Elastic License v2"
 25name = "Potential privilege escalation via CVE-2022-38028"
 26references = [
 27    "https://www.microsoft.com/en-us/security/blog/2024/04/22/analyzing-forest-blizzards-custom-post-compromise-tool-for-exploiting-cve-2022-38028-to-obtain-credentials/",
 28]
 29risk_score = 73
 30rule_id = "dffbd37c-d4c5-46f8-9181-5afdd9172b4c"
 31severity = "high"
 32tags = [
 33    "Domain: Endpoint",
 34    "OS: Windows",
 35    "Use Case: Threat Detection",
 36    "Tactic: Privilege Escalation",
 37    "Data Source: Elastic Endgame",
 38    "Data Source: Elastic Defend",
 39    "Data Source: Sysmon",
 40    "Data Source: Microsoft Defender XDR",
 41    "Data Source: SentinelOne",
 42    "Data Source: Crowdstrike",
 43    "Resources: Investigation Guide",
 44]
 45timestamp_override = "event.ingested"
 46type = "eql"
 47
 48query = '''
 49file where host.os.type == "windows" and event.type != "deletion" and
 50    file.name : "MPDW-constraints.js" and
 51    file.path : (
 52        "?:\\*\\Windows\\system32\\DriverStore\\FileRepository\\*\\MPDW-constraints.js",
 53        "?:\\*\\Windows\\WinSxS\\amd64_microsoft-windows-printing-printtopdf_*\\MPDW-constraints.js", 
 54        "\\Device\\HarddiskVolume*\\*\\Windows\\system32\\DriverStore\\FileRepository\\*\\MPDW-constraints.js",
 55        "\\Device\\HarddiskVolume*\\*\\Windows\\WinSxS\\amd64_microsoft-windows-printing-printtopdf_*\\MPDW-constraints.js"
 56    ) and
 57    not process.executable : (
 58          "?:\\$WINDOWS.~BT\\Sources\\SetupHost.exe",
 59          "?:\\Windows\\System32\\taskhostw.exe"
 60    ) and
 61    not file.path : (
 62        "?:\\$WINDOWS.~BT\\NewOS\\Windows\\WinSxS\\*\\MPDW-constraints.js",
 63        "\\Device\\HarddiskVolume*\\$WINDOWS.~BT\\NewOS\\Windows\\WinSxS\\*\\MPDW-constraints.js"
 64    )
 65'''
 66
 67note = """## Triage and analysis
 68
 69### Investigating Potential privilege escalation via CVE-2022-38028
 70
 71#### Possible investigation steps
 72
 73- Does the alert show protected-path MPDW-constraints.js placement outside Windows servicing?
 74  - Why: the rule proves a Print to PDF constraints-script write, not Print Spooler execution of the modified script.
 75  - Focus: confirm `file.path` is DriverStore or Print to PDF WinSxS for MPDW-constraints.js, then read `process.executable`, `process.command_line`, `process.parent.executable`, and `process.parent.command_line`. $investigate_0
 76  - Implication: escalate when the target is protected DriverStore or WinSxS and the writer is not Windows setup, repair, or print-component servicing; lower suspicion only when path, writer, parent, and surrounding servicing files match the same recognized OS or Print to PDF repair activity.
 77- Does the writer process look like GooseEgg staging rather than servicing?
 78  - Why: Microsoft observed GooseEgg launchers and batch scripts before Print Spooler redirection; writer identity and parentage separate servicing from exploit staging.
 79  - Focus: recover the writer start event with `process.entity_id`; compare `process.executable`, `process.hash.sha256`, `process.code_signature.subject_name`, `process.parent.executable`, and `process.parent.command_line`.
 80  - Implication: escalate when writer or parent is a batch/script host, user-writable or renamed binary, known GooseEgg launcher, or unsigned/unrecognized executable; lower suspicion when identity and lineage remain signed Windows servicing or recognized print-management tooling.
 81- Did the same writer stage GooseEgg files or copied driver-store content?
 82  - Why: published GooseEgg examples stage batch files, wayzgoose*.dll, and copied print-driver directories under version-like C:\\ProgramData\\<vendor>\\v#.#.# paths.
 83  - Focus: same `host.id` and `process.entity_id` file events: `file.path`, `file.name`, `file.Ext.original.path`, and `file.Ext.header_bytes` for staging, rename, or content clues. $investigate_1
 84  - Implication: escalate when those filenames, ProgramData version paths, copied driver-store directories, .save / .zip hive outputs, or rename chains appear around the writer; lower suspicion when the same-process file set is limited to recognized servicing content and no GooseEgg artifact family appears.
 85- If registry telemetry is available, did the writer create GooseEgg protocol or CLSID redirection?
 86  - Focus: same `host.id` and `process.entity_id` registry events, especially `registry.path`, `registry.value`, `registry.data.strings`, and `process.executable` for rogue protocol handler, CLSID, or wayzgoose*.dll paths. $investigate_2
 87  - Hint: missing registry telemetry is unresolved, not benign; continue with file, process, and spooler evidence.
 88  - Implication: escalate when registry changes register the rogue protocol or CLSID or point Print Spooler resolution to actor-controlled ProgramData content; lower suspicion only when available registry data remains recognized print-component configuration and file/process evidence is also clean.
 89- Did activation or spooler follow-on show SYSTEM-level execution?
 90  - Focus: process starts after the write on `host.id`: `process.name`, `process.parent.name`, `process.parent.executable`, `process.command_line`, and `process.Ext.token.integrity_level_name` for scheduled-task launch, spoolsv.exe, PrintIsolationHost.exe, or SYSTEM command tests. $investigate_3
 91  - Hint: with library telemetry, check `dll.name` and `dll.path` for wayzgoose*.dll or loads from the written driver-store path; missing library telemetry is unresolved for load proof, not benign.
 92  - Implication: escalate when the host shows scheduled-task activation as SYSTEM, spooler or print isolation child processes, a SYSTEM whoami test, or a wayzgoose*.dll load after the write; absence is no execution proof, not proof the write was benign.
 93- Does the suspicious artifact set recur enough to change scope?
 94  - Focus: after suspicious or unresolved local evidence, review recent alerts for `host.id`, then search `file.path`, suspicious `process.hash.sha256`, and GooseEgg filenames across hosts. $investigate_4
 95  - Implication: broaden containment and hunting when the same writer hash, ProgramData version path, wayzgoose*.dll, or protected MPDW-constraints.js placement appears on other hosts or pairs with spooler/privilege-escalation alerts; keep scope local when recurrence is absent and local evidence resolves to one recognized workflow.
 96- Escalate when protected-path placement aligns with non-servicing lineage or any GooseEgg, registry, scheduled-task, or spooler corroborator; close only when path, writer, parent, file set, user/host scope, and recovery bind to one recognized servicing or print workflow; preserve artifacts and escalate when evidence is mixed, missing, or contradictory.
 97
 98### False positive analysis
 99
100- Windows servicing, Print to PDF repair, printer-driver packaging, image-build, or print-management workflows can touch these paths. Confirm `file.path`, writer, parent, signer, `host.id` cohort, surrounding file set, and spooler follow-on all bind to one such workflow, with no GooseEgg artifacts, rogue registry evidence, or spooler child-process anomalies. Change records, patch windows, build records, or management tickets can corroborate; if unavailable, close only when telemetry independently proves the bounded workflow.
101- Before creating an exception, validate a stable benign workflow across prior alerts: keep writer identity, `process.parent.executable`, `file.path`, `host.id` cohort, and bounded file set stable. Avoid exceptions on MPDW-constraints.js alone, DriverStore or WinSxS paths alone, or spoolsv.exe activity alone.
102
103### Response and remediation
104
105- If confirmed benign, reverse temporary containment and record the `file.path`, writer identity, parent lineage, `host.id` cohort, and servicing or print-management file pattern that justified closure. Create an exception only for that recurring workflow.
106- If suspicious but unconfirmed, preserve the written MPDW-constraints.js, its path and hash when available, the writer `process.entity_id`, `process.executable`, `process.command_line`, parent lineage, `user.id`, GooseEgg scripts or DLLs, ProgramData staging directories, scheduled-task evidence, and any registry or library corroboration before cleanup. Apply reversible containment first, such as pausing nonessential printing, limiting print-management access, isolating the host when business impact permits, or increasing monitoring. Avoid deleting files, stopping spoolsv.exe, or restoring registry state until the evidence is preserved.
107- If confirmed malicious, preserve the same file, process, registry, library, scheduled-task, and spooler evidence first, then isolate the host through endpoint response when available and proportionate to host criticality. If direct response is unavailable, escalate with the preserved `file.path`, writer lineage, staging directory, registry redirection, and spooler follow-on evidence to the team that can act. After scope is clear, remove the malicious JavaScript, GooseEgg scripts, wayzgoose*.dll, ProgramData staging directory, scheduled task, and rogue registry/protocol state; restore affected print configuration, close the staging mechanism, and rotate credentials only for accounts or hives exposed by collected evidence.
108- Post-incident hardening: apply the Microsoft security update for CVE-2022-38028, disable Print Spooler on systems that do not need it, restrict print-management rights, retain file/process coverage plus registry or library telemetry where it limited the investigation, and document the confirmed MPDW-constraints.js, ProgramData, wayzgoose, or scheduled-task pattern for future triage.
109"""
110
111setup = """## Setup
112
113This 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.
114
115Setup instructions: https://ela.st/install-elastic-defend
116
117### Additional data sources
118
119This rule also supports the following third-party data sources. For setup instructions, refer to the links below:
120
121- [CrowdStrike](https://ela.st/crowdstrike-integration)
122- [Microsoft Defender XDR](https://ela.st/m365-defender)
123- [SentinelOne Cloud Funnel](https://ela.st/sentinel-one-cloud-funnel)
124- [Sysmon Event ID 11 - File Create](https://ela.st/sysmon-event-11-setup)
125"""
126
127[rule.investigation_fields]
128field_names = [
129    "@timestamp",
130    "host.name",
131    "host.id",
132    "user.id",
133    "process.executable",
134    "process.command_line",
135    "process.pid",
136    "process.entity_id",
137    "process.parent.executable",
138    "process.parent.command_line",
139    "process.hash.sha256",
140    "process.code_signature.subject_name",
141    "process.code_signature.trusted",
142    "file.path",
143    "file.name",
144]
145
146[transform]
147
148[[transform.investigate]]
149label = "File events for the same suspicious JavaScript path"
150description = ""
151providers = [
152  [
153    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
154    { excluded = false, field = "file.path", queryType = "phrase", value = "{{file.path}}", valueType = "string" }
155  ]
156]
157relativeFrom = "now-2h"
158relativeTo = "now"
159
160[[transform.investigate]]
161label = "File events from the writer process"
162description = ""
163providers = [
164  [
165    { excluded = false, field = "event.category", queryType = "phrase", value = "file", 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]
170relativeFrom = "now-2h"
171relativeTo = "now"
172
173[[transform.investigate]]
174label = "Registry events from the writer process"
175description = ""
176providers = [
177  [
178    { excluded = false, field = "event.category", queryType = "phrase", value = "registry", valueType = "string" },
179    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
180    { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" }
181  ]
182]
183relativeFrom = "now-2h"
184relativeTo = "now"
185
186[[transform.investigate]]
187label = "Process events after the protected file write"
188description = ""
189providers = [
190  [
191    { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" },
192    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" }
193  ]
194]
195relativeFrom = "now"
196relativeTo = "now"
197
198[[transform.investigate]]
199label = "Alerts associated with the host"
200description = ""
201providers = [
202  [
203    { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
204    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" }
205  ]
206]
207relativeFrom = "now-48h/h"
208relativeTo = "now"
209
210[[rule.threat]]
211framework = "MITRE ATT&CK"
212
213[[rule.threat.technique]]
214id = "T1068"
215name = "Exploitation for Privilege Escalation"
216reference = "https://attack.mitre.org/techniques/T1068/"
217
218[[rule.threat.technique]]
219id = "T1574"
220name = "Hijack Execution Flow"
221reference = "https://attack.mitre.org/techniques/T1574/"
222
223[[rule.threat.technique.subtechnique]]
224id = "T1574.010"
225name = "Services File Permissions Weakness"
226reference = "https://attack.mitre.org/techniques/T1574/010/"
227
228[rule.threat.tactic]
229id = "TA0004"
230name = "Privilege Escalation"
231reference = "https://attack.mitre.org/tactics/TA0004/"
232
233[[rule.threat]]
234framework = "MITRE ATT&CK"
235
236[[rule.threat.technique]]
237id = "T1036"
238name = "Masquerading"
239reference = "https://attack.mitre.org/techniques/T1036/"
240
241[rule.threat.tactic]
242id = "TA0005"
243name = "Defense Evasion"
244reference = "https://attack.mitre.org/tactics/TA0005/"

Triage and analysis

Investigating Potential privilege escalation via CVE-2022-38028

Possible investigation steps

  • Does the alert show protected-path MPDW-constraints.js placement outside Windows servicing?
    • Why: the rule proves a Print to PDF constraints-script write, not Print Spooler execution of the modified script.
    • Focus: confirm file.path is DriverStore or Print to PDF WinSxS for MPDW-constraints.js, then read process.executable, process.command_line, process.parent.executable, and process.parent.command_line. $investigate_0
    • Implication: escalate when the target is protected DriverStore or WinSxS and the writer is not Windows setup, repair, or print-component servicing; lower suspicion only when path, writer, parent, and surrounding servicing files match the same recognized OS or Print to PDF repair activity.
  • Does the writer process look like GooseEgg staging rather than servicing?
    • Why: Microsoft observed GooseEgg launchers and batch scripts before Print Spooler redirection; writer identity and parentage separate servicing from exploit staging.
    • Focus: recover the writer start event with process.entity_id; compare process.executable, process.hash.sha256, process.code_signature.subject_name, process.parent.executable, and process.parent.command_line.
    • Implication: escalate when writer or parent is a batch/script host, user-writable or renamed binary, known GooseEgg launcher, or unsigned/unrecognized executable; lower suspicion when identity and lineage remain signed Windows servicing or recognized print-management tooling.
  • Did the same writer stage GooseEgg files or copied driver-store content?
    • Why: published GooseEgg examples stage batch files, wayzgoose*.dll, and copied print-driver directories under version-like C:\ProgramData<vendor>\v#.#.# paths.
    • Focus: same host.id and process.entity_id file events: file.path, file.name, file.Ext.original.path, and file.Ext.header_bytes for staging, rename, or content clues. $investigate_1
    • Implication: escalate when those filenames, ProgramData version paths, copied driver-store directories, .save / .zip hive outputs, or rename chains appear around the writer; lower suspicion when the same-process file set is limited to recognized servicing content and no GooseEgg artifact family appears.
  • If registry telemetry is available, did the writer create GooseEgg protocol or CLSID redirection?
    • Focus: same host.id and process.entity_id registry events, especially registry.path, registry.value, registry.data.strings, and process.executable for rogue protocol handler, CLSID, or wayzgoose*.dll paths. $investigate_2
    • Hint: missing registry telemetry is unresolved, not benign; continue with file, process, and spooler evidence.
    • Implication: escalate when registry changes register the rogue protocol or CLSID or point Print Spooler resolution to actor-controlled ProgramData content; lower suspicion only when available registry data remains recognized print-component configuration and file/process evidence is also clean.
  • Did activation or spooler follow-on show SYSTEM-level execution?
    • Focus: process starts after the write on host.id: process.name, process.parent.name, process.parent.executable, process.command_line, and process.Ext.token.integrity_level_name for scheduled-task launch, spoolsv.exe, PrintIsolationHost.exe, or SYSTEM command tests. $investigate_3
    • Hint: with library telemetry, check dll.name and dll.path for wayzgoose*.dll or loads from the written driver-store path; missing library telemetry is unresolved for load proof, not benign.
    • Implication: escalate when the host shows scheduled-task activation as SYSTEM, spooler or print isolation child processes, a SYSTEM whoami test, or a wayzgoose*.dll load after the write; absence is no execution proof, not proof the write was benign.
  • Does the suspicious artifact set recur enough to change scope?
    • Focus: after suspicious or unresolved local evidence, review recent alerts for host.id, then search file.path, suspicious process.hash.sha256, and GooseEgg filenames across hosts. $investigate_4
    • Implication: broaden containment and hunting when the same writer hash, ProgramData version path, wayzgoose*.dll, or protected MPDW-constraints.js placement appears on other hosts or pairs with spooler/privilege-escalation alerts; keep scope local when recurrence is absent and local evidence resolves to one recognized workflow.
  • Escalate when protected-path placement aligns with non-servicing lineage or any GooseEgg, registry, scheduled-task, or spooler corroborator; close only when path, writer, parent, file set, user/host scope, and recovery bind to one recognized servicing or print workflow; preserve artifacts and escalate when evidence is mixed, missing, or contradictory.

False positive analysis

  • Windows servicing, Print to PDF repair, printer-driver packaging, image-build, or print-management workflows can touch these paths. Confirm file.path, writer, parent, signer, host.id cohort, surrounding file set, and spooler follow-on all bind to one such workflow, with no GooseEgg artifacts, rogue registry evidence, or spooler child-process anomalies. Change records, patch windows, build records, or management tickets can corroborate; if unavailable, close only when telemetry independently proves the bounded workflow.
  • Before creating an exception, validate a stable benign workflow across prior alerts: keep writer identity, process.parent.executable, file.path, host.id cohort, and bounded file set stable. Avoid exceptions on MPDW-constraints.js alone, DriverStore or WinSxS paths alone, or spoolsv.exe activity alone.

Response and remediation

  • If confirmed benign, reverse temporary containment and record the file.path, writer identity, parent lineage, host.id cohort, and servicing or print-management file pattern that justified closure. Create an exception only for that recurring workflow.
  • If suspicious but unconfirmed, preserve the written MPDW-constraints.js, its path and hash when available, the writer process.entity_id, process.executable, process.command_line, parent lineage, user.id, GooseEgg scripts or DLLs, ProgramData staging directories, scheduled-task evidence, and any registry or library corroboration before cleanup. Apply reversible containment first, such as pausing nonessential printing, limiting print-management access, isolating the host when business impact permits, or increasing monitoring. Avoid deleting files, stopping spoolsv.exe, or restoring registry state until the evidence is preserved.
  • If confirmed malicious, preserve the same file, process, registry, library, scheduled-task, and spooler evidence first, then isolate the host through endpoint response when available and proportionate to host criticality. If direct response is unavailable, escalate with the preserved file.path, writer lineage, staging directory, registry redirection, and spooler follow-on evidence to the team that can act. After scope is clear, remove the malicious JavaScript, GooseEgg scripts, wayzgoose*.dll, ProgramData staging directory, scheduled task, and rogue registry/protocol state; restore affected print configuration, close the staging mechanism, and rotate credentials only for accounts or hives exposed by collected evidence.
  • Post-incident hardening: apply the Microsoft security update for CVE-2022-38028, disable Print Spooler on systems that do not need it, restrict print-management rights, retain file/process coverage plus registry or library telemetry where it limited the investigation, and document the confirmed MPDW-constraints.js, ProgramData, wayzgoose, or scheduled-task pattern for future triage.

References

Related rules

to-top