CVE-2022-30220:Windows Common Log File System Driver 提权漏洞分析

admin 2022年7月20日13:56:57评论225 views字数 13791阅读45分58秒阅读模式

1. 漏洞说明

名称:Windows Common Log File System Driver 提权漏洞

简介:CLFS 驱动中存在堆越界写漏洞,利用该漏洞可以实现本地提权

影响版本:该漏洞影响所有受支持的 Windows 操作系统

编号:CVE-2022-30220

2. CLFS基础

注:以下所有涉及的数据结构根据参考资料整理得到,由于没有官方文档,所以可能存在未知或同名字段,但不影响此次漏洞分析。


2.1 概念

CLFS(Common Log File System) 是一个日志框架,其他应用程序可以通过 CLFS 创建、保存和读取日志数据。“日志(log)”既可以表示一个抽象的概念,也可以表示一个物理上的文件,CLFS 对一条日志以及保存它的物理存储空间做了区分,因此物理空间的管理和日志的管理是分开的。CLFS 通过使用流(stream)和容器(container)在 NTFS 之上构建了一个虚拟的抽象层。 

2.2 日志的存储


一个 CLFS 日志的存储由两部分组成:


  • 包含元数据(metadata)的 base log file(BLF) 

   BLF文件大小通常为 64KB,但是可以根据需要增长,其中包含了日志存储所需的一些元信息,例如日志的起始位置、容器的大小和路径、日志名称、客户端信息等。考虑到日志恢复的需要,BLF 文件中包含了一份元数据的拷贝,使用 dump count 参数来识别哪份信息是最新的。 


  • 最多 1023 个包含真正数据的容器文件

   容器是一个活动的日志流在空间上的基础分配单元,同一日志中的容器大小一致,是 512KB(一个扇区的大小)的倍数,最大为 4GB。CLFS 客户端通过增加和删除容器实现日志流的扩大和缩小。在实现时,CLFS 把容器当作 BLF 所在卷上的一个连续文件,通过在逻辑上将多个容器串在一起,形成包含一条日志的单个逻辑顺序磁盘区。初始化的时候一条日志至少要分配两个容器。 


可以把整个日志存储看作是文件系统中一个卷的概念


2.2.1 Log Blocks

CLFS 使用日志块对记录进行组织管理,每个日志块由多个 512 字节的扇区组成,之后对日志数据的读取和写入操作都在日志块上进行。


每个日志块的开头有一个 _CLFS_LOG_BLOCK_HEADER :

typedef struct _CLFS_LOG_BLOCK_HEADER{    UCHAR MajorVersion;    UCHAR MinorVersion;    UCHAR Usn;    UCHAR StreamNum;    USHORT TotalSectorCount;    USHORT ValidSectorCount;    ULONG Padding;    ULONG Checksum;    ULONG Flags;    ULONG Unknown2;    CLFS_LSN CurrentLsn;    CLFS_LSN NextLsn;    ULONG RecordOffsets[16];    ULONG SignaturesOffset;    ULONG Unknown3;} CLFS_LOG_BLOCK_HEADER;

 当日志写入硬盘的时候,日志块会进行编码,编码状态的日志块中,每个扇区结尾处有一个 2 字节的扇区签名(sector signature): 

[Sector Block Type][Usn]

由于在编码阶段每个扇区的最后两个字节被改写成了扇区签名,因此需要对原始数据进行备份。日志块的最后一个扇区结尾处,有一个签名数组,这个数组中就保存了原始数据,由 _CLFS_LOG_BLOCK_HEADER 中的 SignaturesOffset 表示。


在写入日志的时候,可以比较每个扇区结尾签名位置的数据是否和签名数组中的数据一致来判断写入是否成功

2.2.2 BLF文件


