CVE-2023-28252 CLFS 提权漏洞分析

渗透技巧 8个月前 admin
235 0 0




简介


红雨滴团队的《CVE-2023-28252在野提权漏洞样本分析》文章详细的分析了恶意文件并定位到漏洞触发点,但由于文章的主要目的是分析恶意文件而非讲解漏洞成因,因此漏洞成因方面的内容偏少。该文的主要内容是分析clfs.sys内的函数,以了解漏洞触发过程。由于笔者刚入门,如果文章出现错误,请多多包涵。





实验环境


◆Windows 10 22H2

◆IDA


CVE-2023-28252 CLFS 提权漏洞分析





CLFS


简述


通用日志文件系统(Common Log File System,缩写CLFS)是一个通用目的的日志文件系统,它可以从内核模式或用户模式的应用程序访问,用以构建一个高性能的事务日志。


文件格式


文件格式的类型定义可以参考ionescu007的文章,下面进行简单介绍。
元数据块类型为6种,其中Shadow块为备份块,当主块存在异常时,会使用Shadow块。类型定义如下:


typedef enum _CLFS_METADATA_BLOCK_TYPE
{
ClfsMetaBlockControl,
ClfsMetaBlockControlShadow,
ClfsMetaBlockGeneral,
ClfsMetaBlockGeneralShadow,
ClfsMetaBlockScratch,
ClfsMetaBlockScratchShadow
} CLFS_METADATA_BLOCK_TYPE, *PCLFS_METADATA_BLOCK_TYPE;


每个元数据块都以CLFS_LOG_BLOCK_HEADER结构起始,后面跟着元数据块特有的结构与数据,简单示意图如下:

CVE-2023-28252 CLFS 提权漏洞分析

该漏洞涉及ClfsMetaBlockControl和ClfsMetaBlockGeneral块,其涉及的主要类型定义如下:


typedef struct _CLFS_LOG_BLOCK_HEADER
{
UCHAR MajorVersion;
UCHAR MinorVersion;
UCHAR Usn;
CLFS_CLIENT_ID ClientId;
USHORT TotalSectorCount;
USHORT ValidSectorCount;
ULONG Padding;
ULONG Checksum;
ULONG Flags;
CLFS_LSN CurrentLsn;
CLFS_LSN NextLsn;
ULONG RecordOffsets[16];
ULONG SignaturesOffset;
} CLFS_LOG_BLOCK_HEADER, *PCLFS_LOG_BLOCK_HEADER;

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

typedef struct _CLFS_BASE_RECORD_HEADER
{
CLFS_METADATA_RECORD_HEADER hdrBaseRecord;
CLFS_LOG_ID cidLog;
ULONGLONG rgClientSymTbl[CLIENT_SYMTBL_SIZE];
ULONGLONG rgContainerSymTbl[CONTAINER_SYMTBL_SIZE];
ULONGLONG rgSecuritySymTbl[SHARED_SECURITY_SYMTBL_SIZE];
ULONG cNextContainer;
CLFS_CLIENT_ID cNextClient;
ULONG cFreeContainers;
ULONG cActiveContainers;
ULONG cbFreeContainers;
ULONG cbBusyContainers;
ULONG rgClients[MAX_CLIENTS_DEFAULT];
ULONG rgContainers[MAX_CONTAINERS_DEFAULT];
ULONG cbSymbolZone;
ULONG cbSector;
USHORT bUnused;
CLFS_LOG_STATE eLogState;
UCHAR cUsn;
UCHAR cClients;
} CLFS_BASE_RECORD_HEADER, *PCLFS_BASE_RECORD_HEADER;


其中ClfsMetaBlockGeneral块包含容器类型,且容器的pContainer成员为内核对象指针,因此如果可以控制该成员,则将为执行任意代码打下基础。其结构定义如下:


typedef struct _CLFS_CONTAINER_CONTEXT
{
CLFS_NODE_ID cidNode;
ULONGLONG cbContainer;
CLFS_CONTAINER_ID cidContainer;
CLFS_CONTAINER_ID cidQueue; //队列标识符
union
{
CClfsContainer* pContainer; //指向描述容器类的内核对象
ULONGLONG ullAlignment;
};
CLFS_USN usnCurrent;
CLFS_CONTAINER_STATE eState;
ULONG cbPrevOffset;
ULONG cbNextOffset;
} CLFS_CONTAINER_CONTEXT, *PCLFS_CONTAINER_CONTEXT;


