Files
2026-04-27 13:34:48 +02:00

9.8 KiB
Raw Permalink Blame History

SyncProvider

The Cloud Filter API provides functionality that allows a cloud sync engine to synchronize files between a remote environment and a local client. This functionality is typically used by cloud file synchronization processes such as OneDrive, so that files hosted in the cloud can be represented and accessed from Windows Explorer.

Through this API, a sync engine (or sync provider; Microsoft seems to use both terms interchangeably) can project cloud files by creating placeholders. Placeholders are files on disk that have three states:

  • Dehydrated: This is the initial state when creating a placeholder. It means that although the file representation exists on disk, its content is not present locally and can only be obtained if the sync provider is available.
  • Hydrated: The file content is present on the local disk, so the file can be used normally. At any time, the placeholder can be dehydrated, returning to the previous state.
  • Hydrated and pinned: The placeholder content is on disk and its presence is guaranteed at all times (we do not care about this state for the activities described in this document).

The first access to the content of a dehydrated placeholder is intercepted by the CldFlt minifilter (default altitude: 180451). Before allowing the original request on the file to continue on its path, the minifilter asks the sync provider for the placeholder content so it can hydrate it. When it receives a response from the sync provider, placeholder hydration is performed by calling the FltWriteFileEx function to write the content to disk. Once the placeholder is correctly hydrated, the original request can continue on its path and complete as appropriate.

If we read the documentation for the FltWriteFileEx function, we will see that in the Remarks section it states that this function "causes a write request to be sent to the minifilter driver instances attached below the initiating instance and to the file system. The specified instance and the instances attached above it do not receive the write request". Since AV and EDR minifilters are always loaded at altitudes higher than CldFlt (altitude ranges are officially assigned and documented by Microsoft), this means that this write is invisible to endpoint protection software, which allows writing any content to disk without it being statically analyzed (if we do it correctly). Additionally, although we have described the sending of data from a sync provider as a response to a request from CldFlt, the reality is that a provider can proactively hydrate one of its placeholders at any time following the same procedure.

With all this, we have what we need to abuse Cloud Filter API functionality to write malware to disk without it being statically analyzed. Specifically, the SyncProvider project will launch a malicious provider that performs a double hydration on a placeholder to evade all malware scanning. Initially, upon receiving a hydration request, the malicious provider will return the contents of a non-malicious file, which can be scanned by the security solution without raising suspicion. After a few seconds, the provider will proactively perform a second hydration of the placeholder, this time sending the malwares contents, which will be written to disk without being analyzed. The procedure is as follows:

  1. Launch sync_provider.exe and complete the requested information.
  • Sync root directory: Directory where the malicious placeholder will be created. In this test, the path C:\Temp\Test is inserted.
  • Backing file 1: Legitimate local file. In the proof of concept documented here, C:\Windows\System32\certutil.exe will be used, although in real environments it is not recommended to use binaries resident in System32 (they can trigger other alerts for executing binaries outside their usual directory). This file must have a size greater than or equal to that of our malware, since its information will be used to create the placeholder. The content of this file will be used for the first hydration of the placeholder.
  • Backing file 2: Local or remote (SMB) path where the malware to be dropped is located (.exe file). Ideally it should be hosted remotely but, in either case, it is recommended to encrypt the file beforehand using the xor_file.py script (simple XOR; the provider will perform the decryption in memory before the second hydration). In this test, Mimikatz will be used as the binary to drop, since it is widely known malware with a signature detected by practically any endpoint protection solution. The content of this file will be used for the second hydration of the placeholder.
  • Placeholder name: Name of the placeholder to create inside sync root directory. In this test, notmimi.exe.
  • Decryption key: If Backing file 2 has been encrypted, the same encryption key used must be passed here.
  • Mode: This document only reflects the behavior of mode 2.
C:\Path\To\Puzzle\bin>sync_provider.exe
Sync root directory: C:\Temp\Test
Backing file 1 (benign file): C:\Windows\System32\certutil.exe
Backing file 2 (payload): C:\Temp\mimi_encrypted
Placeholder name: notmimi.exe
Decryption key (empty = unencrypted payload): test1234
Select mode (1 or 2): 2 # Always set it to mode 2
[+] Sync root sucessfully registered.
[+] Connection to sync root established. Connection key: 0x210aaa86060
[+] Placeholder created: C:\Temp\Test\notmimi.exe
[+] Provider status set to CF_PROVIDER_STATUS_IDLE.
  1. Once the placeholder is registered, execute it (double click, CreateProcess, whatever). The process creation routine internally ends up calling NtCreateSection, which ultimately triggers the IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION callback of all minifilters that requested it. On a device without AV/EDR, IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION from CldFlt would trigger directly, which would cause the placeholder to be hydrated before section creation. However, as shown in the video at the end of this document, on devices protected with Microsoft Defender (the minifilters of several EDRs behave exactly the same), the behavior is different, since the AV intercepts the original section creation and requests full hydration of the placeholder in order to perform a prior security analysis. Only when that analysis completes without detecting anything malicious (and leaves the placeholder already in hydrated state) is the original section creation allowed to pass and the process launched (which, in our case, will execute certutil.exe). In this first hydration, the sync provider sends the content of Backing file 1, that is, completely legitimate content, so the security solution scan does not detect anything malicious.

  2. After a few seconds (I introduce this delay to avoid corruption when launching the process), the sync provider hydrates the placeholder a second time proactively (without being asked), except that in this case the content it provides is that of Backing file 2, so the malware can be written to disk without being analyzed.

  3. On occasion (this does not happen on all systems), even after the second hydration has been performed and the content on disk is that of Backing file 2, later executions of the binary still launch Backing file 1. This is because the content is cached, so we must force the system to discard this content and use the content on disk for subsequent executions. This can be done programmatically in several ways, but we can also do it conveniently with Right Click -> Properties on the placeholder.

  4. Once the cached content has been discarded (if necessary), the next execution will launch Mimikatz without Microsoft Defender detecting it, despite executing highly recognizable malicious code. The reason it is not detected (apart from the fact that there is no visibility into the write to disk) is that the AV considers that the file has not been modified since the last scan. If we analyze the activity with Procmon, we can see that, when launching Mimikatz, the AV checks the USN Journal and the metadata of the file's corresponding MFT entry to determine whether it has been modified since the last scan. However, and for some reason I do not know, the hydration performed by CldFlt is not recorded in either of these two sources of truth as a file modification operation (conjecture: I suppose because of the use of the FLTFL_IO_OPERATION_PAGING flag when calling FltWriteFileEx, although this is only a hypothesis). Therefore, since the AV has already recently scanned the file (initial execution of Backing file 1) without finding anything malicious, has not seen any write to it because CldFlt is at a lower altitude, and no checked source of truth indicates file modification, the malware is allowed to execute without being reanalyzed.

This same behavior has also been detected in numerous EDRs. However, although the malware write goes unnoticed by all endpoint protection solutions due to what was discussed previously, some EDRs do reanalyze the binary when receiving a process creation callback regardless of whether it has been recently analyzed or not, which allows them to detect the payload at runtime. For this reason, in this type of environment it is necessary to combine this technique with the use of bindlinks described here.

  1. Once execution is finished, the registered sync provider must be removed. To do this, first dehydrate the file (pressing 1 in the tool console) and then unregister the provider (pressing 2).

POC