BLF 由六种不同的元数据块组成,每种元数据块只包含对应类型的数据,其中 shadow block 中保存的是对应元数据块的备份,同样使用 dump count 参数说明数据块的新旧。


  • Control Block:包含了有关布局(layout)、扩展(extend)区域以及截断(truncate)区域的信息


  • Base Block:包含了符号表信息,其中包括该BLF有关的客户端、容器和安全上下文信息


  • Truncate Block:包含了因为截断操作而需要对扇区进行更改的客户端信息,以及具体更改的扇区字节


  • Control Block Shadow


  • Base Block Shadow


  • Truncate Block Shadow


这里主要关注其中的 Control Block,这个日志块中的记录遵循以下数据结构:

typedef struct _CLFS_CONTROL_RECORD{    CLFS_METADATA_RECORD_HEADER hdrControlRecord;    ULONGLONG ullMagicValue;    ULONG Version;    CLFS_EXTEND_STATE eExtendState;    USHORT iExtendBlock;    USHORT iFlushBlock;    ULONG cNewBlockSectors;    ULONG cExtendStartSectors;    ULONG cExtendSectors;    CLFS_TRUNCATE_CONTEXT cxTruncate;    ULONG cBlocks;    ULONG cReserved;    CLFS_METADATA_BLOCK rgBlocks[6];} CLFS_CONTROL_RECORD;

其中的 cBlocks 表示整个文件中包含的日志块数量:

CVE-2022-30220:Windows Common Log File System Driver 提权漏洞分析


rgBlocks 中保存了每个日志块的大小信息:

typedef struct _CLFS_METADATA_BLOCK{    ULONGLONG pbImage;  // 指向内存中数据的指针,在BLF文件中为0    ULONG cbImage;    // 日志块大小    ULONG cbOffset;    // 偏移    CLFS_METADATA_BLOCK_TYPE eBlockType;    ULONG Padding; } CLFS_METADATA_BLOCK;


3. 补丁分析

对比 clfy.sys 文件发现只有 CClfsBaseFilePersisted::ReadImage 函数存在不同,仔细检查代码,发现修改主要位于 cBlocks > 6 的情况:

CVE-2022-30220:Windows Common Log File System Driver 提权漏洞分析


修复之后,如果 BLF 文件中 cBlocks 数值大于 6,ReadImage 函数会直接出错返回。

4. 漏洞分析

4.1 漏洞原理

根据补丁分析结果,我们生成一个 BLF 文件,并手动将 cBlocks 修改成一个较大值 0x19(后期调试发现大于等于 0x20 无法通过检查),加载 BLF 文件后,系统崩溃(需要多次测试)。


kd> gKDTARGET: Refreshing KD connectionKDTARGET: Refreshing KD connection
*** Fatal System Error: 0x00000050(0xFFFF800C3905118E,0x0000000000000000,0xFFFFF8006B2A8140,0x0000000000000000)
Driver at fault: *** CLFS.SYS - Address FFFFF8006B2A8140 base at FFFFF8006B2A0000, DateStamp 0c6e6b39.Break instruction exception - code 80000003 (first chance)
A fatal system error has occurred.Debugger entered on first try; Bugcheck callbacks have not been invoked.
A fatal system error has occurred.
nt!DbgBreakPointWithStatus:fffff800*6b804c70 cc int 3

查看此时的函数调用栈:

3: kd> kb# RetAddr               : Args to Child                                                           : Call Site00 fffff800*6b918032     : ffffa780*aec28ad0 fffff800*6b782480 fffff800*6b2a0000 00000000*00000000 : nt!DbgBreakPointWithStatus01 fffff800*6b917616     : fffff800*00000003 ffffa780*aec28ad0 fffff800*6b811d10 ffffa780*aec29020 : nt!KiBugCheckDebugBreak+0x1202 fffff800*6b7fced7     : 00000000*00000000 00000000*00000000 0000f288*00000000 ffff800c*3905118e : nt!KeBugCheck2+0x94603 fffff800*6b85352f     : 00000000*00000050 ffff800c*3905118e 00000000*00000000 ffffa780*aec293c0 : nt!KeBugCheckEx+0x10704 fffff800*6b6ab960     : ffffa780*aec29300 00000000*00000000 ffffa780*aec29440 00000000*00000000 : nt!MiSystemFault+0x189b7f05 fffff800*6b80af5e     : 00000000*00000000 00000000*00000000 00000000*00000000 00000000*00000001 : nt!MmAccessFault+0x40006 fffff800*6b2a8140     : 00000000*00000000 00000000*00000000 00000000*00000000 ffffb90d*58a5b0f0 : nt!KiPageFault+0x35e07 fffff800*6b2a802d     : 00000000*00004210 ffff800c*39050190 00000000*00000002 00000000*00848400 : CLFS!ClfsEncodeBlockPrivate+0xe008 fffff800*6b2eedff     : 00000000*00000000 00000000*00000200 00000000*00000200 ffff800c*373e5dd0 : CLFS!ClfsEncodeBlock+0x1d09 fffff800*6b2fa139     : ffff800c*38ba02a0 ffffb90d*00ffffff 00000000*00000200 ffffa881*ebebcfb0 : CLFS!CClfsBaseFileSnapshot::CopyImage+0xc30a fffff800*6b2f39a2     : ffffb90d*538672b0 00000000*00000200 ffffb90d*538672b0 ffffb90d*53867201 : CLFS!CClfsLogCcb::ReadArchiveMetadata+0x850b fffff800*6b2d0e82     : ffffb90d*53df89e0 00000000*00000000 ffffb90d*53dfae50 ffffb90d*53dfad80 : CLFS!CClfsRequest::ReadArchiveMetadata+0xfe0c fffff800*6b2d0987     : ffffb90d*53df89e0 fffff800*6b616131 ffffb90d*53552330 00000058*a7c00fb0 : CLFS!CClfsRequest::Dispatch+0x35e0d fffff800*6b2d08d7     : ffffb90d*53dfad80 ffffb90d*53dfad80 00000000*00000000 ffffdd00*2c53dff8 : CLFS!ClfsDispatchIoRequest+0x870e fffff800*6b653565     : ffffb90d*53dfad80 ffffb90d*5652ca10 00000000*00000021 ffffb90d*5253d080 : CLFS!CClfsDriver::LogIoDispatch+0x270f fffff800*6ba12b18     : ffffb90d*53dfad80 00000000*00000000 00000000*00000000 00000000*0000d55b : nt!IofCallDriver+0x5510 fffff800*6ba13af7     : 00000000*00000002 00000000*00000000 00000000*00000000 ffffa780*aec29b80 : nt!IopSynchronousServiceTail+0x1a811 fffff800*6ba12e76     : 00007ffa*7b746308 00000000*00000000 00000000*00000000 00000000*00000000 : nt!IopXxxControlFile+0xc6712 fffff800*6b80e7b5     : 00000000*00000000 00000000*00000000 00000000*00000000 00000000*00000000 : nt!NtDeviceIoControlFile+0x5613 00007ffa*800ece24     : 00007ffa*7da4b0bb 00000058*a7bfed64 00000000*00000000 00000000*00000078 : nt!KiSystemServiceCopyEnd+0x2514 00007ffa*7da4b0bb     : 00000058*a7bfed64 00000000*00000000 00000000*00000078 00000000*00000034 : ntdll!NtDeviceIoControlFile+0x1415 00000058*a7bfed64     : 00000000*00000000 00000000*00000078 00000000*00000034 00000058*a7bfeda0 : 0x00007ffa*7da4b0bb16 00000000*00000000     : 00000000*00000078 00000000*00000034 00000058*a7bfeda0 00000000*80076856 : 0x00000058*a7bfed64


可以看到异常发生在 CLFS!ClfsEncodeBlockPrivate 函数中,在 IDA 中查看该函数:

CVE-2022-30220:Windows Common Log File System Driver 提权漏洞分析


合理猜测,clfs.sys 在通过 BLF 文件获取到 Block 的数量之后并没有进行验证,而是直接使用该值对后面的空间进行读取。


为验证该猜测,我们跟随函数调用栈到达函数 CClfsBaseFileSnapshot::CopyImage ,从代码看这里在对堆块进行循环编码:

while ( idx < *(this + 20) && *a5 < size )   // *(this+20)保存了cBlocks{  blockHeader = *(*(this + 6) + 24 * idx);  ClfsEncodeBlock(blockHeader, blockHeader->TotalSectorCount << 9, blockHeader->Usn, 0x10u, 1u);  ...  idx = idx + 1;}

在这个函数设置断点并重新开始调试,当代码执行到循环判断时:

1: kd> rrax=0000000000000001 rbx=0000000000000000 rcx=ffff92816d5e8180rdx=0000000000000000 rsi=0000000000000200 rdi=0000000000000000rip=fffff8047537edb7 rsp=ffff8381808b35c0 rbp=0000000000000002 r8=0000000000000000  r9=ffff92816f707500 r10=0000000000000000r11=ffff8381808b3668 r12=0000000000000000 r13=ffffe60fcaf944a0r14=0000000000ffffff r15=ffff8381808b3738iopl=0         nv up ei ng nz na pe nccs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00040282CLFS!CClfsBaseFileSnapshot::CopyImage+0x7b:fffff804*7537edb7 410fb74528      movzx   eax,word ptr [r13+28h] ds:002b:ffffe60f*caf944c8=0019

这里在获取保存的 cBlocks 数值,可以看到系统在通过 ReadImage 读取 BLF 文件中存储的 cBlocks 数值之后,该数值并没有发生过更改,并直接在 CopyImage 中被使用。


4.2 越界写的位置与内容

现在已知漏洞是由于没有对 cBlocks 进行验证,但对于发生堆越界写时,写入的位置和内容还不清楚。


如果继续向下调试,到达获取 blockHeader 地址的位置:

2: kd> pCLFS!CClfsBaseFileSnapshot::CopyImage+0x9f:fffff804*7537eddb 488b3cc8        mov     rdi,qword ptr [rax+rcx*8]2: kd> rrax=ffffe60fc7415030 rbx=0000000000000000 rcx=0000000000000000rdx=0000000000000000 rsi=0000000000000200 rdi=0000000000000000rip=fffff8047537eddb rsp=ffff8381808b35c0 rbp=0000000000000002 r8=0000000000000000  r9=ffff92816f707500 r10=0000000000000000r11=ffff8381808b3668 r12=0000000000000000 r13=ffffe60fcaf944a0r14=0000000000ffffff r15=ffff8381808b3738iopl=0         nv up ei ng nz na po cycs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00040287CLFS!CClfsBaseFileSnapshot::CopyImage+0x9f:fffff804*7537eddb 488b3cc8        mov     rdi,qword ptr [rax+rcx*8] ds:002b:ffffe60f*c7415030=ffffe60fc86bbbb02: kd> dq ffffe60fc7415030ffffe60f*c7415030  ffffe60f*c86bbbb0 00000000*00000400ffffe60f*c7415040  00000000*00000000 ffffe60f*c86bbbb0ffffe60f*c7415050  00000400*00000400 00000000*00000001ffffe60f*c7415060  ffffe60f*cc319000 00000800*00007a00ffffe60f*c7415070  00000000*00000002 ffffe60f*cc319000ffffe60f*c7415080  00008200*00007a00 00000000*00000003ffffe60f*c7415090  ffffe60f*c8c43a10 0000fc00*00000200ffffe60f*c74150a0  00000000*00000004 ffffe60f*c8c43a10

可以看到地址 0xffffe60fc7415030 的位置存储了一个列表,根据数据内容判断,保存的就是 rgBlocks 信息。


在 CClfsBaseFilePersisted::ReadImage 函数中,如果 cBlocks 大于6,修复之前的函数会继续向下执行:

if ( cBlocks > 6u ){  pool1 = ExAllocatePoolWithTag(512, 24 * cBlocks, 'sflC');  // 分配大小为24*cBlocks的空间  pool2 = ExAllocatePoolWithTag(512, 2 * cBlocks, 'sflC');   // 分配大小为2*cBlocks的空间  if ( pool1 )  {    if ( pool2 )    {      memmove(pool1, *(this + 6), 24i64 * *(this + 20));      memmove(pool2_, *(this + 7), 2i64 * *(this + 20));      ExFreePoolWithTag(*(this + 6), 0);      ExFreePoolWithTag(*(this + 7), 0);      *(this + 20) = cBlocks;  // 注意保存的位置      *(this + 6) = pool1;      *(this + 7) = pool2;    }  }}for ( i = 0; i < cBlocks; ++i ){  controlRecord = *pControlRecord;  pool1 = *((_QWORD *)this + 6);  *(_OWORD *)(pool1_ + 24 * i) = *(_OWORD *)((char *)*pControlRecord + 24 * i + 0x50);// 从BLF文件中复制数据,rgBlocks  *(_QWORD *)(pool1_ + 24 * i + 16) = *((_QWORD *)controlRecord_ + 3 * i + 0xC);  *(_QWORD *)(*((_QWORD *)this + 6) + 8 * v15) = 0i64;}**(this + 6) = v13;                          // 第一个堆块的pbImage字段赋值*(*(this + 6) + 24i64) = v13;         // 第二个堆块的pbImage字段赋值

代码根据新的 cBlocks 数值分配了两个空间,大小为 24 x cBlocks 和 2 x cBlocks ,并分别放在了*(this+6)和*(this+7)的位置,除此之外还将 cBlocks 保存到了*(this+20)。之后将 BLF 文件中的 rgBlocks 列表复制到 pool1 所在空间,此时 pbImage 字段为 0。


但是 pool1 的地址并不是崩溃发生时 rgBlocks 列表所在的地址 0xffffe60fc7415030 ,因此在 ReadImage 中,this 指针指向的是一个 CClfsBaseFilePersisted 结构,而崩溃发生时,this 指针指向的是一个 CClfsBaseFileSnapshot 结构,*(this+6)中存储的空间地址并不相同。


根据结构名,找到函数 CClfsBaseFileSnapshot::InitializeSnapshot ,这里的 this 指针指向的同样是 CClfsBaseFileSnapshot 结构,同时发现了相同结构的一段代码:

if ( cBlocks ){  *(this + 6) = ExAllocatePoolWithTag(PagedPool, 24i64 * cBlocks, 'SflC');  pool2 = ExAllocatePoolWithTag(PagedPool, 2i64 * cBlocks, 'sflC');  *(this + 7) = pool2;  pool1 = *(this + 6);  if ( pool1 && pool2 )  {    memmove(pool1, *a3, 24i64 * cBlocks);    memset(pool2, 0, 2i64 * cBlocks);    for ( i = 0; i < cBlocks; ++i )  // 清空所有pbImage      *(*(this + 6) + 24i64 * i) = 0i64;    for ( j = 0; j < cBlocks; j += 2 )    {      *(*(this + 6) + 24i64 * j) = ExAllocatePoolWithTag(PagedPool, *(*(this + 6) + 24i64 * j + 8), 'sflC');// 根据cbImage字段分配空间,并赋值给pbImage      pool1_ = *(*(this + 6) + 24i64 * j);      if...      memmove(pool1_, *(*a3 + 24i64 * j), *(*a3 + 24i64 * j + 8));      *(*(this + 7) + 2i64 * j) = 1;      if ( cBlocks > 1u )      {        v18 = j + 1;        if ( v18 < cBlocks )          *(*(this + 6) + 24 * v18) = *(*(this + 6) + 24i64 * j);// shadow block      }    }    ....  }  ....}

这里根据对应日志块的 cbImage 循环分配了 cBlocks 个空间,由于 cBlocks 比实际值大,且 BLF 文件除 cBlocks 值之外没有做任何修改,因此系统认为后续 19 个日志块的大小为 0,ExAllocatePoolWithTag 分配了大小为 0 的空间,memmove 复制了大小为 0 的数据,最终保存到 pbImage 字段的地址是堆中一个未初始化空间的地址。


因此在系统执行到 ClfsEncodeBlockPrivate 时,blockHeader 指向的实际上是一块未初始化且大小为 0 的空间。


通过调试获取到分配的13 个日志块地址(剩余的 12 个日志块地址重复):


ffffd30c417903c0 // control blockffffd30c43f83000 // base blockffffd30c3fc134b0 // truncate blockffffd30c42cdebd0 ffffd30c42cdec30 ffffd30c42cdecf0 ffffd30c42cdfbd0 ffffd30c42cdfbf0 ffffd30c42cdf950 ffffd30c42cdf9d0 ffffd30c42cdf9f0 ffffd30c42cdfa10 ffffd30c42cdfa30


其中前三个是正常的日志块,我们主要看后 10 个日志块的地址,使用 !pool 命令查看堆块情况,截取部分输出:

2: kd> !pool ffffd30c42cdfbd0 1Pool page ffffd30c42cdfbd0 region is Paged pool...ffffd30c42cdf940 size:   20 previous size:    0  (Allocated)  Clfs    ffffd30c42cdf950  00000000 00000000 26e5c558 00007ff8
... ffffd30c42cdf9c0 size: 20 previous size: 0 (Allocated) Clfs ffffd30c42cdf9d0 00000101 10000000 00002000 00007ff8
ffffd30c42cdf9e0 size: 20 previous size: 0 (Allocated) Clfs ffffd30c42cdf9f0 0000001d 00000000 80000000 00000000
ffffd30c42cdfa00 size: 20 previous size: 0 (Allocated) Clfs ffffd30c42cdfa10 00000101 10000000 00002000 00007ff8
ffffd30c42cdfa20 size: 20 previous size: 0 (Allocated) Clfs ffffd30c42cdfa30 001e001c 00000000 26e5c558 00007ff8...*ffffd30c42cdfbc0 size: 20 previous size: 0 (Allocated) *Clfs Pooltag Clfs : CLFS General buffer, or owner page lookaside list, Binary : clfs.sys ffffd30c42cdfbd0 00000101 10000000 00002000 00007ff8
ffffd30c42cdfbe0 size: 20 previous size: 0 (Allocated) Clfs ffffd30c42cdfbf0 00000000 10000000 00002000 00007ff8

可以看到,虽然调用时请求分配的空间大小是 0,但实际上分配的是大小为 32 字节(包含头部)的堆块,且堆块都位于连续的一块空间中,且堆块头部数据相对固定

2: kd> dt _POOL_HEADER ffffd30c42cdfbc0nt!_POOL_HEADER   +0x000 PreviousSize     : 0y00000000 (0)   +0x000 PoolIndex        : 0y00000000 (0)   +0x002 BlockSize        : 0y00000010 (0x2)   +0x002 PoolType         : 0y00000011 (0x3)   +0x000 Ulong1           : 0x3020000   +0x004 PoolTag          : 0x73666c43   +0x008 ProcessBilled    : (null)    +0x008 AllocatorBackTraceIndex : 0   +0x00a PoolTagHash      : 02: kd> db ffffd30c42cdfbc0 l10ffffd30c*42cdfbc0  00 00 02 03 43 6c 66 73-00 00 00 00 00 00 00 00  ....Clfs........


也就是说,当相对于 blockHeader 进行取值时,如果偏移范围在 0x10-0x1F、0x30-0x3F、0x50-0x5F...,那么取到的数据就来自相对固定的头部数据,否则就来自未初始化的数据空间。


再次回到发生崩溃的函数,看一下涉及到的数据来源:


注:以下代码删除了一些细节,主要关注相对于blockHeader的偏移量_

__int64 __fastcall ClfsEncodeBlockPrivate(struct _CLFS_LOG_BLOCK_HEADER *blockHeader, unsigned int allSectorSize, char usn, unsigned __int8 a4){  nSector = *(blockHeader + 4);   // TotalSectorCount  if ( !nSector ||  *(blockHeader + 6) < nSector || nSector << 9 > allSectorSize )   // ValidSectorCount    return 0xC01A000Ai64;  if ( (*(blockHeader + 0x10) & 1) != 0 )       // Flags    return 0xC01A000Ai64;  signatureOffset = *(blockHeader + 0x68);         // SignaturesOffset  *(blockHeader + 2) = usn;        // Usn  signatureArray = blockHeader + signatureOffset;  if ( ULongAdd(signatureOffset, 2 * (allSectorSize >> 9), v21) < 0 || 0 > allSectorSize )  {    return 0xC01A000Ai64;  }  idx = 0;  if ( nSector )  {    do    {      signatureArray += 2i64;      flag1 = 0x20; flag2 = 0x40; flag = flag2 | flag1;      curSectorSize = idx << 9;      LOBYTE(v22) = a4 | flag;      ++idx;      *(signatureArray - 2) = *(curSectorSize + blockHeader + 0x1FE);// 异常发生位置                                                // 获取当前sector结尾处的signature并写入signature array      *(curSectorSize + blockHeader + 0x1FE) = v22;    }    while ( idx < nSector);  }  return 0i64;}

越界写的位置是 signatureArray - 2,主要受到偏移 0x68 位置的 signatureOffset 的影响;越界写的数据是 (curSectorSize + blockHeader+ 0x1FE),主要受到偏移 0x4 位置的 nSector 的影响,就是因为这里的数值太大才导致了崩溃的发生。


还有一些偏移位置的数据会影响程序流程,这里暂时不关注。


总结:


  • 写入位置:blockHeader + *(blockHeader+0x68) + idx * 2


  • 写入数据:*(blockHeader + idx*0x200 + 0x1FE)


根据上面对于堆块结构的分析,如果 blockHeader+【offset】 中 offset % 16 的结果是奇数,那么数据来源就是相对固定的堆块头部,否则数据来源就是未初始化的数据空间。


所以如果不考虑超出这块内存空间(即内部全部是0x10堆块的空间)的情况:写入数据所在的位置正位于堆块头部偏移 0x0E 的位置,该位置的数据绝大部分情况下均为 0x0000 ;写入位置可以通过类似堆喷射的方式进行控制。


5. 总结

通过以上分析可知,CVE-2022-30220 漏洞是由于对保存在堆块头部中的 cBlocks 字段的检查不够充分造成的,通过修改 BLF 文件中该字段数值,可以导致堆越界写的发生。由于堆空间结构的限制,越界写的位置与写入数据受到限制,如果想要进行漏洞利用,可能需要对堆空间结构更详细的分析,并通过修改BLF文件内容以及类似堆喷射的方式对数据进行控制。

6. 参考资料

1. https://github.com/ionescu007/clfs-docs

2. https://github.com/libyal/libfsclfs/blob/main/documenation/Common Log File System (CLFS).asciidoc

3. Windows Internal editon 6th


原文始发于微信公众号(青藤实验室):CVE-2022-30220:Windows Common Log File System Driver 提权漏洞分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年7月20日13:56:57
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2022-30220:Windows Common Log File System Driver 提权漏洞分析http://cn-sec.com/archives/1188328.html

发表评论

匿名网友 填写信息