之前在CVE-2022-24521漏洞复现过程中,简单编写了一个010 Editor的模板,可以简单解析日志文件(.blf格式文件),便于了解文件结构布局,后续可在附件中下载。


CVE-2023-28252 CLFS 提权漏洞分析





漏洞利用分析


漏洞通过 CreateLogFile和AddLogContainer 函数进行触发,接下来将根据构造的日志文件内容梳理这两个函数的执行流程。为了便于理解clfs.sys的函数,首先将ionescu007文章中的CLFS相关结构体整理成了头文件,并加载到IDA中。


CVE-2023-28252 CLFS 提权漏洞分析


CreateLogFile处理流程


《CVE-2022-37969 技术分析》中说到当在用户空间调用CreateLogFile函数时,CLFS!CClfsRequest::Create负责处理这个请求。当使用 CreateLogFile 函数打开现有基本日志文件时,将在 CLFS.sys 中调用函数CClfsLogFcbPhysical::Initialize ,并随后调用CClfsBaseFilePersisted::OpenImage。接下来将从OpenImage函数开始进行分析。


OpenImage首先进行初始化操作,如申请内存。


CVE-2023-28252 CLFS 提权漏洞分析

图:OpenImage部分代码


OpenImage中调用了CClfsBaseFilePersisted::ReadImage函数,这里提前说明下函数做了哪些后续要关注的工作。26行将this+0x28赋值为6,27行为this+0x30 申请内存空间,45行调用CClfsBaseFile::GetControlRecord获取控制记录的地址。控制记录为_CLFS_CONTROL_RECORD结构,为ClfsMetaBlockControl块的第二个结构体。


CVE-2023-28252 CLFS 提权漏洞分析

图:ReadImage部分代码


随后OpenImage函数的131行调用CClfsBaseFilePersisted::ReadImage函数加载日志文件,获取控制记录结构地址,加载成功后从142行代码开始执行。146行调用CClfsBaseFile::GetBaseLogRecord函数获取基本日志记录地址,该返回值为_CLFS_BASE_RECORD_HEADER指针,指向ClfsMetaBlockGeneral块的第二个结构体,随后在149-157行使用基本日志记录初始化数据。当控制记录的eExtendState不为0,iExtendBlock小于4,iFlushBlock小于6且大于等于iExtendBlock,cExtendStartSectors小于文件扇区总数量,cNewBlockSectors小于扩展元数据块的扇区总数量加上(iExtendBlock/2)时,将在179行调用CClfsBaseFilePersisted::ExtendMetadataBlock函数。


CVE-2023-28252 CLFS 提权漏洞分析

图:OpenImage部分代码


ExtendMetadataBlock函数98行根据参数2(iExtendBlock)加载元数据块,然后获取控制记录指针。当控制记录的eExtendState成员值为2时,跳转到LABEL_41。


CVE-2023-28252 CLFS 提权漏洞分析

图:ExtendMetadataBlock部分代码


192行检测eExtendState值是否为2,不为2则退出循环。随后在208行使用iFlushBlock作为参数2调用CClfsBaseFilePersisted::WriteMetadataBlock函数(本次调用该函数时,参数2被指定为了4,用于扩展ClfsMetaBlockScratch块,这一过程只是为了过渡到FlushControlRecord函数的调用)。随后209行检测iFlushBlock与iExtendBlock值是否相同,相同则v12复制为0,从而在下次for循环时,从192行的检测中退出循环。循环最后调用了CClfsBaseFilePersisted::FlushControlRecord,这个函数需要重点关注。


CVE-2023-28252 CLFS 提权漏洞分析

图:ExtendMetadataBlock部分代码

FlushControlRecord函数在处理部分数据后,于23行调用了CClfsBaseFilePersisted::WriteMetadataBlock。


CVE-2023-28252 CLFS 提权漏洞分析
图:FlushControlRecord代码


WriteMetadataBlock函数在31行根据参数2获取指定元数据块的地址,然后进行了部分数据的更新,此时更新的元数据块是iFlushBlock字段指定的。61行调用了ClfsEncodeBlock处理块数据,并在67行调用CClfsContainer::WriteSector将写入块数据,这两个函数是漏洞利用的关键前置步骤。需要注意的是,ClfsEncodeBlock和WriteSector操作的是参数2指定的元数据块,本次参数2为0,即操作的是ClfsMetaBlockControl块。


