Intro
Today we are looking into patch diffing a reported Elevation of Privilege (EoP) vulnerability reported within the Windows Partition Management Driver
(partmgr.sys). Maybe this information can be helpful for others who are going through all the Patch Tuesday reports and if you are already experienced with GPT disks you will have a much easier time than me as I am still trying to figure it all out.
Tools
- BinDiff - https://www.zynamics.com/bindiff.html
- Ghidra - https://ghidra-sre.org/
- Binary Ninja - https://binary.ninja/
- BinExport - https://github.com/google/binexport
- WinBinDex - https://winbindex.m417z.com/
File Information
- Windows Version: 11 22h2
- Patched Version: 10.0.22621.1413
- Non-Patched Version: 10.0.22621.900
- Binaries: https://winbindex.m417z.com/?file=partmgr.sys
Diffing
So, when patch diffing the first task that we want to complete is that of identifying the associated files related to the CVE that we are reviewing. Luckily in our case, given the information MSFT provides along with the CVE we are able to easily determine that the kernel driver responsible for Partition Management is partmgr.sys
.
You will have to utilize either Ghidra, Binary Ninja, or IDA along with the extension BinExport. Note that Binary Ninja recently updated their version so BinExport no longer works unless you use an older version of Binary Ninja. Similarly with Ghidra, you will want to download Ghidra 10.2.2 to be able to import the BinExport extension.
You will then utilize the BinExport extension, and utilize BinDiff to analyze both the Non-Patched and Patched Binaries. If we look into some of the data gathered from BinDiff we will be able to identify that only a single function appears to have been modified within the partmgr.sys kernel driver, as seen in this image.
Looking at this graph view of the function, we easily identify that in the patched version, it appears more checks are implemented that lead to an early return from the function at the start of the function. In my mind, this seems quite interesting because early returns and more checks normally mean that they are trying to perform sanity verification checks; however, to verify what is happening we need to actually review the modifications. ( Note, lots of changes within this function were performed beyond just at the start but for this post we are just looking at the start. )
Interesting, we have two additional sanity checks, the first one is comparing ECX <= EDX
where EDX
is static value assigned earlier 0x80
. If ECX
is > than 0x80
then another sanity check is performed to make sure that ECX < 0x400
and if it is not then the function exits early.
Now, this is interesting but we need to look into what ECX
is utilized with and why they are checking to make sure that it is less than 0x400
. So, now I will cheat and utilize Binary Ninja (can’t afford the mighty IDA Pro haha) and review some pseudo code.
So, now it is much easier to review this function and we even have some light type information from MSFT PDB (Auto loaded with Binary Ninja), we know the function name is SC_GPT::WritePartitionTable
and it takes 3 arguments:
- SC_GPT* this
- class SC_DISK_LAYOUT* __ptr64 arg2
- uint8_t arg3
Maybe others know what is at SC_DISK_LAYOUT+0x28
as at this time I don’t; however, I think it could be related to the total amount of Partition Entries
within the GPT Partition table? I am not sure, maybe others know. We can see that shortly after the size check on RCX/RAX_34
we see some arithmetic that is used to determine further size variables that are utilized with the rest of the function.
So in my mind this is a arithmetic issue due to RCX/RAX_34/SC_DISK_LAYOUT+0x28
possibly being much larger than they interpreted leading to possibly integer wrapping.
If anyone has some insight into where I can learn more about the structure and layout of GPT Tables entries or these SC_DISK_LAYOUT
structure I would greatly appreciate help! Hope you all have an awesome weekend.