I’m starting a new series of blogs called “Yarden documents random Windows things” (I am open to alternative name suggestions) where I’ll write about some features and changes in Windows that knowledge of exists only in the communal brain of security researchers, in a footnote in a blog about a different topic, or in a vague screenshot on Twitter.
I don’t claim any of the research shown in this series is novel or done by me, and I will credit other people whenever I can. This series only exists to have a place I can point to for documentation of niche topics. If you published anything, or know of anyone who did, about these topics, please let me know and I’ll happily link it here and credit you.
The first topic of the series is: killing the PreviousMode overwrite exploitation technique.
This exploitation technique, that worked in all past Windows versions until Microsoft killed it in Windows 11 23H2, included overwriting a KTHREAD‘s PreviousMode field to set it from user to kernel mode. When a thread is running with PreviousMode == KernelMode, the system will skip all security and access checks, since it assumes the call came from a driver. So, an arbitrary kernel write could turn into a full LPE, bypassing all Windows security restrictions.
The mitigation for this was first spotted by Gabriel Landau and is mentioned in his blog post about PPLFault, which used the technique to achieve LPE and terminate a Protected Process Light. It was also demonstrated in this blog post but the technical details of it were not fully explained.
The mitigation blocks this exploitation technique in two ways:
When a thread enters the kernel through a system call,
KiSystemCall64sets the thread’sPreviousModetoUserMode. This way, if the thread’sPreviousModewas corrupted by an exploit or arbitrary memory corruption, it is corrected back to the right value:
Before returning to user mode,
KiSystemCall64checks if the thread’sPreviousModeis set toUserMode. If it is not (likely because it was corrupted through a kernel vulnerability), the system will crash with bugcheck codePREVIOUS_MODE_MISMATCH(0x1F9).
That’s it. Very simple but very effective mitigation. To bypass it, an attacker would need to corrupt the PreviousMode of a thread that is already in kernel mode, perform any privileged actions through that thread, then set its PreviousMode back to UserMode before it returns to user space. Not an impossible bypass to achieve but definitely complicates things compared to the original technique.
