This is going to be a relatively short post which won’t contain much code in itself but rather some observations I made on the state of existing security and logging utilities, with Sysmon’s handling of usermode modules being the case study.
Recently, a lot of people realized that Sysmon’s stack trace feature is quite useful for detecting code execution from non-module memory. This feature is indeed very nice and can detect most existing attacks which rely on code injection or manual mapping, however the implementation is significantly flawed. 0x00dtm rightly pointed out this out, which resulted in anyone being able to tamper with the PEB and feed false data to Sysmon.
This issue is not isolated, it is the norm. A significant amount of existing EDRs and monitoring tools rely on information that is fully controllable by the threats they’re supposed to stop. From usermode hooking to relying on the PEB for information about a process, the assumption that usermode data is safe for consumption is ubiquitous. Does this not clearly create a giant gap where an attacker can manipulate the information that EDRs and SIEMs depend on to provide context to defenders, giving them the ability to deceive defenders and security solutions?
Given this example of Sysmon relying on PEB to find out where calls are coming from and the problem with it, what is the right way to do things that doesn’t rely on information controllable by the attacker? Why, APIs provided by the Windows Kernel for this very purpose, of course. Calling ZwQueryVirtualMemory with MemoryMappedFilenameInformation will get you the module a memory address belongs to (if any) in a reliable manner.
Here’s a bit of in-depth details which hopefully explains why this method is more reliable than reading PEB. The VAD tree structure describes the virtual address space of a process. VAD (Virtual Address Descriptor) entries have a _CONTROL_AREA structure, which contains the field FilePointer of type _FILE_OBJECT. This field is set whenever Windows map a file to a process’s virtual memory, and points to a descriptor for the file that was mapped. And, where does this all get stored? In the kernel address space. What does this mean? That means this information is out of reach for an attacker sitting in usermode, who has no way to mess with the VAD the way they could freely modify the PEB.
Given this, a question must be asked. Why are people still making the assumption that we can trust the integrity of usermode data, which is fully controllable by any attacker who has achieved code execution?
On a bit of a tangent, even were ZwQueryVirtualMemory used, it is still possible to mess with the calltrace through stack manipulation (though this requires significantly more effort and has more constraints compared to the previous method). I’m not going to go into details into this right now, maybe I’ll share my PoC and further information in another post.
Of course, relying on information from the kernel alone and blindly isn’t a silver bullet to stop all the manipulations that can happen. Window’s handling of file renames as an example is notoriously problematic and causes significant visibility gaps for monitoring/security solutions. Regardless, the point is clear: trusting usermode data, even when sanitized somewhat, is a terrible terrible idea. Usermode data should only be used when no reliable alternatives are available – lest it be used to deceive the very defenders it is supposed to inform.