-
Notifications
You must be signed in to change notification settings - Fork 84
Add CVE-2024-49138 #42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,361 @@ | ||||||||
| # CVE-2024-49138: Windows Common Log File System Driver Elevation of Privilege Vulnerability | ||||||||
| *Ong How Chong (STAR Labs SG Pte. Ltd.)* | ||||||||
|
|
||||||||
| ## The Basics | ||||||||
|
|
||||||||
| **Disclosure or Patch Date:** December 10, 2024 | ||||||||
|
|
||||||||
| **Product:** Windows | ||||||||
|
|
||||||||
| **Advisory:** https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-49138 | ||||||||
|
|
||||||||
| **Affected Versions:** Before security updates of December 10, 2024, for Windows 10, 11 and Windows Server 2008, 2012, 2016, 2019, 2022, 2025 | ||||||||
|
|
||||||||
| **First Patched Version:** Security updates of December 10, 2024, for CVE-2024-49138 | ||||||||
|
|
||||||||
| **Issue/Bug Report:** N/A | ||||||||
|
|
||||||||
| **Patch CL:** N/A | ||||||||
|
|
||||||||
| **Bug-Introducing CL:** N/A | ||||||||
|
|
||||||||
| **Reporter(s):** Advanced Research Team with CrowdStrike | ||||||||
|
|
||||||||
| ## The Code | ||||||||
|
|
||||||||
| **Proof-of-concept:** https://github.com/MrAle98/CVE-2024-49138-POC | ||||||||
|
|
||||||||
| **Exploit sample:** See PoC | ||||||||
|
|
||||||||
| **Did you have access to the exploit sample when doing the analysis?** Yes | ||||||||
|
|
||||||||
| ## The Vulnerability | ||||||||
|
|
||||||||
| **Bug class:** Untrusted Pointer Dereference (CWE-822) | ||||||||
|
|
||||||||
| **Vulnerability details:** CVE-2024-49138 is a logical vulnerability within the Windows Common Log File System kernel driver that occurs when processing maliciously formatted log files. This will eventually lead to an untrusted pointer dereference by the kernel. An attacker is able to modify the pointer such that the the execution flow of the kernel will be redirected to a user controlled address. | ||||||||
|
|
||||||||
| The Windows Common Log File System (CLFS) uses Base Log Files (BLF) and Container files for storing log information. BLFs hold all the important metadata relating to the log file while Containers hold the actual log data. | ||||||||
|
|
||||||||
| The untrusted pointer dereference can be found in the function `CClfsBaseFilePersisted::LoadContainerQ()`, where `pContainer` is a variable that can be indirectly manipulated and dereferenced. | ||||||||
|
|
||||||||
| ``` | ||||||||
| CClfsBaseFilePersisted::LoadContainerQ(){ | ||||||||
| ... | ||||||||
| return_value = CClfsBaseFilePersisted::FlushImage((PERESOURCE *)this); | ||||||||
| ... | ||||||||
| if ( return_value < 0 ) | ||||||||
| goto LABEL_116; | ||||||||
| ... | ||||||||
| LABEL_116: | ||||||||
| ContainerContext->pContainer->Release(ContainerContext->pContainer); //pContainer dereference | ||||||||
| } | ||||||||
| ``` | ||||||||
|
|
||||||||
| In order for `pContainer` dereference to be reached, `CClfsBaseFilePersisted::FlushImage()` would have to return a negative value, or an error code. Provided is the pesudocode for the relevant functions. | ||||||||
Ryujin76 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||
|
|
||||||||
| ``` | ||||||||
| CClfsBaseFilePersisted::FlushImage(PERESOURCE *this){ | ||||||||
| ... | ||||||||
| return_value = CClfsBaseFilePersisted::WriteMetadataBlock(...); | ||||||||
| return return_value; | ||||||||
| } | ||||||||
| ``` | ||||||||
|
|
||||||||
| ``` | ||||||||
| CClfsBaseFilePersisted::WriteMetadataBlock(...){ | ||||||||
| ... | ||||||||
| ++ullDumpCount; | ||||||||
| if (ullDumpCount & 1){ //if ullDumpCount is odd | ||||||||
| ++Usn; | ||||||||
| } | ||||||||
| ... | ||||||||
| return_value = ClfsEncodeBlock(...) | ||||||||
| if (return_value >= 0){ //if ClfsEncodeBlock returns success | ||||||||
| ClfsEncodeBlockSuccess = 1; | ||||||||
| } | ||||||||
| ... | ||||||||
| if (ClfsEncodeBlockSuccess){ | ||||||||
| return_value_2 = ClfsDecodeBlock(...); | ||||||||
| if (return_value_2 < 0){ //if ClfsDecodeBlock returned error | ||||||||
| ReleaseMetadataBlock(...); | ||||||||
| return return_value_2; | ||||||||
| } | ||||||||
| } | ||||||||
| ... | ||||||||
| return return_value; | ||||||||
| } | ||||||||
| ``` | ||||||||
|
|
||||||||
| In order to dereference `pContainer`, you would need to have `ClfsEncodeBlock()` succeed and `ClfsDecodeBlock()` fail. `ClfsEncodeBlock()` succeeding would let us modify the value stored inside of `pContainer`, while `ClfsDecodeBlock()` failing would return an error code, which is necessary to reach the code in `CClfsBaseFilePersisted::LoadContainerQ()` that dereferences `pContainer`. | ||||||||
|
|
||||||||
| A BLF is split into multiple sectors of fixed size 512 bytes, and each of these sectors have a 2 byte signature located at the end. This signature is checked and manipulated by both `ClfsEncodeBlock()` and `ClfsDecodeBlock()`, and is critical for triggering this vulnerability. | ||||||||
|
|
||||||||
| To make `ClfsDecodeBlock()` fail after `ClfsEncodeBlock()` succeeds, an attacker would prepare the BLF such that there are 2 overlapping header sections: | ||||||||
| * A sector signature and `pContainer` overlap. | ||||||||
| * A sector signature and the `signatures array` overlap. | ||||||||
|
|
||||||||
| We also need to ensure that `ullDumpCount`, a value found in the BLF header, is an odd value as we want `Usn` to be incremented in `CClfsBaseFilePersisted::WriteMetadataBlock()`. `Usn` will then be used in `ClfsEncodeBlock()` to calculate a new sector signature. | ||||||||
|
|
||||||||
| `ClfsEncodeBlock()` calls `ClfsEncodeBlockPrivate()`. | ||||||||
|
|
||||||||
| ``` | ||||||||
| ClfsEncodeBlockPrivate(...){ | ||||||||
| if ( size or offsets are wrong ){ //preliminary checks | ||||||||
| return ErrorCode; | ||||||||
| } | ||||||||
|
|
||||||||
| SectorNumber = 0; | ||||||||
| while (SectorNumber < TotalSectors){ | ||||||||
| //calculate new sector signature | ||||||||
| ... | ||||||||
|
|
||||||||
| SectorSigOffset = SectorNumber << 9; //SectorNumber * 512 (size of sector) | ||||||||
| *SignaturesArray = *(SectorSigOffset + 2); //store old signature | ||||||||
| SignaturesArray += 2; //move to next entry in SignaturesArray | ||||||||
| *(SectorSigOffset + 2) = NewSig //write new signature | ||||||||
| SectorNumber++; | ||||||||
| } | ||||||||
| } | ||||||||
| ``` | ||||||||
| ClfsEncodeBlockPrivate() logic: | ||||||||
| * `ClfsEncodeBlock()` and `ClfsEncodeBlockPrivate()` does preliminary checks that various fields in the BLF are valid. | ||||||||
| * Loops over all sector signatures and copy them into the `signatures array` located at `SignaturesOffset`, then calculates and writes a new signature value into sector signature (going from low address to high address). | ||||||||
Ryujin76 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||
| * As an example, take a malicious BLF which has a `ullDumpCount` value of 2 and a `Usn` value of 1. Following the sector signature format of `[Sector Block Type][Usn]`, each sector of this BLF would have a sector signature of `0x10 0x01`. | ||||||||
Ryujin76 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||
| * `WriteMetadataBlock()` will increment both `ullDumpCount` and `Usn` by 1 before jumping to `ClfsEncodeBlock()` and `ClfsEncodeBlockPrivate()`. | ||||||||
| * `ClfsEncodeBlockPrivate()` would calculate the new sector signature as `0x10 0x02`, following the sector signature format. | ||||||||
| * Each sector would have its old signature of `0x10 0x01` stored at the `signatures array` located at `SignaturesOffset`, and its new sector signature value of `0x10 0x02` be written to the sector signature. However, due to the overlapping header sections that are present in the maliciou BLF, when `ClfsEncodeBlockPrivate()` stores the old signature into the `signatures array`, it will overwrite the new sector signataure value of that sector. | ||||||||
|
||||||||
| * As an example: | ||||||||
|
||||||||
| * As an example: | |
| As an example: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As described in my verbose comment above, I think there is a bit more nuance to it than described here.
Ryujin76 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Ryujin76 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Ryujin76 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Ryujin76 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Ryujin76 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| In depth analysis of the chained exploit has been performed and documented below. | |
| In depth analysis of the chained kernel functions has been performed and documented below. |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it was used standalone to elevate privileges on a Windows machine?
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SMAP would kill the usermode dereference, but has been discarded on Windows (https://github.com/microsoft/MSRC-Security-Research/blob/master/papers/2020/Evaluating%20the%20feasibility%20of%20enabling%20SMAP%20for%20the%20Windows%20kernel.pdf)
The leaks via NtQuerySystemInformation from medium IL are killed on Windows 11 24H2.
Overwriting Previousmode should also not work anymore on Windows 11 24H2.
See "Limitations and improvements" at https://security.humanativaspa.it/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1/
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can mention:
- Dropping and modifying BLF files
- Spawning cmd.exe as SYSTEM
- Monitoring suspicious API calls such as NtQuerySystemInformation
Uh oh!
There was an error while loading. Please reload this page.