NT OS Kernel Information Disclosure Vulnerability – CVE-2025-53136

NT OS Kernel Information Disclosure Vulnerability – CVE-2025-53136

Reading Time: 4 minutes

Introduction

Microsoft mitigated many traditional kernel information leaks starting with Windows 11/Windows Server 2022 24H2, including calls such as NtQuerySystemInformation() (when used with the SystemModuleInformation class), by suppressing kernel base addresses unless the caller had the SeDebugPrivilege, typically reserved for administrative processes. That change effectively neutered one of the most accessible KASLR bypass techniques, and, without knowledge of the kernel’s base addresses, exploitation became harder.

While doing patch analysis for CVE-2024-43511, I realised that Microsoft made a mistake leading to a kernel address leak vulnerability. This new bug requires winning a race condition to read out the address; however, it’s pretty easy to achieve. It provides a powerful kernel address leak for any token handle, which can be easily chained with other vulnerabilities to obtain a complete exploit on the latest version of the system.

Vulnerability

Quick review on the patch for CVE-2024-43511

In October 2024, Microsoft released a patch for a Time-of-check Time-of-use (TOCTOU) Race Condition vulnerability in the Windows kernel, namely CVE-2024-43511.

To fix the issue, when passing parameters to the RtlSidHashInitialize() function, it reads data from a kernel pointer (which is a member of the TOKEN structure), instead of the value set in a user-controlled buffer.

Spotting the bug

With the new update, the RtlSidHashInitialize() function, which performs hash initialisation, now takes as its first parameter a pointer from the TOKEN structure and as its third parameter a user-controlled buffer. Then, RtlSidHashInitialize() stores the first parameter (which is a pointer to the UserAndGroups field of the TOKEN structure) into the third parameter (user-supplied pointer), and starts doing hash initialisation later on:

Although the caller function will replace the stored pointer in the user-buffer pointer after that, it still leaves a small time window for us to win a race condition and read out the leaked kernel address. To trigger the vulnerable function, we only need to invoke the NtQuerySystemInformation() API with the SystemTokenInformation class.

Effects of the bug

This leak primitive is particularly useful for Windows versions 24H2 or later, as the well-known technique for leaking kernel addresses using NtQuerySystemInformation() or other alternative methods has been patched. As the vulnerability is located within an NT syscall, the bug can be exploited from either Low IL or AppContainer. If chained with a write-what-where bug to overwrite the Privileges field of the TOKEN object, it will result in a complete LPE.

Exploitation

Setup

To exploit this bug, I need to create two threads to run concurrently:

  • One thread to read at the specific offset, which will be used to store the kernel address in the user buffer.
  • One thread performs the syscall. It is required to run the syscall several times before archiving the kernel leak.

Reliability

Although this is a race condition bug, the time window is wide enough to read the kernel address from the user-space buffer. To increase the success rate, we repeatedly call NtQuerySystemInformation() while keeping reading until we get the leak. The read becomes very reliable, and we can obtain the leaked TOKEN almost every time we run the exploit.

Proof-of-concepts

The results below show the exploit on a Windows Insider Preview in April 2025 (latest version at the time of writing), running the exploit from the Low IL and App Container contexts:

Conclusion

Patch analysis is one of the fastest ways to improve our skills and sharpen our mindset in bug finding. Additionally, it also helps us improve our secure coding skills. Sometimes, bug fixes in a function can introduce new bugs in other parts of the code. When conducting vulnerability research, it’s recommended to take a deep look to understand how the bug was patched and whether the patch completely resolves the issue or leaves other gaps open. From a developer’s point of view, every change made to a function can affect others as well, so take extra care when making any changes to the codebase. It is essential to thoroughly understand how a function works before modifying it, as this helps avoid mistakes or misuse of the function.

Disclosure Timeline

  • April 8th: Reported to vendor.
  • April 9th: Microsoft acknowledged that it is working on the bug.
  • April 22nd: They claimed that the bug is duplicated with a bug which had been fixed already, and closed the case without having any other chance to explain the bug… (I don’t know why).
  • April 22nd: I made a tweet on X to complain about that, and luckily, I got a response from them.
  • April 25th: Confirmed my report is a valid bug:v
  • April 29th: Microsoft replied that the bug was in scope.
  • August 1stCVE-2025-53136 was assigned.

 

Share this post