CVE-2023-28252 CLFS 提权漏洞分析

图:WriteMetadataBlock部分代码


ClfsEncodeBlock先将_CLFS_LOG_BLOCK_HEADER的Checksum 成员值置为0,然后调用ClfsEncodeBlockPrivate函数进行下一步处理。当ClfsEncodeBlockPrivate返回结果为负数时,则不会重新计算校验和并返回。


CVE-2023-28252 CLFS 提权漏洞分析
图:ClfsEncodeBlock代码


ClfsEncodeBlockPrivate检测_CLFS_LOG_BLOCK_HEADER的ValidSectorCount是否小于TotalSectorCount,如果小于则返回错误码0xC01A000A。


CVE-2023-28252 CLFS 提权漏洞分析
图:ClfsEncodeBlockPrivate部分代码


回顾WriteMetadataBlock函数的61行代码,可以发现并没有对ClfsEncodeBlock的返回值进行判断,而是直接调用WriteSector函数将更新数据。假设ValidSectorCount小于TotalSectorCount,执行ClfsEncodeBlock时则首先将校验和置为0,然后ClfsEncodeBlockPrivate检测到异常,返回错误码0xC01A000A,因此ClfsEncodeBlock不会更新校验和。随后直接调用WriteSector函数将指定元数据块的校验和的值更新为了0。


CVE-2023-28252 CLFS 提权漏洞分析
图:WriteMetadataBlock部分代码


将校验和值更新为0的目的在于绕过OpenImage中的检测。OpenImage的163~173行,检测了iFlushBlock和iExtendBlock的值是否大于6,当大于6时则会返回错误码0xC01A000D。简介文件格式时,提到过shadow块为备份块,当主块的校验和值为0时,则会检测失败,从而使用shadow块的数据,因此shadow块数据可以为大于6的数据,然后通过构造特定字段值,执行上述流程使校验和为0,下次获取元数据块则使用shadow块,下一部分内容会说明替换逻辑。


CVE-2023-28252 CLFS 提权漏洞分析

图:OpenImage部分代码


AddLogContainer处理流程


《样本分析》中指出WIN32API AddLogContainer对应内核中的CLFS!CClfsLogFcbPhysical::AllocContainer函数,下面将从AllocContainer函数入手分析。


AllocContainer函数的69行调用了CClfsBaseFilePersisted::AddContainer函数。


CVE-2023-28252 CLFS 提权漏洞分析

图:AllocContainer部分代码


AllocContainer函数的44行调用了CClfsBaseFilePersisted::AddSymbol函数。


CVE-2023-28252 CLFS 提权漏洞分析
图:AddContainer部分代码


AddSymbol函数中当v16 值为 0xC0000023时,会在26行调用CClfsBaseFilePersisted::ExtendMetadataBlock函数。v16为CClfsBaseFile::FindSymbol函数的返回值,因此关注FindSymbol函数。


CVE-2023-28252 CLFS 提权漏洞分析

图:AddSymbol代码


FindSymbol函数中没有发现0xC0000023错误码,但124行调用了虚函数,并且返回值为负数时将通过LABEL_26标记返回。使用windbg设置断点调试,最终确定该虚函数为CLFS!CClfsBaseFilePersisted::AllocSymbol()。


CVE-2023-28252 CLFS 提权漏洞分析

图:FindSymbol部分代码


在AllocSymbol中的25行发现了错误码0xC0000023,其触发条件为当前容器的结束地址大于签名缓冲区地址。当前容器的结束地址根据_CLFS_BASE_RECORD_HEADER结构的cbSymbolZone成员值计算得到,因此可以修改cbSymbolZone值使其满足条件返回错误码0xC0000023,从而在AddSymbol中调用ExtendMetadataBlock函数。


CVE-2023-28252 CLFS 提权漏洞分析
图:AllocSymbol代码


此时执行流程为:
AllocContainer -> AddContainer -> AddSymbol -> FindSymbol -> AllocSymbol //返回错误码0xC0000023
AllocContainer -> AddContainer -> AddSymbol -> ExtendMetadataBlock //根据错误码0xC0000023,调用ExtendMetadataBlock函数

