2020年12月微软发布CVE-2020-17096的补丁,zecops团队对此漏洞进行了分析,文章在这里,本文根据其文章进行复现学习。这个洞是NTFS模块,zecops分析出来是内存泄露,但是微软对这类内存泄漏的洞很少收,并且标注的是Remote Code Execution
,zecops团队也没有找到远程代码执行的地方,所以真正是否为zecops团队分析的那样还需要进一步研究。
问题出在ntfs.sys
中,下面是对比的18362.1171
和18362.1256
,出除去一些未识别的符号,可以直接定位到NtfsOffloadRead
函数
从函数名可以猜到是文件卸载读的操作,搜一下文档可以找到[MS-FSCC],其中的2.3.41 FSCTL_OFFLOAD_READ Request就是卸载读的操作,应该和这个函数有关
before patch
after patch
新版本红框函数内第一个参数从NULL
变为 IrpConetxt
并删除了一些对参数的判断,这个 IrpContext
就是 NtfsOffloadRead
函数的第一个参数 ,第一个函数和调试跟踪有关,应该是开发人员使用的,所以重点应该放在第二个 NtfsExtendedCompleteRequestInternal
函数,下面的代码基于补丁前的版本,如果第一个参数为NULL则直接跳过对第一个参数的操作,然后调用IRP完成函数
void __fastcall NtfsExtendedCompleteRequestInternal(__int64 a1, IRP *irp, int a3, __int64 a4, int a5) { _QWORD *v5; // r13 unsigned __int8 v6; // r12 IRP *Irp; // rsi _IO_STACK_LOCATION *v10; // r15 __int64 v11; // rax void *v12; // rcx bool v13; // sf void *v14; // rcx _QWORD *v15; // r14 _QWORD *v16; // rax void *v17; // rcx PFILE_OBJECT v18; // rax __int64 v19; // rcx __int64 v20; // r8 v5 = 0i64; v6 = a4; Irp = irp; v10 = 0i64; if ( irp ) { v10 = irp->Tail.Overlay.CurrentStackLocation; if... } if ( a1 ) { // ... } LABEL_27: if ( Irp ) { v18 = v10->FileObject; if ( v18 ) v5 = v18->FsContext; Irp->IoStatus.Status = a3; if ( (unsigned __int8)(v10->MajorFunction - 3) <= 1u && a3 == 0xC000009A && v5 && (*(_DWORD *)(v5[21] + 4i64) & 4) != 0 && IoIsOperationSynchronous(Irp) ) { ++NtfsFailedPagingFileOps; } if ( v10->MajorFunction == 3 && a3 == 0xC000009A && (Irp->Flags & 2) != 0 ) ++NtfsFailedPagingReads; IofCompleteRequest(Irp, 1); } }
在patch之后会传入IrpContext
,若其非零则会解析很多字段,做一些释放资源和释放内存的操作,调用一些Cancel
、Cleanup
、Dereference
的函数,由此猜测patch之前没有很好的处理这些释放的资源,导致了内存泄露