
Image: Hasherezade
Process injection is a technique frequently employed by attackers, with its variations appearing in numerous malware. This technique is used for various malicious purposes, including defense evasion, interference with existing processes, and privilege escalation.
Check Point’s latest research reveals a novel and quiet method for executing code in remote processes—Waiting Thread Hijacking (WTH)—a stealthier evolution of classic thread execution hijacking that sidesteps most modern Endpoint Detection and Response (EDR) systems.
Classic thread hijacking involves suspending a thread, modifying its context, and resuming it to execute malicious code. However, this method has several drawbacks:
- It requires using APIs like SuspendThread/ResumeThread and a thread handle with THREAD_SUSPEND_RESUME access, which are often flagged as suspicious.
- It relies on SetThreadContext (or NtSetContextThread) to redirect the thread’s execution, which is also a noisy operation.
- It necessitates storing and restoring the original thread context, which can introduce instability.
Waiting Thread Hijacking aims to overcome these limitations by using a different approach. Instead of manually suspending and resuming threads, WTH targets threads that are already in a waiting state, such as those in Thread Pools. These threads automatically reactivate upon the awaited event, eliminating the need for suspicious SuspendThread/ResumeThread API calls.
Furthermore, WTH avoids directly manipulating the instruction pointer with SetThreadContext. Instead, it leverages the fact that waiting threads are often waiting on a syscall within an NTDLL wrapper, where the return address is conveniently located on the stack. By overwriting this return address, attackers can redirect the execution flow to their malicious code.
Key Advantages of Waiting Thread Hijacking
- Stealthier execution: WTH avoids using APIs that trigger EDR alerts, such as SuspendThread/ResumeThread and SetThreadContext.
- Reduced risk of instability: By targeting waiting threads and restoring the original execution flow, WTH minimizes the risk of crashing the target application.
- Circumvention of defenses: WTH can bypass restrictions like Dynamic Code Prohibited (DCP), as these policies may not apply to executable memory allocated externally.
WTH involves several steps:
- Identifying suitable threads: The NtQuerySystemInformation API is used to enumerate threads and identify those in a waiting state (e.g., waiting on a KQUEUE object with the WrQueue wait reason).
- Writing the shellcode: The malicious shellcode is written into the target process’s memory using VirtualAllocEx and WriteProcessMemory.
- Overwriting the return address: The return address of a waiting thread is overwritten with the address of the shellcode.
- Restoring execution flow: A stub is used to save and restore the original thread’s context, ensuring a seamless return to the original execution flow after the shellcode finishes.
The researchers emphasize, “This approach allows to avoid the common triggers and achieve the code execution,” making it remarkably evasive.
The complete Proof-of-Concept (PoC) code is available here.
Waiting Thread Hijacking presents a stealthier and more robust approach to code injection, posing a significant challenge to existing security solutions.