herpaderping: Process Herpaderping bypasses security products
Process Herpaderping is a method of obscuring the intentions of a process by modifying the content on disk after the image has been mapped. This results in curious behavior by security products and the OS itself.
Background and Motivation
When designing products for securing Windows platforms, many engineers in this field (myself included) have fallen on preconceived notions with respect to how the OS will handle data. In this scenario, some might expect the file on disk to remain “locked” when the process is created. You can’t delete the file. You can’t write to it. But you can rename it. Seen here, under the right conditions, you can in fact write to it. Remain vigilant on your assumptions, always question them, and do your research.
The motivation for this research came about when discovering how to do analysis when a file is written. With prior background researching the process of Hollowing and Doppelganging, I had theorized this might be possible. The goal is to provide better security. You cannot create a better lock without first understanding how to break the old one.
Herpaderping is similar to Hollowing and Doppelganging however there are some key differences:
Process Hollowing involves modifying the mapped section before execution begins, which abstractly this looks like: map -> modify section -> execute. This workflow results in the intended execution flow of the Hollowed process diverging into unintended code. Doppelganging might be considered a form of Hollowing. However, Hollowing, in my opinion, is closer to injection in that Hollowing usually involves an explicit write to the already mapped code. This differs from Herpaderping where there are no modified sections.
Process Doppelganging is closer to Herpaderping. Doppelganging abuses transacted file operations and generally involves these steps: transact -> write -> map -> rollback -> execute. In this workflow, the OS will create the image section and account for transactions, so the cached image section ends up being what you wrote to the transaction. The OS has patched this technique. Well, they patched the crash it caused. Maybe they consider this a “legal” use of a transaction. Thankfully, Windows Defender does catch the Doppelganging technique. Doppelganging differs from Herpaderping in that Herpaderping does not rely on transacted file operations. And Defender doesn’t catch Herpaderping.
For reference, the generalized techniques:
|Hollowing||map -> modify section -> execute|
|Doppelganging||transact -> write -> map -> rollback -> execute|
|Herpaderping||write -> map -> modify -> execute -> close|
We can see the differences laid out here. While Herpaderping is arguably noisier than Doppelganging, in that the malicious bits do hit the disk, we’ve seen that security products are still incapable of detecting Herpaderping.
There is not a clear fix here. It seems reasonable that preventing an image section from being mapped/cached when there is write access to the file should close the hole. However, that may or may not be a practical solution.
Another option might be to flush the changes to the file through to the cached image section if it hasn’t yet been mapped into a process. However, since the map into the new process occurs at NtCreateProcess that is probably not a viable solution.
From a detection standpoint, there is not a great way to identify the actual bits that got mapped, inspection at IRP_MJ_CLEANUP or a callback registered at PsSetCreateProcessNotifyRoutineEx results in incorrect attribution since the bits on disk have been changed, you would have to rebuild the file from the section that got created. It’s worth pointing out here there is a new callback in Windows 10 you may register for PsSetCreateProcessNotifyRoutineEx2 however this suffers from the same problem as the previous callback, it’s called out when the initial thread is executed, not when the process object is created. Microsoft did add PsSetCreateThreadNotifyRoutineEx which is called out when the initial thread is inserted if registered with PsCreateThreadNotifyNonSystem, opposed to when it is about to begin execution (as the old callback did). Extending PSCREATEPROCESSNOTIFYTYPE to be called out when the process object is created won’t help either, we’ve seen in the Diving Deeper section that the image section object is cached on the NtCreateSection call notNtCreateProcess.
We can’t easily identify what got executed. We’re left with trying to detect the exploitive behavior by the actor, I’ll leave the discovery of the behavior indicators as an exercise for the reader.
Copyright (c) 2020 Johnny Shaw