ExtendMetadataBlock函数105行调用CClfsBaseFile::GetControlRecord获取控制记录地址(_CLFS_CONTROL_RECORD),控制记录存在于ClfsMetaBlockControl块中。在CreateLogFile执行过程中,通过构造特定的字段使的CreateLogFile校验和为0,因此本次获取的控制记录实则为ClfsMetaBlockControlShadow块的。下面分析GetControlRecord函数,查看控制记录是如何被替换的。


CVE-2023-28252 CLFS 提权漏洞分析

图:ExtendMetadataBlock部分代码


GetControlRecord函数18行调用CClfsBaseFile::AcquireMetadataBlock函数加载ClfsMetaBlockControl块,随后进行一系列检查,最终将ClfsMetaBlockControl中CLFS_CONTROL_RECORD的地址写入到参数2。


CVE-2023-28252 CLFS 提权漏洞分析

图:GetControlRecord代码


AcquireMetadataBlock中调用了一个虚函数,在windbg中跟踪为CClfsBaseFilePersisted::ReadMetadataBlock函数。


CVE-2023-28252 CLFS 提权漏洞分析
图:AcquireMetadataBlock代码


ReadMetadataBlock函数31至52行代码读取参数2指定的元数据块到分配的池内存,随后在58行调用ClfsDecodeBlock函数进行解码(因为CreateLogFile函数处理流程中ClfsMetaBlockControl校验置为了0,因此该函数会返回错误码)。73行代码再次调用ReadMetadataBlock函数,加载当前元数据块的shadow块。随后通过一系列检查到达75行,此时v8小于0,将跳转到117行代码开始执行。117~122代码,释放了ReadMetadataBlock为当前元数据块申请的池空间,然后使用其shadow块地址代替当前元数据块。


CVE-2023-28252 CLFS 提权漏洞分析
图:ReadMetadataBlock部分代码


CVE-2023-28252 CLFS 提权漏洞分析
图:ReadMetadataBlock部分代码


ClfsDecodeBlock函数先判断校验和是否为0,这里为0然后跳转到16行继续判断。通过ReadMetadataBlock的函数调用可知a4值为0x10,然后MajorVersion值为0xF,因此该检测失败,直接返回错误代码 0xC01A000A。至此ReadMetadataBlock函数使用ClfsMetaBlockControlShadow块替换了ClfsMetaBlockControl块。


CVE-2023-28252 CLFS 提权漏洞分析
图:ClfsDecodeBlock代码


CVE-2023-28252 CLFS 提权漏洞分析
图:默认MajorVersion值


回到ExtendMetadataBlock函数,可以得知105行代码获取的实际为ClfsMetaBlockControlShadow块。随后通过检测,跳转到LABEL_41处。


CVE-2023-28252 CLFS 提权漏洞分析

图:ExtendMetadataBlock部分代码


跳转到LABEL_41后,在208行调用了CClfsBaseFilePersisted::WriteMetadataBlock函数。需要注意的是ClfsMetaBlockControlShadow块中的iFlushBlock值为0x13,即WriteMetadataBlock的参数2值为0x13。


CVE-2023-28252 CLFS 提权漏洞分析

图:ExtendMetadataBlock部分代码


此时查看WriteMetadataBlock处理逻辑。31行代码使用24乘以参数2作为this+0x30的偏移,随后取得数据。在ReadImage中可以得知this+0x30的内存空间为0x90,而24*0x13结果为0x1C8,已经超出了0x90,从而取得了错误的地址。然后从错误地址的0x28偏移取得偏移B,然后将错误地址的偏移B的数据进行+1。此时通过漏洞已经触发,实现了数据自增1。


CVE-2023-28252 CLFS 提权漏洞分析

图:WriteMetadataBlock部分代码


任意函数执行


《样本分析》中指出CreateLogFile函数会调用CClfsBaseFilePersisted::CheckSecureAccess函数。CheckSecureAccess函数的55行起会遍历容器,然后64行获取pContainer值,并在69行和78行调用二次虚函数。因此可以创建一个日志文件,其包含了精心构造的容器,然后利用该漏洞修改容器的偏移,使其再次调用CreateLogFile时,遍历的容器为构造的容器,然后pContainer值指向用户空间中构造虚函数布局,这样调用虚函数时便可以执行我们想要执行的函数。由此构造函数利用链(函数利用链可以查看《CVE-2022-37969 技术分析》,该文章详细的介绍了相关内容),实现权限提升。


CVE-2023-28252 CLFS 提权漏洞分析

图:CheckSecureAccess部分代码


