Loading
0

SMBv3远程拒绝服务(BSOD)漏洞分析

kd> p
tcpip!TcpDeliverDataToClient+0x1c1:
fffff80a`72c21961 e99bfeffff      jmp     tcpip!TcpDeliverDataToClient+0x61 (fffff80a`72c21801)
kd> p
tcpip!TcpDeliverDataToClient+0x61:
fffff80a`72c21801 48837b0800      cmp     qword ptr [rbx+8],0
kd> dd rbx+8
ffffc10c`a0643e60  9d8c2fa0 ffffc10c 9d8c2fa0 ffffc10c
来看一下这个if语句。
while ( 1 )
{
if ( v6[1] )
{
if ( !*v5 )
break;
v9 = v6[1];
v10 = v6[2];
*((_BYTE *)v6 + 98) &= 0xFEu;
v69 = v9;
v6[1] = 0i64;
v6[2] = 0i64;
v11 = vars30;
v71 = v10;
LODWORD(v12) = TcpSatisfyReceiveRequests(v7, 0, (__int64)v6, vars30, v5, &v69, &v66);
}
}
在这个if语句中,会调用TcpSatisfyReceiveRequests函数,这个函数中第六个参数,也就是v69是很关键的,这个值决定了后面的空指针引用,接下来进入这个函数。
int __fastcall TcpSatisfyReceiveRequests(PKSPIN_LOCK SpinLock, char a2, __int64 a3, signed int a4, __int64 *a5, __int64 *a6, _DWORD *a7)
{
v8 = *a5;
v95 = SpinLock;
v9 = *a6;                                     // RBP+148
v38 = *(_QWORD *)(v9 + 48);
v39 = *(_QWORD *)(v9 + 56);
v40 = *(_QWORD *)(v9 + 8);
v41 = *(_QWORD *)(v9 + 72);
v93 += v38;
v99 += *(_QWORD *)(v9 + 40);
v42 = *(_QWORD *)v9;
_guard_dispatch_icall_fptr(v40, 0i64, v38, v39);// call WskProTLReceiveComplete
这个函数中的_guard_dispatch_icall_fptr调用了WskProTLreceiveComplete函数,而v40参数和v9结构体有关,v9是由传入第六个参数,也就是刚才提到的v69有关,v69又来自于v6[1],而这个结构体是和Complete有关,但是在TreeConnect数据包中却没有对这个结构体进行赋值。
随后在WskProTLReceiveComplete中,会将rcx,也就是第一个参数v40,进行传递(64位Windows系统中,参数传递通过寄存器,第一个参数是rcx,第二个是rdx,第三个是r8,第四个是r9)。在后面的分析中,省略了无关的汇编过程,只留关键的给大家分享。
kd> p
afd!WskProTLReceiveComplete+0x34:
fffff80a`7365aa84 488bd9          mov     rbx,rcx
…………
kd> p
afd!WskProTLReceiveComplete+0x8e:
fffff80a`7365aade 488bcb          mov     rcx,rbx
kd> r rbx
rbx=ffffc10ca01ba010
kd> p
afd!WskProTLReceiveComplete+0x91:
fffff80a`7365aae1 ff15512d0200    call    qword ptr [afd!_imp_IofCompleteRequest (fffff80a`7367d838)]
经过一系列传递后,这个第一个参数会直接传给IofCompleteRequest函数,这个函数是irp完成函数,其实是一个中间过程,同步irp完成,后面就是善后工作。
在函数中,参数继续传递。
kd> p
nt!IopfCompleteRequest+0xb:
fffff800`9464b81b 4881ec00010000  sub     rsp,100h
kd> p
nt!IopfCompleteRequest+0x12:
fffff800`9464b822 488bd9          mov     rbx,rcx
…………
kd> p
nt!IopfCompleteRequest+0x109:
fffff800`9464b919 488bd3          mov     rdx,rbx
kd> p
nt!IopfCompleteRequest+0x10c:
fffff800`9464b91c 488bce          mov     rcx,rsi
kd> p
nt!IopfCompleteRequest+0x10f:
fffff800`9464b91f ff5735          call    qword ptr [rdi+35h]
kd> t
Breakpoint 0 hit
mrxsmb!SmbWskReceiveComplete:
fffff80a`731d6950 48895c2408      mov     qword ptr [rsp+8],rbx
在IofCompleteRequest函数中,会有一处调用回到SmWskReceivComplete函数,而结构体会交给rdx,也就是第二个参数进入这个函数。随后这个参数会连续传递。先来看一下之前的堆栈回溯。
kd> kb
RetAddr           : Args to Child                                                           : Call Site

分页阅读: 1 2 3 4 5
【声明】:8090安全小组门户(https://www.8090-sec.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们:邮箱hack@ddos.kim,我们会在最短的时间内进行处理。