{"id":4929,"date":"2025-01-29T09:32:27","date_gmt":"2025-01-29T08:32:27","guid":{"rendered":"https:\/\/security.humanativaspa.it\/?p=4929"},"modified":"2025-09-15T13:16:33","modified_gmt":"2025-09-15T13:16:33","slug":"cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1","status":"publish","type":"post","link":"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/","title":{"rendered":"CVE-2024-49138 Windows CLFS heap-based buffer overflow analysis &#8211; Part 1"},"content":{"rendered":"<p><a href=\"https:\/\/msrc.microsoft.com\/update-guide\/vulnerability\/CVE-2024-49138\">CVE-2024-49138<\/a> is a <strong>Windows vulnerability<\/strong> detected by CrowdStrike as <strong>exploited in the wild<\/strong>. Microsoft <strong>patched<\/strong> the vulnerability on December 10th, 2024 with <a href=\"https:\/\/support.microsoft.com\/help\/5048685\">KB5048685<\/a> (for Windows 11 23H2\/22H2).<\/p>\n<p>The analysis of the patch reveals that Microsoft actually patched <strong>two distinct vulnerabilities <\/strong>in the following functions defined in clfs.sys:<\/p>\n<ul>\n<li><em>CClfsBaseFilePersisted::LoadContainerQ()<\/em><\/li>\n<li><em>CClfsBaseFilePersisted::WriteMetadataBlock()<\/em><\/li>\n<\/ul>\n<p>I created <strong>two proof-of-concept exploits <\/strong>for these vulnerabilities\u00a0that are available in this <a href=\"https:\/\/github.com\/MrAle98\/CVE-2024-49138-POC\">repository<\/a>:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/MrAle98\/CVE-2024-49138-POC\">master branch<\/a>: exploit leveraging the <em>LoadContainerQ()<\/em> vulnerability<\/li>\n<li><a href=\"https:\/\/github.com\/MrAle98\/CVE-2024-49138-POC\/tree\/second\">second branch<\/a>:\u00a0 exploit leveraging the <em>WriteMetadataBlock()<\/em> vulnerability<\/li>\n<\/ul>\n<p>The analysis was conducted on a <strong>Windows 11 23H2<\/strong> machine having the following hashes for ntoskrnl.exe and clfs.sys:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"monokai\">PS C:\\Windows\\System32\\drivers&gt; Get-FileHash .\\clfs.sys\r\n\r\nAlgorithm       Hash                                                                   Path\r\n---------       ----                                                                   ----\r\nSHA256          B138C28F72E8510F9612D07D5109D73065CED6CBBF8079A663A1E0601FE0FBAA       C:\\Windows\\System32\\drivers\\c...\r\n\r\n\r\nPS C:\\Windows\\System32\\drivers&gt;<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"monokai\">PS C:\\Windows\\System32&gt; Get-FileHash .\\ntoskrnl.exe\r\n\r\nAlgorithm       Hash                                                                   Path\r\n---------       ----                                                                   ----\r\nSHA256          0CE15480462E9CD3F7CBF2D44D2E393CF5674EE1D69A3459ADFA0E913A7A2AEB       C:\\Windows\\System32\\ntoskrnl.exe\r\n\r\n\r\nPS C:\\Windows\\System32&gt;<\/pre>\n<p>This article aims to analyze the <strong><em>LoadContainerQ()\u00a0<\/em>vulnerability<\/strong> and develop a proof of concept exploit.<\/p>\n<p>The <em>CLFS Background <\/em>section below describes the CLFS data structures involved. The <em>Vulnerability Analysis<\/em> section describes the vulnerability, and the <em>Exploitation <\/em>section describes how to exploit the vulnerability to obtain arbitrary read\/write in ring 0 and elevate privileges to system. Finally, the <em>Limitations and Improvements <\/em>section analyzes the restriction and proposes improvements for the PoC, while the <em>Patch Analysis<\/em> section briefly discusses the patch and its effects.<\/p>\n<p>For some background on <strong>Windows kernel driver exploitation<\/strong>, please refer to my previous articles in <a href=\"https:\/\/hnsecurity.it\/tag\/atdcm64a\/\">this series<\/a>.<\/p>\n<p><em>Note: All code snippets provided here come from reverse engineering and may not be entirely accurate.<\/em><\/p>\n<h2>CLFS Background<\/h2>\n<p>The Windows <strong>Common Log File System (CLFS)<\/strong> provides a high-performance, general-purpose log file subsystem that dedicated client applications can use and multiple clients can share to optimize log access. Any user mode application that needs logging or recovery support can use CLFS.<\/p>\n<p>The data structures and APIs described in this section are taken both from <a href=\"https:\/\/learn.microsoft.com\/en-us\/previous-versions\/windows\/desktop\/clfs\/common-log-file-system-portal\"><em>MSDN<\/em><\/a> and from <a href=\"https:\/\/github.com\/ionescu007\/clfs-docs\">Alex Ionescu&#8217;s\u00a0unofficial documentation<\/a>. Here are some excellent resources describing the inner working of CLFS and some related exploits:<\/p>\n<ul>\n<li><a href=\"https:\/\/blog.exodusintel.com\/2022\/03\/10\/exploiting-a-use-after-free-in-windows-common-logging-file-system-clfs\/\">Exodus Intelligence: use-after-free in CLFS<\/a><\/li>\n<li><a href=\"https:\/\/securelist.com\/windows-clfs-exploits-ransomware\/111560\/\">SecureList&#8217;s series on CLFS exploits<\/a><\/li>\n<\/ul>\n<h3>Base Log File<\/h3>\n<p>The Base Log File (BLF) is the .BLF file created\/opened using the <a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/api\/clfsw32\/nf-clfsw32-createlogfile\"><em>CreateLogFile()<\/em><\/a> API. The BLF keeps track of <em>containers<\/em> and <em>clients<\/em> (among other things) where containers are files associated with the BLF containing the actual user data.<\/p>\n<p>Containers are created with the <a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/api\/clfsw32\/nf-clfsw32-addlogcontainer\"><em>AddLogContainer()<\/em><\/a> API and the producer can write data (i.e., records) in containers using a combination of CLFS APIs. Microsoft provides examples for <a href=\"https:\/\/learn.microsoft.com\/en-us\/previous-versions\/windows\/desktop\/clfs\/appending-records-to-a-log\">writing records to containers<\/a> and <a href=\"https:\/\/learn.microsoft.com\/en-us\/previous-versions\/windows\/desktop\/clfs\/reading-records-from-a-log\">reading records from containers<\/a>.<\/p>\n<p>The BLF is made up of <strong>6 metadata blocks<\/strong>:<\/p>\n<ul>\n<li><strong>Control Metadata Block<\/strong>: stores a <em>control record<\/em> that contains <strong>information about all other blocks<\/strong> in the BLF<\/li>\n<li><strong>Control Metadata Block Shadow<\/strong>: a <strong>copy of the Control Metadata Block<\/strong><\/li>\n<li><strong>General Metadata Block<\/strong>: stores a <strong>base log record<\/strong>\u00a0containing information about <strong>clients <\/strong>and <strong>containers<\/strong><\/li>\n<li><strong>General Metadata Block Shadow<\/strong>: a <strong>copy of the General Metadata Block<\/strong><\/li>\n<li><strong>Scratch Metadata Block<\/strong>: contains information about <strong>truncate context<\/strong><\/li>\n<li><strong>Scratch Metadata Block Shadow<\/strong>: contains <strong>a copy of Scratch Metadata Block<\/strong><\/li>\n<\/ul>\n<p>Every metadata block is made up of <em>sectors<\/em> where each one is 0x200 bytes large.<\/p>\n<p>The following picture from <a href=\"https:\/\/securelist.com\/windows-clfs-exploits-ransomware\/111560\/\">securelist&#8217;s article<\/a> describes the sizes and location of the different metadata blocks in a BLF.<\/p>\n<figure style=\"width: 800px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" src=\"https:\/\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2023\/12\/20151624\/Windows-CLFS-five-exploits-ransomware_part1_en_03-800x500.png\" alt=\"\" width=\"800\" height=\"500\" \/><figcaption class=\"wp-caption-text\">Layout of a BLF file (source: Securelist&#8217;s blog)<\/figcaption><\/figure>\n<p>We will focus mainly on the <strong>General Metadata Block<\/strong> as the vulnerability lies in how the driver handles it in memory.<\/p>\n<h3>General Metadata Block<\/h3>\n<p>The General Metadata Block as all the others block starts with a <em>CLFS_LOG_BLOCK_HEADER:<\/em><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">typedef struct _CLFS_LOG_BLOCK_HEADER\r\n{\r\n    UCHAR MajorVersion;\r\n    UCHAR MinorVersion;\r\n    UCHAR Usn;\r\n    CLFS_CLIENT_ID ClientId;\r\n    USHORT TotalSectorCount;\r\n    USHORT ValidSectorCount;\r\n    ULONG Padding;\r\n    ULONG Checksum;\r\n    ULONG Flags;\r\n    CLFS_LSN CurrentLsn;\r\n    CLFS_LSN NextLsn;\r\n    ULONG RecordOffsets[16];\r\n    ULONG SignaturesOffset;\r\n} CLFS_LOG_BLOCK_HEADER, *PCLFS_LOG_BLOCK_HEADER;<\/pre>\n<p>This is followed by a <em>BASE_RECORD_HEADER:<\/em><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">typedef struct _CLFS_BASE_RECORD_HEADER\r\n{\r\n    CLFS_METADATA_RECORD_HEADER hdrBaseRecord;\r\n    CLFS_LOG_ID cidLog;\r\n    ULONGLONG rgClientSymTbl[CLIENT_SYMTBL_SIZE];\r\n    ULONGLONG rgContainerSymTbl[CONTAINER_SYMTBL_SIZE];\r\n    ULONGLONG rgSecuritySymTbl[SHARED_SECURITY_SYMTBL_SIZE];\r\n    ULONG cNextContainer;\r\n    CLFS_CLIENT_ID cNextClient;\r\n    ULONG cFreeContainers;\r\n    ULONG cActiveContainers;\r\n    ULONG cbFreeContainers;\r\n    ULONG cbBusyContainers;\r\n    ULONG rgClients[MAX_CLIENTS_DEFAULT];\r\n    ULONG rgContainers[MAX_CONTAINERS_DEFAULT];\r\n    ULONG cbSymbolZone;\r\n    ULONG cbSector;\r\n    USHORT bUnused;\r\n    CLFS_LOG_STATE eLogState;\r\n    UCHAR cUsn;\r\n    UCHAR cClients;\r\n} CLFS_BASE_RECORD_HEADER, *PCLFS_BASE_RECORD_HEADER;<\/pre>\n<p>The <em>rgContainers<\/em> field corresponds to an array of offsets (from the beginning of the block) to <em>CLFS_CONTAINER_CONTEXT<\/em> structures (always inside the General Metadata Block) describing information about containers:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">typedef struct _CLFS_CONTAINER_CONTEXT\r\n{\r\n    CLFS_NODE_ID cidNode;\r\n    ULONGLONG cbContainer;\r\n    CLFS_CONTAINER_ID cidContainer;\r\n    CLFS_CONTAINER_ID cidQueue;\r\n    union\r\n    {\r\n        CClfsContainer* pContainer;\r\n        ULONGLONG ullAlignment;\r\n    };\r\n    CLFS_USN usnCurrent;\r\n    CLFS_CONTAINER_STATE eState;\r\n    ULONG cbPrevOffset;\r\n    ULONG cbNextOffset;\r\n} CLFS_CONTAINER_CONTEXT, *PCLFS_CONTAINER_CONTEXT;<\/pre>\n<p>Of particular interest is the <em><strong>pContainer<\/strong><\/em> field. On <strong>disk it is set to 0<\/strong> while when the BLF is loaded in memory it corresponds to a <strong>kernel pointer<\/strong> pointing to a <em><strong>CClfsContainer<\/strong><\/em> object.<\/p>\n<p>Each <em>CLFS_CONTAINER_CONTEXT<\/em> is preceded by a <em>CLFSHASHSYM<\/em> structure as defined below:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">typedef struct _CLFSHASHSYM\r\n{\r\n    CLFS_NODE_ID cidNode;\r\n    ULONG ulHash;\r\n    ULONG cbHash;\r\n    ULONGLONG ulBelow;\r\n    ULONGLONG ulAbove;\r\n    LONG cbSymName;\r\n    LONG cbOffset;\r\n    BOOLEAN fDeleted;\r\n} CLFSHASHSYM, *PCLFSHASHSYM;<\/pre>\n<p>The <em>BASE_RECORD_HEADER.<\/em><em>rgContainerSymTbl <\/em>array stores offsets to these <em>CLFSHASHSYM<\/em> structures. It is a hash table that uses the <em>ClfsHashPJW() <\/em>function, applied to the container&#8217;s full path, to compute the index in the table containing the right offset.<\/p>\n<p>Here&#8217;s an example of Base Log File storing a container named &#8220;container1&#8221; (the BLF was opened inside ImHex):<\/p>\n<figure id=\"attachment_4992\" aria-describedby=\"caption-attachment-4992\" style=\"width: 628px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"wp-image-4992 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-20-10_11_32-ImHex-mylogdddd.blf_.blf_.normal-1.png\" alt=\"\" width=\"628\" height=\"423\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-20-10_11_32-ImHex-mylogdddd.blf_.blf_.normal-1.png 628w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-20-10_11_32-ImHex-mylogdddd.blf_.blf_.normal-1-300x202.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-20-10_11_32-ImHex-mylogdddd.blf_.blf_.normal-1-350x236.png 350w\" sizes=\"(max-width: 628px) 100vw, 628px\" \/><figcaption id=\"caption-attachment-4992\" class=\"wp-caption-text\">General Metadata Block (ImHex)<\/figcaption><\/figure>\n<p>In the diagram above you can see the beginning of the General Metadata Block that starts with a <em>_CLFS_LOG_BLOCK_HEADER\u00a0<\/em>with <em>MajorVersion=15, <\/em>the <em>Usn=3, <\/em>the <em>checksum\u00a0<\/em>and <em>recordOffsets[0]=0x70. <\/em>meaning that the <em>_CLFS_BASE_RECORD_HEADER\u00a0<\/em>is located at 0x800+0x70 = 0x870.<\/p>\n<p>At offset 0x8e0 lies the <em>rgContainerSymTbl <\/em>hash table (in orange) containing the offset value 0x1440 (from <em>_CLFS_BASE_RECORD_HEADER)<\/em> at index 6.<\/p>\n<p>In fact, at 0x800+0x70+0x1440=0x1cb0 we can find the <em>CLFSHASHSYM<\/em> structure followed by the <em>CLFS_CONTAINER_CONTEXT\u00a0<\/em>finally followed by the actual symbol, the full path to the file:<\/p>\n<figure id=\"attachment_4993\" aria-describedby=\"caption-attachment-4993\" style=\"width: 544px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"wp-image-4993 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-20-10_20_07-ImHex-mylogdddd.blf_.blf_.normal-1.png\" alt=\"\" width=\"544\" height=\"303\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-20-10_20_07-ImHex-mylogdddd.blf_.blf_.normal-1.png 544w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-20-10_20_07-ImHex-mylogdddd.blf_.blf_.normal-1-300x167.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-20-10_20_07-ImHex-mylogdddd.blf_.blf_.normal-1-350x195.png 350w\" sizes=\"(max-width: 544px) 100vw, 544px\" \/><figcaption id=\"caption-attachment-4993\" class=\"wp-caption-text\">CLFS_CONTAINER_CONTEXT in General Metadata Block (ImHex)<\/figcaption><\/figure>\n<p>Notice that the metadata blocks, when stored on disk, are encoded. In fact, it is possible to notice the values 0x10 0x03. This is the <em>sector signature<\/em> and corresponds to <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">[Sector Block Type][Usn]<\/code> as described by Alex Ionescu. Every sector (recall a sector is 0x200 bytes wide) presents this signature at the end.<\/p>\n<p>When the metadata blocks are parsed from the BLF on disk and loaded in memory the signatures <strong>must be replaced<\/strong> with the actual data. For this purpose the <em>_CLFS_LOG_BLOCK_HEADER.SignaturesOffset<\/em> exists<em>. <\/em>It is an offset, from the beginning of the block, pointing to an <strong>array containing the actual data that must replace the sector signatures<\/strong> <strong>when blocks are decoded<\/strong> from disk and loaded in memory.<\/p>\n<p>Finally, clfs.sys uses the <em>CClfsBaseFilePersisted<\/em> class to represent the Base Log File in memory having the following shape:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">struct __unaligned __declspec(align(8)) _CClfsBaseFilePersisted\r\n{\r\n  _CClfsBaseFilePersisted_VTABLE_0_00000001C0014000::vtable *vftbl_0_00000001C0014000;\r\n  ULONG m_cref;\r\n  _BYTE gapC[4];\r\n  PUCHAR m_pbImage;\r\n  ULONG m_cbImage;\r\n  _BYTE gap1C[4];\r\n  __int64 m_presImage;\r\n  USHORT m_cBlocks;\r\n  _BYTE gap2A[6];\r\n  CLFS_METADATA_BLOCK *m_rgBlocks;\r\n  PUSHORT m_rgcBlockReferences;\r\n  CLFSHASHTBL m_symtblClient;\r\n  CLFSHASHTBL m_symtblContainer;\r\n  CLFSHASHTBL m_symtblSecurity;\r\n  ULONGLONG size;\r\n  ULONG m_cbRawSectorSize;\r\n  BOOLEAN m_fgeneralBlockReferenced;\r\n  __declspec(align(4)) __int64 pCclfsContainer;\r\n  __int64 event_a0;\r\n  __int64 field_A8;\r\n  char file_ea_info[16];\r\n  __int64 field_C0;\r\n  int field_C8;\r\n  _BYTE gapCC[4];\r\n  __int64 field_D0;\r\n  _UNICODE_STRING filepath;\r\n  RTL_BITMAP bitmap;\r\n  char bitmapBuf[128];\r\n  int field_178;\r\n  _BYTE gap17C[4];\r\n  char field_180[16];\r\n  char field_190[16];\r\n  char n_writes[16];\r\n  __int64 field_1B0;\r\n  __int64 controlrecord;\r\n  int field_1C0;\r\n};\r\n<\/pre>\n<p>The important fields here are <em>m_rgBlocks<\/em>, an array of <em>CLFS_METADATA_BLOCK (<\/em>containing pointers to the different blocks in memory), and <em>m_rgcBlockReferences<\/em> storing a <strong>reference count<\/strong> for each block.<\/p>\n<p>The definition of <em>CLFS_METADATA_BLOCK <\/em>is:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">struct _CLFS_METADATA_BLOCK\r\n{\r\n  PUCHAR pbImage;\r\n  ULONG cbImage;\r\n  ULONG cbOffset;\r\n  CLFS_METADATA_BLOCK_TYPE eBlockType;\r\n};\r\n<\/pre>\n<p><em>pbImage <\/em>points to the <strong>Metadata Block in memory<\/strong>, <em>cbImage <\/em>corresponds to the size of the block. <em>eBlockType<\/em> is the following enum:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\">typedef enum _CLFS_METADATA_BLOCK_TYPE\r\n{\r\n    ClfsMetaBlockControl,\r\n    ClfsMetaBlockControlShadow,\r\n    ClfsMetaBlockGeneral,\r\n    ClfsMetaBlockGeneralShadow,\r\n    ClfsMetaBlockScratch,\r\n    ClfsMetaBlockScratchShadow\r\n} CLFS_METADATA_BLOCK_TYPE, *PCLFS_METADATA_BLOCK_TYPE;<\/pre>\n<p>The <em>eBlockType <\/em>of a General Metadata Block is <strong>ClfsMetaBlockGeneral\u00a0<\/strong>that correponds to <strong>2<\/strong>. <em>CLFS_METADATA_BLOCK_TYPE <\/em>is also used as <strong>index<\/strong> inside the <em>_CClfsBaseFilePersisted.m_rgBlocks<\/em> array.<\/p>\n<h2>Vulnerability Analysis<\/h2>\n<p>The base log file can be opened using the <em><a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/api\/clfsw32\/nf-clfsw32-createlogfile\">CreateLogFile()<\/a><\/em> API. The API will lead to a call to <em>CClfsLogFcbPhysical::Initialize()<\/em> in the kernel:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">__int64 __fastcall CClfsLogFcbPhysical::Initialize(\r\n        _CClfsLogFcbPhysical *this,\r\n        CLFS_LSN a2,\r\n        struct _SECURITY_SUBJECT_CONTEXT *a3,\r\n        ACCESS_MASK a4,\r\n        ULONG DesiredShareAccess,\r\n        struct _ACCESS_STATE *a6,\r\n        char a7,\r\n        struct _CLFS_FILTER_CONTEXT *a8,\r\n        struct _FILE_OBJECT *FileObject,\r\n        unsigned __int8 a10){\r\n\r\n[...]\r\n if ( v26 )\r\n    cclfsbaseFilePersisted = CClfsBaseFilePersisted::CClfsBaseFilePersisted(v26);\r\n  else\r\n    cclfsbaseFilePersisted = 0LL;\r\n  this-&gt;pcclfBaseFilePersisted = cclfsbaseFilePersisted;\r\n  if ( !cclfsbaseFilePersisted )\r\n    goto LABEL_76;\r\n  v75 = 1;\r\n  CClfsBaseFile::AddRef((CClfsBaseFile *)cclfsbaseFilePersisted);\r\n  ret = CClfsBaseFilePersisted::OpenImage(\r\n          this-&gt;pcclfBaseFilePersisted,\r\n          &amp;Destination,\r\n          (const struct _CLFS_FILTER_CONTEXT *)&amp;v86,\r\n          a10,\r\n          (unsigned __int8 *)&amp;v88);\r\n[...]\r\n ret = CClfsBaseFilePersisted::LoadContainerQ(\r\n          v51,\r\n          (unsigned int *const)&amp;this-&gt;field_558,\r\n          0x400,\r\n          (this-&gt;flags &amp; 2) != 0,\r\n          v53,\r\n          (union _CLS_LSN)lsnRestart,\r\n          (unsigned int *)&amp;this-&gt;field_554,\r\n          (unsigned int *)&amp;this-&gt;field_550,\r\n          &amp;v84);\r\n[...]\r\n}<\/pre>\n<h3>CClfsBaseFilePersisted::OpenImage()<\/h3>\n<p>This method creates a <em>CClfsBaseFilePersisted<\/em> object, initializes the object, and calls <em>CClfsBaseFilePersisted::OpenImage()<\/em>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">__int64 __fastcall CClfsBaseFilePersisted::OpenImage(\r\n        _CClfsBaseFilePersisted *this,\r\n        struct _UNICODE_STRING *ExtFileName,\r\n        const struct _CLFS_FILTER_CONTEXT *clfsFilterContext,\r\n        char a4,\r\n        unsigned __int8 *a5)\r\n{\r\n[...]\r\n ret = CClfsBaseFilePersisted::ReadImage(this, &amp;controlRecord);\r\n  ret_1 = ret;\r\n  v31 = ret;\r\n  if ( ret &lt; 0 )\r\n  {\r\nLABEL_21:\r\n    if ( ret != 0xC0000011 )\r\n      goto end;\r\nset_error:\r\n    ret_1 = 0xC01A000D;\r\nLABEL_45:\r\n    v31 = ret_1;\r\n    goto end;\r\n  }\r\n  ret_1 = CClfsContainer::GetContainerSize((_CClfsContainer *)this-&gt;pCclfsContainer, &amp;this-&gt;size);\r\n  v31 = ret_1;\r\n  if ( ret_1 &lt; 0 )\r\n    goto end;\r\n  BaseLogRecord = CClfsBaseFile::GetBaseLogRecord(this);\r\n  if ( !BaseLogRecord )\r\n    goto set_error;\r\n  this-&gt;m_symtblClient.rgSymHash = BaseLogRecord-&gt;rgClientSymTbl;\r\n  this-&gt;m_symtblClient.cHashElt = 11;\r\n  this-&gt;m_symtblClient.pBaseFile = (CClfsBaseFile *)this;\r\n  this-&gt;m_symtblContainer.rgSymHash = BaseLogRecord-&gt;rgContainerSymTbl;\r\n  this-&gt;m_symtblContainer.cHashElt = 11;\r\n  this-&gt;m_symtblContainer.pBaseFile = (CClfsBaseFile *)this;\r\n  this-&gt;m_symtblSecurity.rgSymHash = BaseLogRecord-&gt;rgSecuritySymTbl;\r\n  this-&gt;m_symtblSecurity.cHashElt = 11;\r\n  this-&gt;m_symtblSecurity.pBaseFile = (CClfsBaseFile *)this;\r\n  controlRecord_1 = controlRecord;\r\n[...]\r\n}<\/pre>\n<p><em>OpenImage<\/em> will issue a call to <em>CClfsBaseFilePersisted::ReadImage() <\/em>to read the Control Block and the General Block from the BLF on disk and load them in memory at the addresses <em>CClfsBaseFilePersisted.m_rgBlocks[blockType].pbImage<\/em>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">__int64 __fastcall CClfsBaseFilePersisted::ReadImage(\r\n        _CClfsBaseFilePersisted *this,\r\n        struct _CLFS_CONTROL_RECORD **ppcontrolrecord)\r\n{\r\n[...]\r\n  memset(m_rgBlocks, 0, 0x18LL * this-&gt;m_cBlocks);\r\n  memset(this-&gt;m_rgcBlockReferences, 0, 2LL * this-&gt;m_cBlocks);\r\n  this-&gt;m_rgBlocks-&gt;cbOffset = 0;\r\n  this-&gt;m_rgBlocks-&gt;cbImage = 2 * this-&gt;m_cbRawSectorSize;\r\n  this-&gt;m_rgBlocks[ClfsMetaBlockControlShadow].cbOffset = 2 * this-&gt;m_cbRawSectorSize;\r\n  this-&gt;m_rgBlocks[ClfsMetaBlockControlShadow].cbImage = 2 * this-&gt;m_cbRawSectorSize;\r\n  ret = CClfsBaseFile::GetControlRecord(this, ppcontrolrecord, 0);\r\n[...]\r\n pbImageControlRecord = this-&gt;m_rgBlocks-&gt;pbImage;\r\n  for ( i = 0; i &lt; this-&gt;m_cBlocks; ++i )\r\n  {\r\n    v13 = i;\r\n    controlrecord_1 = *ppcontrolrecord;\r\n    controlblock = this-&gt;m_rgBlocks;\r\n    *(_OWORD *)&amp;controlblock[v13].pbImage = *(_OWORD *)&amp;(*ppcontrolrecord)-&gt;rgBlocks[i].pbImage;\r\n    *(_QWORD *)&amp;controlblock[v13].eBlockType = *(_QWORD *)&amp;controlrecord_1-&gt;rgBlocks[i].eBlockType;\r\n    this-&gt;m_rgBlocks[v13].pbImage = 0LL;\r\n  }\r\n  this-&gt;m_rgBlocks-&gt;pbImage = pbImageControlRecord;\r\n  this-&gt;m_rgBlocks[ClfsMetaBlockControlShadow].pbImage = pbImageControlRecord;\r\n  ret = CClfsBaseFile::AcquireMetadataBlock(this, ClfsMetaBlockGeneral);\r\n  ret_1 = ret;\r\n  if ( ret &gt;= 0 )\r\n    this-&gt;m_fgeneralBlockReferenced = 1;\r\n[...]\r\n}<\/pre>\n<p>The function <em>ReadImage()<\/em> calls <em>GetControlRecord() <\/em>that internally calls <em>AcquireMetadataBlock()<\/em> to load the Control Block (and the corresponding shadow block) in memory, and later calls <em>AcquireMetadataBlock()\u00a0<\/em>again to load the General Block in memory (and the corresponding shadow block).<\/p>\n<p>The pseudocode for <em>AcquireMetadataBlock() <\/em>follows.\u00a0If the block wasn&#8217;t already loaded in memory, that is the reference count in <em>m_rgcBlockReferences<\/em> is equal to zero, it will call <em>ReadMetadataBlock()<\/em>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">__int64 __fastcall CClfsBaseFile::AcquireMetadataBlock(\r\n        _CClfsBaseFilePersisted *this,\r\n        enum _CLFS_METADATA_BLOCK_TYPE blockType)\r\n{\r\n  __int64 BlockType; \/\/ rsi\r\n  unsigned int v4; \/\/ edx\r\n  int v5; \/\/ r8d\r\n  int v6; \/\/ r9d\r\n\r\n  BlockType = blockType;\r\n  v4 = 0;\r\n  if ( (int)BlockType &lt; 0 || (int)BlockType &gt;= this-&gt;m_cBlocks )\r\n    return 0xC0000225LL;\r\n  if ( ++this-&gt;m_rgcBlockReferences[BlockType] != 1 )\r\n    return v4;\r\n  v4 = ((__int64 (__fastcall *)(_CClfsBaseFilePersisted *, _QWORD))this-&gt;vftbl_0_00000001C0014000-&gt;CClfsBaseFilePersisted::ReadMetadataBlock(ulong))(\r\n         this,\r\n         (unsigned int)BlockType);\r\n  if ( (v4 &amp; 0x80000000) != 0 )\r\n  {\r\n    --this-&gt;m_rgcBlockReferences[BlockType];\r\n    return v4;\r\n  }\r\n  if ( this-&gt;m_rgBlocks[BlockType].pbImage )\r\n    return v4;\r\n[...]\r\n}<\/pre>\n<p>Here&#8217;s the execution state after <em>OpenImage()<\/em> completes successfully. It is possible to notice that the General Block was loaded in CClfsBaseFilePersisted.m_rgBlocks[2].pbImage = 0xFFFFD4000EF9A000, and the corresponding reference count is set to 1. In the Hex-View we can see that the memory at 0xFFFFD4000EF9A000 starts with 15 00 03 00 confirming it contains the block from from the BLF on disk:<\/p>\n<figure id=\"attachment_4998\" aria-describedby=\"caption-attachment-4998\" style=\"width: 1901px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"wp-image-4998 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-01_01_40-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1.png\" alt=\"\" width=\"1901\" height=\"889\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-01_01_40-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1.png 1901w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-01_01_40-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-300x140.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-01_01_40-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-1024x479.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-01_01_40-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-768x359.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-01_01_40-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-1536x718.png 1536w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-01_01_40-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-350x164.png 350w\" sizes=\"(max-width: 1901px) 100vw, 1901px\" \/><figcaption id=\"caption-attachment-4998\" class=\"wp-caption-text\">General Metadata Block loaded in memory with reference count set to 1 after OpenImage()<\/figcaption><\/figure>\n<h3><strong>CClfsBaseFilePersisted::LoadContainerQ()<\/strong><\/h3>\n<p><em>OpenImage(), CClfsLogFcbPhysical::Initialize() <\/em>then calls <em>LoadContainerQ()<\/em>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">__int64 __fastcall CClfsBaseFilePersisted::LoadContainerQ(\r\n        _CClfsBaseFilePersisted *this,\r\n        unsigned int *const a2,\r\n        int a3,\r\n        unsigned __int8 a4,\r\n        char a5,\r\n        union _CLS_LSN a6,\r\n        unsigned int *a7,\r\n        unsigned int *a8,\r\n        unsigned __int64 *pcbContainer)\r\n{\r\n[...]\r\n BaseLogRecord = CClfsBaseFile::GetBaseLogRecord(this);\r\n[...]\r\n rgContainers = BaseLogRecord-&gt;rgContainers;\r\n[...]\r\n rgContainers_1 = rgContainers;\r\n[..]\r\n while ( (unsigned int)k &lt; MAX_CONTAINERS_DEFAULT )\r\n  {\r\n[...]\r\n    offset = rgContainers_1[k];\r\n    if ( offset )\r\n    {\r\n      if ( offset &lt; 0x1338 )\r\n        goto error;\r\n      if ( (int)CClfsBaseFile::GetSymbol(this, offset, k, (UCHAR **)&amp;container_context) &lt; 0 )\r\n        goto error;\r\n      container_context_2 = (CLFS_CONTAINER_CONTEXT *__shifted(_CLFSHASHSYM,0x30))CClfsBaseFile::OffsetToAddr(\r\n                                                                                    this,\r\n                                                                                    offset);\r\n      if ( !container_context_2 )\r\n        goto error;\r\n      v40 = (CLFS_CONTAINER_CONTEXT *)CClfsBaseFile::OffsetToAddr(this, ADJ(container_context_2)-&gt;cbSymName);\r\n      v41 = v40;\r\n      if ( !v40 )\r\n[...]\r\n      }\r\n      j_1 = (_CClfsContainer *)pcbContainer;\r\n      containerContext = container_context;\r\n[...]\r\n if ( (containerContext-&gt;eState &amp; ClfsContainerInitializing) != 0 )\r\n        {\r\n          containerContext-&gt;eState = ClfsContainerInactive;\r\n          ret = CClfsBaseFilePersisted::FlushImage(this);\r\n          ret_2 = ret;\r\n          if ( ret &lt; 0 )\r\n            goto LABEL_116;\r\n        }\r\n        v57 = &amp;a2[containerContext-&gt;cidQueue &amp; 0x3FF];\r\n        if ( *v57 != -1 )\r\n        {\r\nLABEL_118:\r\n          ret = 0xC01A000D;\r\n          ret_2 = 0xC01A000D;\r\nLABEL_116:\r\n          ((void (__fastcall *)(_CClfsContainer *))containerContext-&gt;pContainer-&gt;vftbl_0_00000001C0014040-&gt;CClfsContainer::Release(void))(containerContext-&gt;pContainer);\r\n          containerContext-&gt;pContainer = 0LL;\r\n          v19 = a8;\r\n          v13 = a7;\r\n          v9 = a2;\r\n          goto LABEL_145;\r\n[...]\r\n  }\r\n[...]\r\n}<\/pre>\n<p>The routine starts looping over the offsets in <em>_CLFS_BASE_RECORD_HEADER.rgContainers<\/em>. For each of them, it retrieves a pointer to the associated <em>CLFS_CONTAINER_CONTEXT <\/em>(<em>containerContext<\/em> variable in the pseudocode).<\/p>\n<p><strong>containerContext will point to the CLFS_CONTAINER_CONTEXT structure inside the block at <em>CClfsBaseFilePersisted-&gt;m_rgBlocks[2].pbImage.<\/em><\/strong><\/p>\n<p>In case <em>containerContext-&gt;eState<\/em> is <em>ClfsContainerInitializing<\/em>, it calls <em>CClfsBaseFilePersisted::FlushImage()<\/em>\u00a0and in case it <strong>fails<\/strong>, then calls method <em>CClfsContainer::Release()<\/em> of <em>containerContext-&gt;pContainer<\/em>.<\/p>\n<p>The pseudocode of <em>FlushImage()<\/em> follows.\u00a0 Notice it tries to write to disk the <em>General Metadata Block<\/em> using <em>CClfsBaseFilePersisted::WriteMetadataBlock()\u00a0<\/em>and in case it <strong>fails<\/strong> it directly returns the error:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">__int64 __fastcall CClfsBaseFilePersisted::FlushImage(_CClfsBaseFilePersisted *this)\r\n{\r\n  char v2; \/\/ dl\r\n  char v3; \/\/ si\r\n  int v4; \/\/ edi\r\n  unsigned int v6; \/\/ [rsp+30h] [rbp-18h]\r\n\r\n  v2 = 1;\r\n  v3 = ((__int64 (__fastcall *)(__int64, char))nt_ExAcquireResourceExclusiveLite)(this-&gt;m_presImage, v2);\r\n  v4 = CClfsBaseFilePersisted::WriteMetadataBlock(this, ClfsMetaBlockGeneral, 1);\r\n  v6 = v4;\r\n  if ( v4 &gt;= 0 )\r\n[...]\r\nreturn v4;\r\n}<\/pre>\n<h3>CClfsBaseFilePersisted::WriteMetadataBlock()<\/h3>\n<p>The partial pseudocode of <em>WriteMetadataBlock<\/em> follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">_int64 __fastcall CClfsBaseFilePersisted::WriteMetadataBlock(\r\n        _CClfsBaseFilePersisted *this,\r\n        enum _CLFS_METADATA_BLOCK_TYPE blocktype,\r\n        char a3)\r\n{\r\n  [...]\r\n  blockType_1 = (unsigned int)blocktype;\r\n  pbImage = (CLFS_LOG_BLOCK_HEADER *)this-&gt;m_rgBlocks[blockType_1].pbImage;\r\n  v27 = pbImage;\r\n  if ( !pbImage )\r\n  {\r\n    ret = 0xC01A000D;\r\n    ret_1 = 0xC01A000D;\r\n    goto LABEL_23;\r\n  }\r\n  pbImagenotnull = 1;\r\n  recordOffset = pbImage-&gt;RecordOffsets[0];\r\n  v11 = ++*(_QWORD *)(&amp;pbImage-&gt;MajorVersion + recordOffset) &amp; 1LL;\r\n  m_rgBlocks = this-&gt;m_rgBlocks;\r\n  [...]\r\nLABEL_9:\r\n  if ( v11 )\r\n    ++pbImage-&gt;Usn;\r\n  container_idx = 0;\r\n[...]\r\n while ( container_idx &lt; MAX_CONTAINERS_DEFAULT )\r\n  {\r\n    ret_1 = CClfsBaseFile::AcquireContainerContext(this, container_idx, &amp;containercontext);\r\n    v15 = &amp;this-&gt;vftbl_0_00000001C0014000 + container_idx;\r\n    if ( ret_1 &gt;= 0 )\r\n    {\r\n      containercontext_1 = containercontext;\r\n      v15[56] = (_CClfsBaseFilePersisted_VTABLE_0_00000001C0014000::vtable *)containercontext-&gt;pContainer;\r\n      containercontext_1-&gt;pContainer = 0LL;\r\n      CClfsBaseFile::ReleaseContainerContext(this, &amp;containercontext);\r\n    }\r\n    else\r\n    {\r\n      v15[56] = 0LL;\r\n    }\r\n    v25 = ++container_idx;\r\n  }\r\n[...]\r\nret = ClfsEncodeBlock(pbImage, pbImage-&gt;TotalSectorCount &lt;&lt; 9, pbImage-&gt;Usn, 0x10u, 1u);\r\n  ret_1 = ret;\r\nif ( ret &gt;= 0 )\r\n  {\r\n    encodeBlock_successul = 1;\r\n    ret = CClfsContainer::WriteSector(\r\n            (_CClfsContainer *)this-&gt;pCclfsContainer,\r\n            (PRKEVENT)this-&gt;event_a0,\r\n            0LL,\r\n            this-&gt;m_rgBlocks[blockType].pbImage,\r\n            pbImage-&gt;TotalSectorCount,\r\n            &amp;a6);\r\n    ret_1 = ret;\r\n[...]\r\n if ( pbImagenotnull )\r\n  {\r\n    if ( encodeBlock_successul )\r\n    {\r\n      v17 = ClfsDecodeBlock(pbImage, pbImage-&gt;TotalSectorCount, pbImage-&gt;Usn, 0x10u, (unsigned int *)&amp;a6);\r\n      if ( v17 &lt; 0 ){\r\n            CClfsBaseFile::ReleaseMetadataBlock(this, (enum _CLFS_METADATA_BLOCK_TYPE)blockType_1);\r\n       }\r\n[...]\r\n<\/pre>\n<p>Here are the important things to notice about this code:<\/p>\n<ol>\n<li>It increments<em>\u00a0_CLFS_METADATA_RECORD_HEADER.ullDumpCount<\/em> <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">v11 = ++*(_QWORD *)(&amp;pbImage-&gt;MajorVersion + recordOffset) &amp; 1LL;<\/code>, checks if it is even or odd and stores the result in v11.<\/li>\n<li>If the result is odd (v11 == 1), it updates the Usn field of the metadata block <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">++pbImage-&gt;Usn;<\/code>.<\/li>\n<li>It loops over containers and for each of them it sets the <strong><em>CLFS_CONTAINER_CONTEXT.pContainer\u00a0<\/em>field to 0<\/strong> (as in memory it is a kernel pointer to a <em>CClfsContainer<\/em> object).<\/li>\n<li>Calls <em>ClfsEncodeBlock()\u00a0<\/em>and if successful then writes the metadata block to the .BLF file calling <em>CClfsContainer::WriteSector()<\/em> and finally calls <em>ClfsDecodeBlock()<\/em>.<\/li>\n<li>If <em>ClfsDecodeBlock()\u00a0<\/em><strong>fails i<\/strong>t calls <strong><em>CClfsBaseFile::ReleaseMetadataBlock()<\/em><\/strong><em>.<\/em><\/li>\n<\/ol>\n<p>Let&#8217;s now inspect <em>CClfsBaseFile::ReleaseMetadataBlock()<\/em>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">\u00a0PUCHAR *__fastcall CClfsBaseFile::ReleaseMetadataBlock(\r\n        _CClfsBaseFilePersisted *this,\r\n        enum _CLFS_METADATA_BLOCK_TYPE blocktype)\r\n{\r\n  __int64 blocktype_1; \/\/ rbx\r\n  PUSHORT m_rgcBlockReferences; \/\/ rcx\r\n  PUCHAR *ptr; \/\/ rax\r\n\r\n  blocktype_1 = blocktype;\r\n  m_rgcBlockReferences = this-&gt;m_rgcBlockReferences;\r\n  ptr = (PUCHAR *)m_rgcBlockReferences[blocktype];\r\n  if ( (_WORD)ptr )\r\n  {\r\n    m_rgcBlockReferences[blocktype] = (_WORD)ptr - 1;\r\n    ptr = (PUCHAR *)this-&gt;m_rgcBlockReferences;\r\n    if ( !*((_WORD *)ptr + (int)blocktype) )\r\n    {\r\n      if ( this-&gt;m_rgBlocks[blocktype].pbImage )\r\n        ((void (__fastcall *)(_CClfsBaseFilePersisted *))this-&gt;vftbl_0_00000001C0014000-&gt;CClfsBaseFile::FreeMetadataBlock(uchar *))(this);\r\n      this-&gt;m_rgBlocks[blocktype_1].pbImage = 0LL;\r\n      ptr = &amp;this-&gt;m_rgBlocks-&gt;pbImage;\r\n      ptr[3 * blocktype_1 + 3] = 0LL;\r\n    }\r\n  }\r\n  return ptr;\r\n}<\/pre>\n<p>It decrements the block reference count in the <em>CClfsBaseFilePersisted-&gt;m_rgcBlockReferences\u00a0<\/em>array and in case it goes to zero it frees the block.<\/p>\n<h3>Vulnerable Scenario<\/h3>\n<p>Let&#8217;s suppose the following scenario:<\/p>\n<ol>\n<li>The execution path follows <em>LoadContainerQ()-&gt;FlushImage()-&gt;WriteMetadataBlock()\u00a0<\/em>writing the General Metadata Block.<\/li>\n<li>Inside <em>WriteMetadataBock()\u00a0<\/em>all <em>CLFS_CONTAINER_CONTEXT.pContainer<\/em> will be set to 0 and the final call to <em>ClfsDecodeBlock() <\/em><strong>fails\u00a0<\/strong>and so it <strong>frees<\/strong> the block with <em>ReleaseMetadataBlock()<\/em>.<\/li>\n<li>When returning from <em>FlushImage()\u00a0<\/em>there is <strong>no check that the General Metadata Block<\/strong> was freed due to a fail of <em>ClfsDecodeBlock().\u00a0<\/em><\/li>\n<\/ol>\n<p>Therefore the <strong>containerContext-&gt;pContainer<\/strong> of <em>LoadContainerQ()<\/em> will potential point to <strong>invalid memory<\/strong> as it belongs to the <strong>memory region freed<\/strong> by <em>ReleaseMetadataBlock()<\/em>.<\/p>\n<p>In case the freed memory region is not reallocated, <strong>containerContext-&gt;pContainer should point to a controllable invalid address <\/strong>(<em>WriteMatadataBlock()\u00a0<\/em>at step 2 sets to 0 all <em>CLFS_CONTAINER_CONTEXT.pContainer <\/em>fields<em>).<\/em><\/p>\n<p>For successful exploitation, it is required to to make <em>ClfsEncodeBlock()<\/em> <strong>succeed<\/strong>\u00a0and at the same time <em>ClfsDecodeBlock()<\/em> <strong>fail<\/strong>\u00a0<em>.\u00a0<\/em><\/p>\n<h3>ClfsEncodeBlock()\/ClfsDecodeBlock()<\/h3>\n<p>The pseudocode of <em>ClfsDecodeBlock()<\/em>\u00a0is:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">__int64 __fastcall ClfsDecodeBlock(\r\n        struct _CLFS_LOG_BLOCK_HEADER *logBlockHeader,\r\n        unsigned int n_sectors,\r\n        char usn,\r\n        unsigned __int8 a4,\r\n        unsigned int *a5)\r\n{\r\n[..]\r\n\r\n  Checksum = logBlockHeader-&gt;Checksum;\r\n  if ( Checksum )\r\n  {\r\n    if ( Checksum != -1 )\r\n    {\r\n      logBlockHeader-&gt;Checksum = 0;\r\n      v9 = CCrc32::ComputeCrc32(&amp;logBlockHeader-&gt;MajorVersion, n_sectors &lt;&lt; 9);\r\n      if ( v10 == v9 )\r\n        return ClfsDecodeBlockPrivate(logBlockHeader, n_sectors, usn, a4, a5);\r\n      logBlockHeader-&gt;Checksum = v10;\r\n    }\r\n  }\r\n  [...]\r\n}<\/pre>\n<p>It first checks the checksum (i.e., a CRC32 of the whole MetadataBlock) and then calls <em>ClfsDecodeBlockPrivate()<\/em>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">__int64 __fastcall ClfsDecodeBlockPrivate(\r\n        _CLFS_LOG_BLOCK_HEADER *blockHeader,\r\n        unsigned int n_sectors,\r\n        char usn,\r\n        unsigned __int8 flags,\r\n        unsigned int *a5)\r\n{\r\n [...]\r\n  if ( !n_sectors )\r\n    return 0xC000000DLL;\r\n  if ( blockHeader-&gt;MajorVersion != 0x15 || blockHeader-&gt;MinorVersion )\r\n    return 0xC01A0009LL;\r\n  if ( n_sectors &lt; blockHeader-&gt;TotalSectorCount )\r\n    return 0xC01A000ALL;\r\n  if ( flags &gt; 0x10u )\r\n    return 0xC000000DLL;\r\n  v9 = 0x10111;\r\n  if ( !_bittest(&amp;v9, flags) )\r\n    return 0xC000000DLL;\r\n  if ( (blockHeader-&gt;Flags &amp; 1) == 0 )\r\n    return 0xC01A000ALL;\r\n  SignatureOffset = blockHeader-&gt;SignaturesOffset;\r\n  block_size = n_sectors &lt;&lt; 9;\r\n  offset_to_end_of_signatures = SignatureOffset + 2 * n_sectors;\r\n  signatures_array = &amp;blockHeader-&gt;MajorVersion + SignatureOffset;\r\n  if ( offset_to_end_of_signatures &lt; (unsigned int)SignatureOffset\r\n    || (SignatureOffset &amp; 7) != 0\r\n    || offset_to_end_of_signatures &gt; block_size )\r\n  {\r\n    return 0xC01A000ALL;\r\n  }\r\n  n_sectors_1 = n_sectors;\r\n  while ( 1 )\r\n  {\r\n    v15 = n_sectors == n_sectors_1;\r\n    *(_QWORD *)&amp;i = (unsigned int)(n_sectors_1 - 1);\r\n    sector_block_begin = SECTOR_BLOCK_BEGIN;\r\n    sector_block_end = SECTOR_BLOCK_END;\r\n    if ( !v15 )\r\n      sector_block_end = 0;\r\n    if ( i )\r\n      sector_block_begin = 0;\r\n    sector_block_flags = flags | sector_block_begin | sector_block_end;\r\n    offset_start_block = (unsigned int)(i &lt;&lt; 9);\r\n    currentsector_blocktype = *((_BYTE *)&amp;blockHeader[4].RecordOffsets[5] + offset_start_block + 2);\r\n    if ( currentsector_blocktype &lt; 0 )\r\n      break;\r\n    if ( *((_BYTE *)&amp;blockHeader[4].RecordOffsets[5] + offset_start_block + 3) != usn )\r\n    {\r\n      result = 0xC01A0002LL;\r\n      goto LABEL_38;\r\n    }\r\n    if ( (sector_block_flags &amp; SECTOR_BLOCK_DATA) != 0 &amp;&amp; (currentsector_blocktype &amp; SECTOR_BLOCK_DATA) == 0\r\n      || (sector_block_flags &amp; SECTOR_BLOCK_BEGIN) != 0 &amp;&amp; (currentsector_blocktype &amp; SECTOR_BLOCK_BEGIN) == 0\r\n      || (sector_block_flags &amp; SECTOR_BLOCK_END) != 0 &amp;&amp; (currentsector_blocktype &amp; SECTOR_BLOCK_END) == 0\r\n      || (sector_block_flags &amp; SECTOR_BLOCK_OWNER) != 0 &amp;&amp; (currentsector_blocktype &amp; SECTOR_BLOCK_OWNER) == 0\r\n      || (sector_block_flags &amp; SECTOR_BLOCK_BASE) != 0 &amp;&amp; (currentsector_blocktype &amp; SECTOR_BLOCK_BASE) == 0 )\r\n    {\r\n      result = 0xC01A0001LL;\r\n      goto LABEL_38;\r\n    }\r\n    *(_WORD *)((char *)&amp;blockHeader[4].RecordOffsets[5] + offset_start_block + 2) = *(_WORD *)&amp;signatures_array[2 * *(_QWORD *)&amp;i];\r\n    n_sectors_1 = i;\r\n   [...]\r\n}<\/pre>\n<p><em>ClfsDecodeBlockPrivate()<\/em>\u00a0first checks multiple fields such as <em>MinorVersion, MajorVersion, TotalSectorCount<\/em> of <em>CLFS_LOG_BLOCK_HEADER.<\/em><\/p>\n<p>In the while loop, it checks that every signature (at the end of each sector 0x200 bytes wide) is valid.<\/p>\n<p>Therefore, the second byte matches with the <em>Usn<\/em> and first byte (sector block type) has the bits properly set according to the following constants (taken directly from Alex Ionescu&#8217;s unofficial documentation):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">const UCHAR SECTOR_BLOCK_NONE   = 0x00;\r\nconst UCHAR SECTOR_BLOCK_DATA   = 0x04;\r\nconst UCHAR SECTOR_BLOCK_OWNER  = 0x08;\r\nconst UCHAR SECTOR_BLOCK_BASE   = 0x10;\r\n\r\nconst UCHAR SECTOR_BLOCK_END    = 0x20;\r\nconst UCHAR SECTOR_BLOCK_BEGIN  = 0x40;<\/pre>\n<p><strong>Every signature, after the check, is replaced with the actual content in the signature array at offset <em>SignaturesOffset.<\/em><\/strong><\/p>\n<p>Find below the pseudocode of <em>ClfsEncodeBlock()<\/em>. Internally, it calls <em>ClfsEncodeBlockPrivate() <\/em>to encode the block and later computes the checksum with <em>CCrc32::ComputeCrc32()<\/em>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">__int64 __fastcall ClfsEncodeBlock(\r\n        struct _CLFS_LOG_BLOCK_HEADER *a1,\r\n        unsigned int size,\r\n        unsigned __int8 usn,\r\n        unsigned __int8 flags,\r\n        unsigned __int8 needchecksum)\r\n{\r\n [...]\r\n  a1-&gt;Checksum = 0;\r\n  v7 = ClfsEncodeBlockPrivate(a1, size, usn, flags);\r\n  if ( v7 &gt;= 0 &amp;&amp; needchecksum )\r\n    a1-&gt;Checksum = CCrc32::ComputeCrc32(&amp;a1-&gt;MajorVersion, size);\r\n  return (unsigned int)v7;\r\n}<\/pre>\n<p><em>ClfsEncodeBlockPrivate()<\/em>\u00a0does the following:<\/p>\n<ol>\n<li>It checks again some fields like <em>TotalSectorCount.<\/em><\/li>\n<li>It checks that <em>SignaturesOffset<\/em> is 8-bytes aligned.<\/li>\n<li>It loops over all the sector signatures, copies the original value in the Signatures array at <em>SignaturesOffset\u00a0<\/em>and writes the sector signature.<\/li>\n<\/ol>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"monokai\">__int64 __fastcall ClfsEncodeBlockPrivate(\r\n        struct _CLFS_LOG_BLOCK_HEADER *blockHeader,\r\n        unsigned int size,\r\n        UCHAR usn,\r\n        unsigned __int8 flags)\r\n{\r\n[...]\r\n\r\n  TotalSectorCount = blockHeader-&gt;TotalSectorCount;\r\n  if ( !(_WORD)TotalSectorCount\r\n    || blockHeader-&gt;ValidSectorCount &lt; (unsigned __int16)TotalSectorCount\r\n    || TotalSectorCount &lt;&lt; 9 &gt; size )\r\n  {\r\n    return 0xC01A000ALL;\r\n  }\r\n  if ( flags &gt; 0x10u )\r\n    return 0xC000000DLL;\r\n  v6 = 0x10111;\r\n  if ( !_bittest(&amp;v6, flags) )\r\n    return 0xC000000DLL;\r\n  if ( (blockHeader-&gt;Flags &amp; 1) != 0 )\r\n    return 0xC01A000ALL;\r\n  SignaturesOffset = blockHeader-&gt;SignaturesOffset;\r\n  n_sectors = size &gt;&gt; 9;\r\n  blockHeader-&gt;Usn = usn;\r\n  HIBYTE(usn_1) = usn;\r\n  signatures_array = &amp;blockHeader-&gt;MajorVersion + SignaturesOffset;\r\n  offset_to_end_of_signatures = SignaturesOffset + 2 * (size &gt;&gt; 9);\r\n  if ( offset_to_end_of_signatures &lt; (unsigned int)SignaturesOffset\r\n    || (SignaturesOffset &amp; 7) != 0\r\n    || offset_to_end_of_signatures &gt; size )\r\n  {\r\n    return 0xC01A000ALL;\r\n  }\r\n  for ( i = 0; i &lt; n_sectors; *(_WORD *)((char *)&amp;blockHeader[4].RecordOffsets[5] + (unsigned int)v14 + 2) = usn_1 )\r\n  {\r\n   [...]\r\n    *(_WORD *)signatures_array = *(_WORD *)((char *)&amp;blockHeader[4].RecordOffsets[5] + v14 + 2);\r\n    signatures_array += 2;\r\n  }\r\n[...]\r\n}<\/pre>\n<p>The SignaturesOffset typically <strong><em>should<\/em><\/strong> point to an <strong>array<\/strong> that is <strong>in the last sector<\/strong> and <strong>doesn&#8217;t<\/strong> have to<strong> overlap<\/strong> with the last <strong>sector&#8217;s signature<\/strong>. However, this is <strong>not enforced<\/strong>.<\/p>\n<p>In fact, the idea to make <em>ClfsDecodeBlock() <\/em>fail<em>,<\/em> right after <em>ClfsEncodeBlock()<\/em>, is the following:<\/p>\n<ol>\n<li>\u00a0Change the <strong><em>SignaturesOffset<\/em> <\/strong>so that the <strong>signatures array spans over two consecutive sectors, sector X and sector X+1 <\/strong>and therefore<strong> overlaps with signature of sector X.<\/strong><\/li>\n<li>Set the <em>CLFS_METADATA_RECORD_HEADER.ullDumpCount\u00a0<\/em>of the block to be <strong>even<\/strong>. This way, <em>WriteMetadataBlock()<\/em> will increment it by one and will <strong>increment the <em>CLFS_LOG_BLOCK_HEADER.Usn<\/em><\/strong><em>.<\/em><\/li>\n<\/ol>\n<p>At this point when <em>ClfsEncodeBlockPrivate() <\/em>finishes to write the signatures, a <strong>sector signature<\/strong> will be <strong>invalid<\/strong>. A metadata block after the return from <em>ClfsEncodeBlockPrivate()<\/em> is shown below:<\/p>\n<figure id=\"attachment_5010\" aria-describedby=\"caption-attachment-5010\" style=\"width: 1804px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"wp-image-5010 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-23_34_46-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-1.png\" alt=\"\" width=\"1804\" height=\"855\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-23_34_46-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-1.png 1804w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-23_34_46-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-1-300x142.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-23_34_46-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-1-1024x485.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-23_34_46-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-1-768x364.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-23_34_46-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-1-1536x728.png 1536w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-23_34_46-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-1-350x166.png 350w\" sizes=\"(max-width: 1804px) 100vw, 1804px\" \/><figcaption id=\"caption-attachment-5010\" class=\"wp-caption-text\">Beginning of a Metadata Block after ClfsEncodePrivate()<\/figcaption><\/figure>\n<p>Notice the <em>ullDumpCount<\/em> was initially 2 (an even value), that <em>WriteMetadataBlock()<\/em> incremented setting it to 3, and the <em>Usn<\/em> was set to 2. This means <em>every sector&#8217;s signature <\/em><strong>must have the second byte equal to 0x2<\/strong>. At the same time the <em>SignaturesOffset\u00a0<\/em>points to FFFFC380949E7480+0x03f8 = 0xFFFFC380949E7878.<\/p>\n<p>Also notice that the second sector signature (the one overlapping the signatures array) corresponds to 0x10 0x1 that is <strong>invalid <\/strong>as it should be 0x10 0x2 (since the <em>Usn\u00a0<\/em>is 0x2). This will cause <em>ClfsDecodeBlock()<\/em> to <strong>fail<\/strong>:<\/p>\n<figure id=\"attachment_5011\" aria-describedby=\"caption-attachment-5011\" style=\"width: 1750px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"wp-image-5011 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-23_46_04-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1.png\" alt=\"\" width=\"1750\" height=\"826\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-23_46_04-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1.png 1750w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-23_46_04-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-300x142.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-23_46_04-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-1024x483.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-23_46_04-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-768x362.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-23_46_04-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-1536x725.png 1536w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-21-23_46_04-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-350x165.png 350w\" sizes=\"(max-width: 1750px) 100vw, 1750px\" \/><figcaption id=\"caption-attachment-5011\" class=\"wp-caption-text\">Tampered section signature<\/figcaption><\/figure>\n<h3>Triggering the Vulnerability<\/h3>\n<p>In order to trigger the vulnerability, the PoC first calls <em>CreateLogFile()<\/em> and <em>AddContainer()<\/em> to create both files on disk.<\/p>\n<p>After that, it overwrites the generated base log file (BLF) with a malicious BLF (embedded as resource file in the exploit and retrieved through <em>FindResource()\/LoadResource()\/LockResource())<\/em> with the following characteristics:<\/p>\n<figure id=\"attachment_5016\" aria-describedby=\"caption-attachment-5016\" style=\"width: 541px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"wp-image-5016 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_11_31-ImHex-mylog.blf_.blf_.working_triggersgeneralblockshadow-1.png\" alt=\"\" width=\"541\" height=\"266\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_11_31-ImHex-mylog.blf_.blf_.working_triggersgeneralblockshadow-1.png 541w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_11_31-ImHex-mylog.blf_.blf_.working_triggersgeneralblockshadow-1-300x148.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_11_31-ImHex-mylog.blf_.blf_.working_triggersgeneralblockshadow-1-350x172.png 350w\" sizes=\"(max-width: 541px) 100vw, 541px\" \/><figcaption id=\"caption-attachment-5016\" class=\"wp-caption-text\">malicious BLF. Start of General Metadata Block<\/figcaption><\/figure>\n<figure id=\"attachment_5018\" aria-describedby=\"caption-attachment-5018\" style=\"width: 549px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"wp-image-5018 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_17_38-ImHex-mylog.blf_.blf_.working_triggersgeneralblockshadow-1-1.png\" alt=\"\" width=\"549\" height=\"518\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_17_38-ImHex-mylog.blf_.blf_.working_triggersgeneralblockshadow-1-1.png 549w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_17_38-ImHex-mylog.blf_.blf_.working_triggersgeneralblockshadow-1-1-300x283.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_17_38-ImHex-mylog.blf_.blf_.working_triggersgeneralblockshadow-1-1-350x330.png 350w\" sizes=\"(max-width: 549px) 100vw, 549px\" \/><figcaption id=\"caption-attachment-5018\" class=\"wp-caption-text\">Malicious BLF. CLFS_CONTAINER_CONTEXT and signatures array<\/figcaption><\/figure>\n<p>The <em>Usn<\/em> is set to 1 and the <em>ullDumpCount<\/em> is set to 2 (an <strong>even value<\/strong>). The <em>signaturesOffset<\/em> is changed so that the signatures array overlap one of the sector signatures (the red area at the bottom).<\/p>\n<p>In addition, the <em>CLFS_CONTAINER_CONTEXT<\/em> is shifted in a way that the <em><strong>pContainer<\/strong> <\/em>field <strong>overlap<\/strong> with another <strong>sector signature<\/strong>, and <em>eState\u00a0<\/em>is set to 1.<\/p>\n<p>It is necessary to update also all other offsets such as:<\/p>\n<ul>\n<li><em>cbSymbolZone.<\/em><\/li>\n<li>The offset in the <em>rgContainer\u00a0<\/em>array.<\/li>\n<li>The offset in the <em>rgContainerSymTbl array<\/em>.<\/li>\n<\/ul>\n<p>Finally, it is necessary to overwrite all signatures to match the <em>Usn\u00a0<\/em>and recompute the <strong>checksum<\/strong>.<\/p>\n<p>This Python script can be useful to compute the checksum (created by ChatGPT):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"monokai\">import binascii\r\n\r\ndef calculate_crc32(input_file):\r\n    \"\"\"\r\n    Reads a file containing hexadecimal numbers, calculates the CRC32 checksum\r\n    using the polynomial 0x04C11DB7, prints the buffer length in hexadecimal,\r\n    and displays the CRC32 checksum in both big-endian and little-endian formats.\r\n    \"\"\"\r\n    try:\r\n        # Read the input file\r\n        with open(input_file, \"r\") as file:\r\n            hex_data = file.read().strip()\r\n\r\n        # Convert hex string to bytes\r\n        hex_numbers = hex_data.split()\r\n        byte_array = bytes(int(num, 16) for num in hex_numbers)\r\n\r\n        # Calculate CRC32 using binascii\r\n        crc32_checksum = binascii.crc32(byte_array) &amp; 0xFFFFFFFF\r\n\r\n        # Calculate buffer length in hexadecimal\r\n        buffer_length = len(byte_array)\r\n\r\n        # Convert checksum to little-endian hex sequence\r\n        little_endian_hex = ' '.join(f\"{b:02X}\" for b in crc32_checksum.to_bytes(4, 'little'))\r\n\r\n        # Print the results\r\n        print(f\"Buffer Length (hex): 0x{buffer_length:02X}\")\r\n        print(f\"CRC32 Checksum (big-endian): 0x{crc32_checksum:08X}\")\r\n        print(f\"CRC32 Checksum (little-endian as hex sequence): {little_endian_hex}\")\r\n    except Exception as e:\r\n        print(f\"Error: {e}\")\r\n\r\n# Example usage\r\nif __name__ == \"__main__\":\r\n    input_file = \"hex_numbers.txt\"  # Replace with your input file path\r\n    calculate_crc32(input_file)\r\n<\/pre>\n<p>It would be enough to place inside the hex_numbers.txt file the hex numbers composing the metadata block (which can be extracted with ImHex or another hex editor).<\/p>\n<p>The PoC, after replacing the BLF on disk with the malicious one, calls again <em>CreateLogFile()\u00a0<\/em>and the execution reaches <em>LoadContainerQ()<\/em> and then <em>FlushImage():<\/em><\/p>\n<figure id=\"attachment_5021\" aria-describedby=\"caption-attachment-5021\" style=\"width: 1914px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"wp-image-5021 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_37_30-Clipboard-1-1.png\" alt=\"\" width=\"1914\" height=\"788\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_37_30-Clipboard-1-1.png 1914w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_37_30-Clipboard-1-1-300x124.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_37_30-Clipboard-1-1-1024x422.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_37_30-Clipboard-1-1-768x316.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_37_30-Clipboard-1-1-1536x632.png 1536w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_37_30-Clipboard-1-1-350x144.png 350w\" sizes=\"(max-width: 1914px) 100vw, 1914px\" \/><figcaption id=\"caption-attachment-5021\" class=\"wp-caption-text\">General Metadata Block before FlushImage() is valid<\/figcaption><\/figure>\n<p>Notice the reference count of the General Metadata Block is set to 1 meaning the block loaded in memory is valid.<\/p>\n<p>The execution flow continues reaching <em>WriteMetadataBlock()\u00a0<\/em>on the General Metadata Block, that internally calls\u00a0<em>ClfsEncodeBlock(). ClfsEncodeBlock()<\/em> will produce an invalid block and cause <em>ClfsDecodeBlock() <\/em>to fail and call <em>ReleaseMetadataBlock()<\/em>.<\/p>\n<p>Notice at this point that the <strong>pContainer field now has value 0x0000000002100000<\/strong>:<\/p>\n<figure id=\"attachment_5022\" aria-describedby=\"caption-attachment-5022\" style=\"width: 1894px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"wp-image-5022 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_49_30-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1.png\" alt=\"\" width=\"1894\" height=\"694\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_49_30-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1.png 1894w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_49_30-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-300x110.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_49_30-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-1024x375.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_49_30-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-768x281.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_49_30-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-1536x563.png 1536w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_49_30-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-350x128.png 350w\" sizes=\"(max-width: 1894px) 100vw, 1894px\" \/><figcaption id=\"caption-attachment-5022\" class=\"wp-caption-text\">General metadata block invalidated by ClfsEncodeBlock(). ClfsDecodeBlock() fails and reaches ReleaseMetadataBlock()<\/figcaption><\/figure>\n<p>After returning from <em>FlushImage(), <\/em>the reference count of the General Metadata Block is 0 and the corresponding <em>pbImage<\/em> pointer is also 0 confirming it was freed:<\/p>\n<figure id=\"attachment_5023\" aria-describedby=\"caption-attachment-5023\" style=\"width: 1787px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"wp-image-5023 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_54_30-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-2.png\" alt=\"\" width=\"1787\" height=\"646\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_54_30-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-2.png 1787w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_54_30-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-2-300x108.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_54_30-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-2-1024x370.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_54_30-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-2-768x278.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_54_30-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-2-1536x555.png 1536w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_54_30-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-2-350x127.png 350w\" sizes=\"(max-width: 1787px) 100vw, 1787px\" \/><figcaption id=\"caption-attachment-5023\" class=\"wp-caption-text\">General Metadata Block after FlushImage(). It is invalid and was freed by ReleaseMetadataBlock()<\/figcaption><\/figure>\n<p>Stepping through the instructions, the execution flow will <strong>load in RCX the tampered pContainer<\/strong>:<\/p>\n<figure id=\"attachment_5025\" aria-describedby=\"caption-attachment-5025\" style=\"width: 1712px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"wp-image-5025 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_58_26-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1.png\" alt=\"\" width=\"1712\" height=\"485\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_58_26-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1.png 1712w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_58_26-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-300x85.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_58_26-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-1024x290.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_58_26-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-768x218.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_58_26-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-1536x435.png 1536w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/2025-01-22-00_58_26-IDA-clfs.sys_.i64-clfs.sys-C__CVE-2024-49138_clfs.sys_.i64-1-350x99.png 350w\" sizes=\"(max-width: 1712px) 100vw, 1712px\" \/><figcaption id=\"caption-attachment-5025\" class=\"wp-caption-text\">RCX tampered. Execution flow can be hijacked<\/figcaption><\/figure>\n<p>The following instructions will <strong>store in RAX a value coming from [RCX]<\/strong> and then <strong>call RAX<\/strong> allowing to <strong>hijack the execution flow<\/strong> to an arbitrary kernel address.<\/p>\n<p><em>Note: If between the ReleaseMetadataBlock() and the mov RCX, [RDI+0x18] the memory region is <strong>reallocated<\/strong> and then <strong>overwritten<\/strong> with <strong>other data<\/strong>, the value stored in RCX will be <strong>random<\/strong> and may lead to a <strong>crash<\/strong>. <strong>Heap spraying<\/strong> may help deal with this scenario.<\/em><\/p>\n<h2>Exploitation<\/h2>\n<p>To summarize, here are the <strong>steps<\/strong> performed by the proof of concept <strong>exploit<\/strong> available <a href=\"https:\/\/github.com\/MrAle98\/CVE-2024-49138-POC\">here<\/a> (<em>master <\/em>branch):<\/p>\n<ol>\n<li>Call <em>CreateLogFile()\u00a0<\/em>and <em>AddLogContainer()\u00a0<\/em>to create the .BLF and the container files under <em>C:\\temp\\testlog.<\/em><\/li>\n<li>Fetch the malicious .BLF from the resources and overwrite the original .BLF with the malicious .BLF.<\/li>\n<li>Allocate memory at address <em><strong>0x0000000002100000<\/strong> (<\/em>stored in the variable <em>pcclfscontainer<\/em>).<\/li>\n<li>Create a fake <em>CClfsContainer<\/em> object with a fake vtable that points to the address of <em>nt!PoFxProcessorNotification.<\/em><\/li>\n<li>Write additional data in the allocated memory region such as the address of <em>nt!DbgkpTriageDumpRestoreState <\/em>and the address of _KTHREAD.PreviousMode of the current thread.<\/li>\n<li>Call again <em>CreateLogFile().<\/em><\/li>\n<\/ol>\n<p>When the PoC invokes <em>CreateLogFile() <\/em>on the malicious BLF the <strong>driver<\/strong> does the following:<\/p>\n<ol>\n<li>Dereference the malicious <em>CClfsContainer<\/em> object at address <em><strong>0x0000000002100000.<\/strong><\/em><\/li>\n<li>Call <em>nt!PoFxProcessorNotification.<\/em><\/li>\n<li><em>nt!PoFxProcessorNotification <\/em>redirects the execution flow to <em>nt!DbgkpTriageDumpRestoreState.<\/em><\/li>\n<li><em>nt!DbgkpTriageDumpRestoreState\u00a0<\/em>is used to obtain an <strong>arbitrary write of 8 bytes<\/strong> (already discussed <a href=\"https:\/\/hnsecurity.it\/from-arbitrary-pointer-dereference-to-arbitrary-read-write-in-latest-windows-11\/\">here<\/a>). In this case it is exploited to overwrite the <em>_KTHREAD.PreviousMode<\/em> to 0 of the current thread, granting us arbitrary read\/write primitives.<\/li>\n<\/ol>\n<p>At this point the PoC does the following:<\/p>\n<ol>\n<li>Issue a series of calls to <em>NtReadVirtualMemory()\/NtWriteVirtualMemory()\u00a0<\/em>to overwrite the <em>_EPROCESS.Token <\/em>of the current process with the system process (PID 4).<\/li>\n<li>Restore <em>_KTHREAD.PreviousMode<\/em>\u00a0to 1 with a final <em>NtWriteVirtualMemory()\u00a0<\/em>and finally spawn a cmd shell.<\/li>\n<\/ol>\n<figure id=\"attachment_5029\" aria-describedby=\"caption-attachment-5029\" style=\"width: 1642px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"wp-image-5029 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/systemshell-1.gif\" alt=\"\" width=\"1642\" height=\"859\" \/><figcaption id=\"caption-attachment-5029\" class=\"wp-caption-text\">Running POC and elevating privileges<\/figcaption><\/figure>\n<h2>Limitations and Improvements<\/h2>\n<p>The exploit retrieves the kernel address of <em>_KTHREAD\u00a0<\/em>using <em>NtQuerySystemInformation().<\/em> Starting from Windows 11 24h2, to access this API <strong>the user must have the SeDebugPrivilege<\/strong> (meaning they must be an Administrator).<\/p>\n<p>As already outlined, if between the free and the loading of the tampered <em>pContainer\u00a0<\/em>in RCX the memory region is reallocated and overwritten with other data, then exploitation may fail. Maybe this can be addressed using heap spraying.<\/p>\n<p>The <em>PreviousMode<\/em> technique was mitigated by Microsoft starting from Windows 11 24h2. Attackers can still use other techniques to grant themselves read\/write in kernel-land (<a href=\"https:\/\/windows-internals.com\/one-i-o-ring-to-rule-them-all-a-full-read-write-exploit-primitive-on-windows-11\/\">I\/O Ring<\/a> for example).<\/p>\n<p>Hardcoded offsets should be replaced with hash-based search in ntoskrnl.exe for <em>nt!PoFxProcessorNotification\u00a0<\/em>and <em>nt!DbgkpTriageDumpRestoreState.\u00a0<\/em>Otherwise, offsets may be fetched by PDB symbol server passing as input the ntoskrnl.exe file hash.<\/p>\n<p>After the vulnerability is exploited, it is recommended to <strong>clean up the state in memory<\/strong> (container1 cannot be deleted) and then delete the container and the BLF file. For this purpose, the <a href=\"https:\/\/github.com\/Cr4sh\/KernelForge\">KernelForge<\/a> project may be useful to call arbitrary APIs in kernel mode from user mode having an arbitrary read\/write.<\/p>\n<h2>Patch Analysis<\/h2>\n<p>The screenshot below highlights the patch applied by Microsoft to <em><strong>LoadContainerQ()<\/strong><\/em>:<\/p>\n<figure id=\"attachment_5142\" aria-describedby=\"caption-attachment-5142\" style=\"width: 1785px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"wp-image-5142 size-full\" src=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/patch_loadcont-1.png\" alt=\"\" width=\"1785\" height=\"628\" srcset=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/patch_loadcont-1.png 1785w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/patch_loadcont-1-300x106.png 300w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/patch_loadcont-1-1024x360.png 1024w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/patch_loadcont-1-768x270.png 768w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/patch_loadcont-1-1536x540.png 1536w, https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/01\/patch_loadcont-1-350x123.png 350w\" sizes=\"(max-width: 1785px) 100vw, 1785px\" \/><figcaption id=\"caption-attachment-5142\" class=\"wp-caption-text\">LoadContainerQ before and after patch<\/figcaption><\/figure>\n<p>The address of <em>pContainer <\/em>is\u00a0copied in <em>v58\u00a0<\/em><strong>before<\/strong> calling <em>FlushImage()<\/em>, <strong>before<\/strong> the attacker can tamper <em>pContainer.\u00a0<\/em>After <em>FlushImage()\u00a0<\/em>fails, the program performs a call to <em>CClfsContainer::Release(v58).\u00a0<\/em>This time <em>v58\u00a0<\/em>points to a valid instance of <em>CClfsContainer<\/em>, therefore it not possible anymore to hijack the execution flow tampering the General Metadata Block.<\/p>\n<h2>Conclusions<\/h2>\n<p>Initially, the article provided some background information on the <strong>Common Log File System<\/strong> focusing on the data structure of a <strong>Base Log File<\/strong>. Later it analyzed the <strong>vulnerability<\/strong> in <em>LoadContainerQ()\u00a0<\/em>and described how to <strong>exploit<\/strong> it in a Windows 11 23H2 environment.<\/p>\n<p>Finally, it highlighted limitations and proposed improvements to the PoC and analyzed the patch applied by Microsoft.<\/p>\n<p><a href=\"https:\/\/hnsecurity.it\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-2\">Part 2<\/a> will <strong>analyze the other vulnerability<\/strong>, this time in <em>WriteMetadataBlock()<\/em>, that similarly to this one, allows again to hijack the execution flow and escalate privileges on Windows systems.<\/p>\n<h2>References<\/h2>\n<ul>\n<li><a href=\"https:\/\/github.com\/ionescu007\/clfs-docs\">https:\/\/github.com\/ionescu007\/clfs-docs<\/a><\/li>\n<li><a href=\"https:\/\/securelist.com\/windows-clfs-exploits-ransomware\/111560\/\">https:\/\/securelist.com\/windows-clfs-exploits-ransomware\/111560\/<\/a><\/li>\n<li><a href=\"https:\/\/blog.exodusintel.com\/2022\/03\/10\/exploiting-a-use-after-free-in-windows-common-logging-file-system-clfs\/\">https:\/\/blog.exodusintel.com\/2022\/03\/10\/exploiting-a-use-after-free-in-windows-common-logging-file-system-clfs\/<\/a><\/li>\n<li><a href=\"https:\/\/ti.qianxin.com\/blog\/articles\/CVE-2023-28252-Analysis-of-In-the-Wild-Exploit-Sample-of-CLFS-Privilege-Escalation-Vulnerability\/\">https:\/\/ti.qianxin.com\/blog\/articles\/CVE-2023-28252-Analysis-of-In-the-Wild-Exploit-Sample-of-CLFS-Privilege-Escalation-Vulnerability\/<\/a><\/li>\n<\/ul>\n<h2>Contacts<\/h2>\n<p>If you have any questions, feel free to reach out at:<\/p>\n<ul>\n<li><a href=\"https:\/\/x.com\/MrAle_98\">X<\/a><\/li>\n<li><a href=\"https:\/\/www.linkedin.com\/in\/alessandro-iandoli-86a19b211\/\">Linkedin<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>CVE-2024-49138 is a Windows vulnerability detected by CrowdStrike as exploited in the wild. Microsoft patched the vulnerability on December 10th, [&hellip;]<\/p>\n","protected":false},"author":12,"featured_media":159961,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[78,81],"tags":[218,219,77,82,135,191,210],"class_list":["post-4929","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-exploits","category-vulnerabilities","tag-clfs","tag-cve-2024-49138","tag-exploit","tag-vulnerability-research","tag-windows","tag-red-teaming","tag-exploit-development"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.2 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>HN Security CVE-2024-49138 Windows CLFS heap-based buffer overflow analysis - Part 1<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/\" \/>\n<meta property=\"og:locale\" content=\"it_IT\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"HN Security CVE-2024-49138 Windows CLFS heap-based buffer overflow analysis - Part 1\" \/>\n<meta property=\"og:description\" content=\"CVE-2024-49138 is a Windows vulnerability detected by CrowdStrike as exploited in the wild. Microsoft patched the vulnerability on December 10th, [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/\" \/>\n<meta property=\"og:site_name\" content=\"HN Security\" \/>\n<meta property=\"article:published_time\" content=\"2025-01-29T08:32:27+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-09-15T13:16:33+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/WIN.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1600\" \/>\n\t<meta property=\"og:image:height\" content=\"836\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Alessandro Iandoli\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@hnsec\" \/>\n<meta name=\"twitter:site\" content=\"@hnsec\" \/>\n<meta name=\"twitter:label1\" content=\"Scritto da\" \/>\n\t<meta name=\"twitter:data1\" content=\"Alessandro Iandoli\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tempo di lettura stimato\" \/>\n\t<meta name=\"twitter:data2\" content=\"17 minuti\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/\"},\"author\":{\"name\":\"Alessandro Iandoli\",\"@id\":\"https:\/\/hnsecurity.it\/it\/#\/schema\/person\/7883a9c36dac7694ca101137125d5fff\"},\"headline\":\"CVE-2024-49138 Windows CLFS heap-based buffer overflow analysis &#8211; Part 1\",\"datePublished\":\"2025-01-29T08:32:27+00:00\",\"dateModified\":\"2025-09-15T13:16:33+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/\"},\"wordCount\":3187,\"publisher\":{\"@id\":\"https:\/\/hnsecurity.it\/it\/#organization\"},\"image\":{\"@id\":\"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/WIN.jpg\",\"keywords\":[\"clfs\",\"cve-2024-49138\",\"exploit\",\"vulnerability research\",\"windows\",\"red teaming\",\"exploit development\"],\"articleSection\":[\"Exploits\",\"Vulnerabilities\"],\"inLanguage\":\"it-IT\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/\",\"url\":\"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/\",\"name\":\"HN Security CVE-2024-49138 Windows CLFS heap-based buffer overflow analysis - Part 1\",\"isPartOf\":{\"@id\":\"https:\/\/hnsecurity.it\/it\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/WIN.jpg\",\"datePublished\":\"2025-01-29T08:32:27+00:00\",\"dateModified\":\"2025-09-15T13:16:33+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/#breadcrumb\"},\"inLanguage\":\"it-IT\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/#primaryimage\",\"url\":\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/WIN.jpg\",\"contentUrl\":\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/WIN.jpg\",\"width\":1600,\"height\":836,\"caption\":\"Microsoft logo\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/hnsecurity.it\/it\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"CVE-2024-49138 Windows CLFS heap-based buffer overflow analysis &#8211; Part 1\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/hnsecurity.it\/it\/#website\",\"url\":\"https:\/\/hnsecurity.it\/it\/\",\"name\":\"HN Security\",\"description\":\"Offensive Security Specialists\",\"publisher\":{\"@id\":\"https:\/\/hnsecurity.it\/it\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/hnsecurity.it\/it\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"it-IT\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/hnsecurity.it\/it\/#organization\",\"name\":\"HN Security\",\"url\":\"https:\/\/hnsecurity.it\/it\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\/\/hnsecurity.it\/it\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/01\/hn-libellula.jpg\",\"contentUrl\":\"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/01\/hn-libellula.jpg\",\"width\":696,\"height\":696,\"caption\":\"HN Security\"},\"image\":{\"@id\":\"https:\/\/hnsecurity.it\/it\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/hnsec\",\"https:\/\/www.linkedin.com\/company\/hnsecurity\/\",\"https:\/\/github.com\/hnsecurity\",\"https:\/\/infosec.exchange\/@hnsec\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/hnsecurity.it\/it\/#\/schema\/person\/7883a9c36dac7694ca101137125d5fff\",\"name\":\"Alessandro Iandoli\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/644822f5d8329ca419a50c1f39c97de5ccd163d1932e4cdc60a6cc8cb64ed29e?s=96&d=mm&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/644822f5d8329ca419a50c1f39c97de5ccd163d1932e4cdc60a6cc8cb64ed29e?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/644822f5d8329ca419a50c1f39c97de5ccd163d1932e4cdc60a6cc8cb64ed29e?s=96&d=mm&r=g\",\"caption\":\"Alessandro Iandoli\"},\"url\":\"https:\/\/hnsecurity.it\/it\/blog\/author\/ale98\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"HN Security CVE-2024-49138 Windows CLFS heap-based buffer overflow analysis - Part 1","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/","og_locale":"it_IT","og_type":"article","og_title":"HN Security CVE-2024-49138 Windows CLFS heap-based buffer overflow analysis - Part 1","og_description":"CVE-2024-49138 is a Windows vulnerability detected by CrowdStrike as exploited in the wild. Microsoft patched the vulnerability on December 10th, [&hellip;]","og_url":"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/","og_site_name":"HN Security","article_published_time":"2025-01-29T08:32:27+00:00","article_modified_time":"2025-09-15T13:16:33+00:00","og_image":[{"width":1600,"height":836,"url":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/WIN.jpg","type":"image\/jpeg"}],"author":"Alessandro Iandoli","twitter_card":"summary_large_image","twitter_creator":"@hnsec","twitter_site":"@hnsec","twitter_misc":{"Scritto da":"Alessandro Iandoli","Tempo di lettura stimato":"17 minuti"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/#article","isPartOf":{"@id":"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/"},"author":{"name":"Alessandro Iandoli","@id":"https:\/\/hnsecurity.it\/it\/#\/schema\/person\/7883a9c36dac7694ca101137125d5fff"},"headline":"CVE-2024-49138 Windows CLFS heap-based buffer overflow analysis &#8211; Part 1","datePublished":"2025-01-29T08:32:27+00:00","dateModified":"2025-09-15T13:16:33+00:00","mainEntityOfPage":{"@id":"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/"},"wordCount":3187,"publisher":{"@id":"https:\/\/hnsecurity.it\/it\/#organization"},"image":{"@id":"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/#primaryimage"},"thumbnailUrl":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/WIN.jpg","keywords":["clfs","cve-2024-49138","exploit","vulnerability research","windows","red teaming","exploit development"],"articleSection":["Exploits","Vulnerabilities"],"inLanguage":"it-IT"},{"@type":"WebPage","@id":"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/","url":"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/","name":"HN Security CVE-2024-49138 Windows CLFS heap-based buffer overflow analysis - Part 1","isPartOf":{"@id":"https:\/\/hnsecurity.it\/it\/#website"},"primaryImageOfPage":{"@id":"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/#primaryimage"},"image":{"@id":"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/#primaryimage"},"thumbnailUrl":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/WIN.jpg","datePublished":"2025-01-29T08:32:27+00:00","dateModified":"2025-09-15T13:16:33+00:00","breadcrumb":{"@id":"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/#breadcrumb"},"inLanguage":"it-IT","potentialAction":[{"@type":"ReadAction","target":["https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/"]}]},{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/#primaryimage","url":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/WIN.jpg","contentUrl":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/WIN.jpg","width":1600,"height":836,"caption":"Microsoft logo"},{"@type":"BreadcrumbList","@id":"https:\/\/hnsecurity.it\/it\/blog\/cve-2024-49138-windows-clfs-heap-based-buffer-overflow-analysis-part-1\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/hnsecurity.it\/it\/"},{"@type":"ListItem","position":2,"name":"CVE-2024-49138 Windows CLFS heap-based buffer overflow analysis &#8211; Part 1"}]},{"@type":"WebSite","@id":"https:\/\/hnsecurity.it\/it\/#website","url":"https:\/\/hnsecurity.it\/it\/","name":"HN Security","description":"Offensive Security Specialists","publisher":{"@id":"https:\/\/hnsecurity.it\/it\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/hnsecurity.it\/it\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"it-IT"},{"@type":"Organization","@id":"https:\/\/hnsecurity.it\/it\/#organization","name":"HN Security","url":"https:\/\/hnsecurity.it\/it\/","logo":{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/hnsecurity.it\/it\/#\/schema\/logo\/image\/","url":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/01\/hn-libellula.jpg","contentUrl":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2026\/01\/hn-libellula.jpg","width":696,"height":696,"caption":"HN Security"},"image":{"@id":"https:\/\/hnsecurity.it\/it\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/hnsec","https:\/\/www.linkedin.com\/company\/hnsecurity\/","https:\/\/github.com\/hnsecurity","https:\/\/infosec.exchange\/@hnsec"]},{"@type":"Person","@id":"https:\/\/hnsecurity.it\/it\/#\/schema\/person\/7883a9c36dac7694ca101137125d5fff","name":"Alessandro Iandoli","image":{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/secure.gravatar.com\/avatar\/644822f5d8329ca419a50c1f39c97de5ccd163d1932e4cdc60a6cc8cb64ed29e?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/644822f5d8329ca419a50c1f39c97de5ccd163d1932e4cdc60a6cc8cb64ed29e?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/644822f5d8329ca419a50c1f39c97de5ccd163d1932e4cdc60a6cc8cb64ed29e?s=96&d=mm&r=g","caption":"Alessandro Iandoli"},"url":"https:\/\/hnsecurity.it\/it\/blog\/author\/ale98\/"}]}},"jetpack_featured_media_url":"https:\/\/hnsecurity.it\/wp-content\/uploads\/2025\/09\/WIN.jpg","_links":{"self":[{"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/posts\/4929","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/users\/12"}],"replies":[{"embeddable":true,"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/comments?post=4929"}],"version-history":[{"count":1,"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/posts\/4929\/revisions"}],"predecessor-version":[{"id":160074,"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/posts\/4929\/revisions\/160074"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/media\/159961"}],"wp:attachment":[{"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/media?parent=4929"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/categories?post=4929"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hnsecurity.it\/it\/wp-json\/wp\/v2\/tags?post=4929"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}