
CVE-2026-97798 Windows Error Reporting - Command Injection TO SYSTEM
[!WARNING] This repository is for authorized vulnerability research and controlled lab validation. The proof of concept fails closed when it cannot identify exactly one compatible
faultrep.dll!SpawnDataCollectorimplementation.
CVE-2026-97798 is a local elevation-of-privilege vulnerability in the Windows
Error Reporting (WER) Time Travel Debugging path. An unprivileged caller can
preserve attacker-controlled command-line syntax across the WER privilege
boundary. The elevated collector later concatenates that input into a
TTTracer.exe command line without preserving argument boundaries. Injected
-out and -launch switches are therefore interpreted by the TTD recorder as
recorder options, allowing an attacker-selected executable to be launched with
the collector's elevated token.
The included single-file PoC turns that primitive into an interactive
NT AUTHORITY\SYSTEM shell. It has been validated from both a standard user
and a medium-integrity, UAC-filtered administrator account.

| Path | Description |
|---|---|
src/CVE-2026-97798.cpp | Complete single-image exploit source |
bin/CVE-2026-97798.exe | Reproducible x64 laboratory build |
build.ps1 | Deterministic LLVM-MinGW build script |
assets/system-shell.png | Captured whoami proof from the isolated VM |
No report PDFs are included yet; the long-form paper is still being edited.
The vulnerable flow crosses several components:
low/medium-integrity process
-> faultrep.dll!CElevatedDataCollection::ControlTimeTravelDebugging
-> faultrep.dll!SpawnDataCollector
-> Windows Error Reporting service (elevated collector)
-> CDataCollection::ControlTimeTravelDebugging
-> TtdControl::LaunchRecordingProcess
-> TTTracer.exe / TTDRecord.dll command-line parser
-> attacker-controlled -launch target
The request contains a Process value that begins with a legitimate executable
but appends additional TTD switches. The vulnerable implementation applies a
weak exact-name blocklist and later formats the process string directly into the
privileged recorder command line. Because the process value is not serialized
as one argument, its spaces become argument delimiters when TTTracer parses the
result.
Conceptually, the injected portion is:
Process=CVE-2026-97798-payload.exe
-out ..\..\Users\Public\Documents\CVE97798\trace
-launch ..\..\Users\Public\Documents\CVE97798\CVE-2026-97798-payload.exe
--payload;
The relative paths are deliberate. WER also incorporates this data into a
.ttdconfig pathname; an absolute drive prefix introduces a colon and fails
with ERROR_INVALID_NAME. The traversal-style path avoids that parser conflict
while normalizing to the controlled public directory.
This is an argument-injection issue (CWE-88), not a conventional shell-command
injection. No cmd.exe /c is required at the vulnerable sink: TTTracer itself
interprets the injected switches.
Normal use requires only CVE-2026-97798.exe. The same PE image re-enters
itself in several internal modes:
faultrep.dll!SpawnDataCollector dynamically from the unique function that
contains the WER collector opcode and protocol invariants. No build-specific
RVA is embedded.cmd.exe through named pipes, allowing a visible
user-session console to interact with a shell created in session 0.The distributed artifact remains one EXE. At runtime it stages two aliases of
that same image: one for the integrated console and one for the elevated
payload. The payload alias is also used as TTTracer's -onlaunch target, so the
recorder observes the process it actually launches and exits when that short
payload stage ends. The PoC resets stale TTD state before each trigger and again
after a successful payload, preventing an interrupted run from making the next
execution fail with HRESULT 0x80070032.
For a standard user, the elevated collector path reaches SYSTEM directly. For a
UAC-filtered administrator, WER first launches the payload with the linked high
administrator token—the account name remains unchanged, but
TokenIsElevated=true. The PoC then re-enters the same image as SYSTEM. It tries
direct SYSTEM-token process creation first and uses a short-lived Task Scheduler
entry as a fallback; the fallback task is deleted immediately after launch.
| Component | Validated value |
|---|---|
| OS | Windows 11 24H2 x64, build 26100.9550 |
Vulnerable faultrep.dll | 10.0.26100.9549 |
| Fixed comparison | faultrep.dll 10.0.26100.9711 |
| TTTracer / TTDRecord | 1.11.580.0 |
| Dynamic resolver check | 9549: RVA 0x4CEB0; 9711: RVA 0x4E40C |
| PoC SHA-256 | C7B8FAFB132D69E9BD5A398AE183107155129C7080A87D56EFE55572450B4147 |
The resolver walks the x64 exception table and requires one function with the
collector's large-frame setup, request opcode 0xD0000002, message size
0x578, wait timeout 10000, and its three expected wait/service error
mappings. It was checked against both supplied faultrep.dll builds and
negative-tested against unrelated PE images. No build number or RVA is stored.
If a future build changes that implementation enough to make the match
ambiguous or incomplete, the PoC stops before making an indirect call.
Use a disposable snapshot of the vulnerable build. From a non-elevated PowerShell or Command Prompt:
.\bin\CVE-2026-97798.exe
On success, the integrated console prints:
[CVE-2026-97798] Exploit shell token:
nt authority\system
The machine-readable proof is written beneath:
C:\Users\Public\Documents\CVE97798\system-proof.txt
The resolver can also be tested against an offline x64 DLL without triggering the vulnerability:
.\bin\CVE-2026-97798.exe --resolve C:\path\to\faultrep.dll
To preflight the installed system DLL, also without triggering the vulnerable path:
.\bin\CVE-2026-97798.exe --preflight
A successful filtered-administrator validation produced:
cve=CVE-2026-97798
user=NT AUTHORITY\SYSTEM
is_system=true
is_elevated=true
payload_session=0
shell_session=0
spawn_error=0
Install an x64 LLVM-MinGW
toolchain and place x86_64-w64-mingw32-clang++.exe in PATH, or pass its
absolute path explicitly:
.\build.ps1
# or
.\build.ps1 -Compiler C:\toolchains\llvm-mingw\bin\x86_64-w64-mingw32-clang++.exe
The build is static and suppresses the PE linker timestamp, so identical source and toolchain inputs produce the same executable hash.
Close the PoC console first. From an elevated laboratory console, if TTD state remains active:
Stop-Process -Name TTTracer,TTDInject -Force -ErrorAction SilentlyContinue
C:\Windows\System32\TTTracer.exe -cleanup
Remove-Item -Recurse -Force C:\Users\Public\Documents\CVE97798
Reverting the disposable VM snapshot is the preferred final cleanup.