Although not the most common vulnerability class, it sometimes happens that a ring-0 module (or the kernel itself) references a local variable or buffer, which wasn’t previously properly initialized. The threat is usually mitigated by compiler warnings / errors, informing about potential security flaws present in the source code – as life shows, it is not always enough to avoid serious vulnerabilities of that kind. Having the knowledge about a buggy function, one might stumble upon a serious problem – how to actually make use of the information in a beneficial way (e.g. execute code in the security context of the faulty function – here, kernel-mode). The problem actually boils down to another matter – how can one control the trash bytes present on the ring-0 stack, from within a ring-3 perspective. It is primarily caused by the fact that each thread present on the Windows platform has two separate, dedicated stacks – a user- and kernel-mode one. Such security design obviously limits any possibility for an application to poke with the execution path of a highly-privileged code. Unfortunately, it also narrows down the amount of controllable data, which the user is able to (indirectly) move to the ring-0 stack… or does it? In this post, I am going to focus on my recent, minor discovery, which makes it possible to insert large amounts of arbitrary data into the stack memory areas of the current thread.
In the remaining part of the post, an assumption is made that the faulty device driver code runs in the same thread context as the code that actually triggers the vulnerability.