简介
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之前没有很好的处理这些释放的资源,导致了内存泄露
if ( irpcontext )