Saturday, April 6, 2019

Circumventing Windows Defender ATP's user-mode APC Injection sensor from Kernel-mode

In this blogpost, I will share a simple technique to circumvent the check that was introduced in Windows 10 build 1809 to detect user-mode APC injection. This technique will only allow us to "bypass" the sensor when we're running code from kernel-mode, i.e., queuing a user-mode APC to a remote thread from user-mode will still be logged. For more information about this new feature, please check out my previous blogpost.

In short, the sensor will log any user-mode APCs queued to a remote thread, be it from user-mode or kernel-mode. The most important check is implemented in the kernel function : EtwTiLogQueueApcThread as shown below.

(Click to zoom)

So queuing a user-mode APC to a thread in a process other than ours is considered suspicious and will be logged. However, when having code execution in kernel-mode we can queue a kernel-mode APC that will run in the context of the target process and from there we can queue a user-mode APC. This way, the check when KeInsertQueueApc is called from the kernel-mode APC will always yield (UserApc->Thread->Process  == CurrentThread->Process).

I have written a simple driver to test this out : https://github.com/SouhailHammou/Drivers/tree/master/Apc-Injection-ATP-Bypass
  • The driver registers a CreateThreadNotifyRoutine in its DriverEntry.
  • CreateThreadNotifyRoutine queues a kernel-mode APC to a newly created thread.
  • The kernel-mode APC is delivered as soon as the IRQL drops below APC_LEVEL in the target thread in which we allocate executable memory in user-space, copy the shellcode, then queue the user-mode APC.
  • The user-mode APC is delivered in user-mode.
The only issue here is that Windows Defender's ATP will still log the allocation of executable memory thanks to another sensor.

Thanks for your time :)
Follow me on Twitter : here