权限提升思路


权限提升过程涉及到池空间分配、利用管道属性实现任意地址写入等操作,这里仅简单介绍下思路,不在详细展开,具体过程可以查看《样本分析》。


1.创建一个包含容器的日志文件A,然后容器地址偏移0x100处构造一个pContainer成员有值的容器。


2.通过NtQuerySystemInformation查询0x7A00大小的CLFS数据池。


3.调用CreateLogFile函数将日志文件A加载到内核。


4.通过NtQuerySystemInformation查询0x7A00大小的CLFS数据池,查询到新增的池地址,这个地址为日志文件A的ClfsMetaBlockGeneral块地址(该块的大小为0x7A00)。


5.创建多个漏洞利用日志文件B,构造文件数据,使其最终可以在WriteMetadataBlock中实现越界数据访问,并进行数据自增。


6.构造池布局空间。申请大量的匿名管道,然后将13个日志文件A的ClfsMetaBlockGeneral块地址写入到管道,使其申请0x90的池空间。


7.关闭匿名管道,释放池空间,然后调用CreateLogFile函数将多个日志文件B加载到内核,然后在将13个日志文件A的ClfsMetaBlockGeneral块地址写入到管道,这样在日志文件B的clsfhelp(this+0x30)的周围就是构造的日志文件A的ClfsMetaBlockGeneral块地址。


8.构造函数执行内存布局。


9.调用AddLogContainer函数触发漏洞,修改日志文件A的ClfsMetaBlockGeneral块中rgContainer数据,使其容器偏移增加0x100。增加0x100的原因是利用漏洞增加的是后24位的数据,因此自增1,等于增加了0x100偏移。


10.调用CreateLogFile函数再次加载日志文件A,随后通过CheckSecureAccess函数利用构造的容器,然后根据函数执行内存布局利用管道属性,实现任意数据写入,然后替换了进程的TOKEN从而实现提权。





漏洞修复


根据上面分析可以得知触发漏洞是由于WriteMetadataBlock的ClfsEncodeBlock函数将校验和置为了0,然后在触发错误时,仍更新了ClfsMetaBlockControl块数据,从而导致下一次加载ClfsMetaBlockControl块时使用了导致越界访问的ClfsMetaBlockControlShadow块。因此修复后的WriteMetadataBlock函数在82行对ClfsEncodeBlock的返回值进行了检测,在出现异常时不调用WriteSector函数,从而使得ClfsMetaBlockControlShadow不会被使用。《样本分析》中描述了其他的修复内容,这里就不再重复陈述。


CVE-2023-28252 CLFS 提权漏洞分析

图:修复后的WriteMetadataBlock部分代码



参考


https://mp.weixin.qq.com/s/Qlst6CX_z1A698Tvvx-bIQ(CVE-2023-28252在野提权漏洞样本分析)

https://github.com/ionescu007/clfs-docs/(CLFS格式)

https://www.zscaler.com/blogs/security-research/technical-analysis-windows-clfs-zero-day-vulnerability-cve-2022-37969-part(CVE-2022-37969 技术分析 上)

https://www.zscaler.com/blogs/security-research/technical-analysis-windows-clfs-zero-day-vulnerability-cve-2022-37969-part2-exploit-analysis(CVE-2022-37969技术分析 下)




CVE-2023-28252 CLFS 提权漏洞分析


看雪ID:i未若

https://bbs.kanxue.com/user-home-875946.htm

*本文为看雪论坛精华文章,由 i未若 原创,转载请注明来自看雪社区

CVE-2023-28252 CLFS 提权漏洞分析

# 往期推荐

1、在 Windows下搭建LLVM 使用环境

2、深入学习smali语法

3、安卓加固脱壳分享

4、Flutter 逆向初探

5、一个简单实践理解栈空间转移

6、记一次某盾手游加固的脱壳与修复


CVE-2023-28252 CLFS 提权漏洞分析


CVE-2023-28252 CLFS 提权漏洞分析

球分享

CVE-2023-28252 CLFS 提权漏洞分析

球点赞

CVE-2023-28252 CLFS 提权漏洞分析

球在看

原文始发于微信公众号(看雪学苑):CVE-2023-28252 CLFS 提权漏洞分析

版权声明:admin 发表于 2023年8月20日 下午6:00。
转载请注明:CVE-2023-28252 CLFS 提权漏洞分析 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...