I was studying a Windows Server 2012 R2 host that is compromised with a IIS SEO Campaign malware.
Using Process Monitor I noticed it injects the malicious DLL when it loads a rightful one. All DLLs down to, and including this one, have matching md5sums with another Windows Server 2012 R2 that's not infected by this virus.
Something particular at this point is that the rightful DLL responds to a CreateFile operation with REPARSE.
This suggests a Reparse Point is set to the victim DLL, which then leads to load the malicious file.
The problem is that I can query the file with windows properties dialog to see it's authentic and signed, tools like md5sum to get some checksum to compare elsewhere, and even copy over the file, say, to file2.dll to get the rightful file handle and contents.
The only time it seems I get it to redirect to the malicious file is when a program tries to load it.
Here's the output I get from ProcMon when I load the infected file:
2:53:54.2321174 PM w3wp.exe 4876 CreateFile C:\Windows\System32\inetsrv\custerr.dll REPARSE Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Superseded
2:53:54.2344554 PM w3wp.exe 4876 CreateFile C:\Windows\Vss\Logs\WsmRes64.dll SUCCESS Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened
2:53:54.2353130 PM w3wp.exe 4876 CreateFile C:\Windows\System32\inetsrv\custerr.dll REPARSE Desired Access: Read Data/List Directory, Execute/Traverse, Synchronize, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: n/a, ShareMode: Read, Delete, AllocationSize: n/a, OpenResult: Superseded
2:53:54.2354092 PM w3wp.exe 4876 CreateFile C:\Windows\Vss\Logs\WsmRes64.dll ACCESS DENIED Desired Access: Read Data/List Directory, Execute/Traverse, Synchronize, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: n/a, ShareMode: Read, Delete, AllocationSize: n/a
Notice the last entry is ACCESS DENIED because at that point I already corrupted the malicious DLL trying to get it out of that Shadow Copy directory. Before it was inaccessible, it naturally went down to the Load Image step and carried on its, well, activities.
Compare with the load if I just shamelessly copy over the very same custerr.dll file into custerr2.dll, and instruct IIS to use this DLL:
12:51:54.2194050 PM w3wp.exe 6804 CreateFile C:\Windows\System32\inetsrv\custerr2.dll SUCCESS Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened
12:51:54.2196814 PM w3wp.exe 6804 CreateFile C:\Windows\System32\inetsrv\custerr2.dll SUCCESS Desired Access: Read Data/List Directory, Execute/Traverse, Synchronize, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: n/a, ShareMode: Read, Delete, AllocationSize: n/a, OpenResult: Opened
12:51:54.2200149 PM w3wp.exe 6804 CreateFile C:\Windows\System32\inetsrv\custerr2.dll SUCCESS Desired Access: Generic Read, Disposition: Open, Options: Write Through, Synchronous IO Non-Alert, Random Access, Attributes: SN, ShareMode: Read, AllocationSize: n/a, OpenResult: Opened
12:51:54.2202689 PM w3wp.exe 6804 CreateFile C:\Windows\System32\inetsrv\custerr2.dll SUCCESS Desired Access: Generic Read, Disposition: Open, Options: Write Through, Synchronous IO Non-Alert, Random Access, Attributes: SN, ShareMode: Read, AllocationSize: n/a, OpenResult: Opened
12:51:54.2205066 PM w3wp.exe 6804 Load Image C:\Windows\System32\inetsrv\custerr2.dll SUCCESS Image Base: 0x7fff248a0000, Image Size: 0x10000
No reparse response and no substitution takes place at all.
For being able to load it everywhere else does it mean only IIS uses createFile to load the modules? Or is there means to construct reparse rules to trigger only when the file is opened, say, by a given executable? Ultimately, how do I query these rules (and maybe remove t hem). Wherever I see about reparse rules or junction tool, it's about symbolic links and this looks a bit more elaborate than just a link.
Edit
Further bit of research I found fsutil that could query reparse points, and what I got is:
$ fsutil reparsepoint query custerr.dll
Error: The file or directory is not a reparse point.
But it definitively returned with REPARSE from CreateFile. Maybe there's different reparse semantics between fsutil and fileapi's REPARSE, or maybe the information from Process Monitor makes me think this is a symlink-ish reparse concept but there's something else?