7.9 KiB
BindLinks
As already mentioned in the SyncProvider project README, using a cloud sync provider allows us to write malware to disk without it being statically analyzed during that write, but this does not prevent certain EDRs from reanalyzing the binary when they receive a process creation callback. To evade this second analysis, we will use the BindLinks solution, which allows us to manage the creation of bindlinks. The people at Bitdefender recently published a great research on how bindlinks work and how we can abuse them in different scenarios, so if you want to know more about this technology, I strongly recommend reading that research.
To avoid going on too long, broadly speaking a bindlink is an access-time redirection from a fileA (known by the term virtual path) to a fileB (or backing path), so that every access to the former always ends up transparently accessing the latter. This redirection is performed by the bindflt minifilter (default altitude: 409800), which means that once the bindlink has been established, every access by path to fileA will end up accessing the content and information of fileB. Again, for more information about the internal behavior of bindflt, I recommend reading Bitdefender's research.
Therefore, the idea is to use this redirection provided by bindlinks so that, when the EDR receives a process/section creation notification and tries to access our payload to analyze it (which we will have dropped using the sync provider technique discussed here), instead of accessing the content of our malware and thanks to the bindlink, it accesses the content of a legitimate, non-malicious backing path, thereby avoiding analysis of the payload that is actually being executed.
On paper this looks simple and well on track, although someone has probably already noticed the problem: how are we going to launch or access the content of our malware if the bindlink redirection also affects us? In other words, once the link has been established, if we try to perform a CreateProcess on fileA (or, as we will see below, try to map the PE into our current process through a new section), what will actually end up being accessed is fileB. Therefore, we prevent the EDR from scanning the payload but also prevent the payload from executing, which is clearly a problem!
To solve this, we need a mechanism that allows us to access the content of the malware without using its path (since accessing by path will always trigger the bindlink redirection). We can achieve this by accessing the malware through its FRN (File Reference Number), which Microsoft sometimes also refers to as "file ID". The FRN is a unique identifier assigned to each MFT entry in an NTFS file system, formed by combining the record number and the sequence number. In other words: the FRN is a unique identifier that allows accessing any file without using its path. In fact, on Windows this access by FRN can be performed using NtCreateFile with the FILE_OPEN_BY_FILE_ID flag or, more conveniently, OpenFileById. When accessing by FRN, the bindlink does not apply and the redirection is not performed, which allows us to open a handle to the malware previously dropped.
Once we have opened a handle to the payload, we have two options to execute its code: launch it in a separate process using NtCreateProcessEx (this legacy API has been used by code injection techniques in the past and currently generates alerts with certain EDRs; see this Microsoft post to find out why) or map the PE into the current process, managing the mapping manually and jumping to the entry point (this method does not generate alerts but has its own limitations/issues that the loader we use has to manage; even so, it is the most reliable method from a stealth point of view). Both options are implemented in the IdMapper project.
All in all, this would be the procedure for executing our payload:
-
Write it to disk following the procedure described in the SyncProvider documentation.
-
Obtain the malware FRN using the
fsutilutility or the functionality implemented in theUtilsproject present in this repository (it will return a 32-byte hexadecimal number):
C:\Path\To\Puzzle\bin> fsutil file queryfileid C:\Path\To\Payload.exe
C:\Path\To\Puzzle\bin> utils.exe query C:\Path\To\Payload.exe
- Create a
bindlinkfrom the malware to a legitimate system binary:
C:\Path\To\Puzzle\bin> bindlinks.exe create C:\Path\To\Payload.exe C:\Windows\System32\lsass.exe
- Execute the payload using
IdMapper, either in a new process or by loading it in the current process (sinceIdMapperis only a proof of concept, it has its limitations and may fail when executing certain binaries, both when launching them in a separate process and in the current process):
C:\Path\To\Puzzle\bin> id_mapper.exe
Select mode (spawn/load): spawn (set this to "load" to map the PE in the current process)
Select volume (e.g. 'C'): C
Insert FRN: 0x000300000019fa17
[+] Successfully opened handle to file by FRN '0x300000019fa17' on volume '\\.\C:'.
[+] File section mapped into current process. Base address: 0x7ff7d53f0000.
[+] Process created from section. Handle: 0x114.
[+] New process PEB address obtained: 0x3dbbed8000
[+] Remote process image base address: 0x7ff7d53f0000
[+] New environment block created. Size: 6734 bytes.
[+] RtlUserProcessParameters structure populated. Size: 1744 bytes.
[+] New environment block successfully written to the remote process. Address: 0x2134dda0000
[+] RtlUserProcessParameters structure written to the remote process. Address: 0x2134ddb0000
[+] New process' PEB patched.
[+] Initial thread launched.
In this way, if we analyze the EDR/AV activity with Procmon during malware launch, we will see that the analysis is performed on the backing path (in this case, C:\Windows\System32\lsass.exe) instead of on our payload. This is because, apparently, even though we access the malware using the FRN, the EDR accesses it through the binary path, so the bindlink redirection comes into play and the file that is actually being executed is not analyzed.
- Once the proof of concept is finished, it is recommended to remove the
bindlinkto restore the system:
C:\Path\To\Puzzle\bin> bindlinks.exe remove C:\Path\To\Payload.exe
In addition to the use described in this document, the truth is that bindlinks can be useful to evade other control and security mechanisms. For example, we can do something like this:
C:\Path\To\Puzzle\bin> bindlinks.exe create C:\Windows\System32\cmd.exe C:\Path\To\Payload.exe
C:\Path\To\Puzzle\bin> C:\Windows\System32\cmd.exe
C:\Path\To\Puzzle\bin> bindlinks.exe remove C:\Windows\System32\cmd.exe
Under the hood, and thanks to the bindlink redirection, this will create a C:\Windows\System32\cmd.exe process as a container, although the code actually executed will be that of C:\Path\To\Payload.exe (this is not just a user-space illusion; if we inspect the process EPROCESS in the kernel, we will see that the ImageFileName field indicates cmd.exe, and if we inspect SeAuditProcessCreationInfo, we will see that the ImageFileName field indicates the path \Device\HarddiskVolumeX\Windows\System32\cmd.exe). This effectively allows evading security controls such as obtaining a Chromium browser's ABE key without needing to inject code into another process (we use the path of a Chromium browser installed on the machine as the backing path) or firewall filtering based on the process, among others.
