CVE-2021-24086漏洞分析
2022-7-19 18:4:0 Author: 看雪学苑(查看原文) 阅读量:24 收藏


本文为看雪论坛精华文章
看雪论坛作者ID:badboyl


漏洞信息

2021年,Microsoft发布了一个安全补丁程序,修复了一个拒绝服务漏洞,编号为CVE-2021-24086,该漏洞影响每个Windows版本的IPv6堆栈,此问题是由于IPv6分片处理不当引起的。微软为了这个漏洞特地升级了一次补丁,同时该漏洞的效果和影响也是非常巨大和广泛,可直接远程触发目标机器蓝屏死机。


漏洞复现

去年互联网上发布了该漏洞的攻击代码,笔者从该地址得到了payload:
https://github.com/0vercl0k/CVE-2021-24086
我们需要在该main函数方法中设置攻击机Linux的网卡名称。

目标机器是需要填写IPV6的地址。
python3 cve-2021-24086.py --target fe80::69eb:90bf:3f91:deae
触发BSOD


漏洞分析

触发BSOD后的栈回溯
0: kd> rrax=0000000000000000 rbx=0000000000000003 rcx=0000000000000003rdx=000000000000008a rsi=fffff800042531c0 rdi=0000000000000000rip=fffff800040f9720 rsp=fffff800054d5218 rbp=0000000000000000 r8=0000000000000065  r9=0000000000000000 r10=0000000000000000r11=fffff800054d4ea0 r12=000000000000000a r13=0000000000000001r14=0000000040000082 r15=0000000000000000iopl=0         nv up ei ng nz na pe nccs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000282nt!RtlpBreakWithStatusInstruction:fffff800`040f9720 cc              int     30: kd> kb # RetAddr               : Args to Child                                                           : Call Site00 fffff800`041adc22     : 00000000`00000000 fffff800`042531c0 00000000`00000065 fffff800`040ca378 : nt!RtlpBreakWithStatusInstruction01 fffff800`041aea12     : 00000000`00000003 00000000`00000000 fffff800`041025d0 00000000`000000d1 : nt!KiBugCheckDebugBreak+0x1202 fffff800`040f2fa4     : 00000000`00000000 fffff800`04259888 fffff800`04259a02 fffff800`0408e00a : nt!KeBugCheck2+0x72203 fffff800`041012e9     : 00000000`0000000a 00000000`00000000 00000000`00000002 00000000`00000001 : nt!KeBugCheckEx+0x10404 fffff800`040ff0ce     : 00000000`00000001 00000000`00000000 fffffa80`32dc6500 00000000`00010010 : nt!KiBugCheckDispatch+0x6905 fffff880`018884bd     : fffff880`01920bff 00000000`00010010 fffffa80`00000060 fffffa80`339b15e0 : nt!KiPageFault+0x44e06 fffff880`01920bff     : 00000000`00010010 fffffa80`00000060 fffffa80`339b15e0 00000000`00000000 : tcpip!memmove+0xbd07 fffff880`01938d18     : fffffa80`31fb1000 00000000`00000000 fffffa80`32dc6702 00000000`0000fffa : tcpip!Ipv6pReassembleDatagram+0x17f08 fffff880`01938e03     : fffffa80`00000008 fffff880`0196b738 fffffa80`32dfe8d0 fffffa80`31e96900 : tcpip!Ipv6pReceiveFragment+0xb5809 fffff880`01858964     : 0000057f`cd9e03a8 fffffa80`334a81b0 fffffa80`334a81b0 fffff880`01003e8b : tcpip!Ipv6pReceiveFragmentList+0x430a fffff880`0185642f     : 00000000`00000000 00000000`0199c801 00000000`00000000 fffff880`01966870 : tcpip!IppReceiveHeaderBatch+0x4850b fffff880`01855a4c     : fffffa80`32e0b960 00000000`00000000 fffff880`0199c801 fffffa80`00000001 : tcpip!IpFlcReceivePackets+0x64f0c fffff880`0185443a     : fffffa80`32e13ba0 fffff800`054d6250 fffffa80`32e13ba0 00000003`e9110001 : tcpip!FlpReceiveNonPreValidatedNetBufferListChain+0xcec0d fffff800`040a8dd9     : fffffa80`32dc65e0 00000000`00000000 fffffa80`31e9c830 00000000`00000000 : tcpip!FlReceiveNetBufferListChainCalloutRoutine+0xda0e fffff880`01854b32     : fffff880`01854360 fffff800`054d6370 fffffa80`00000000 ffff0092`174ff900 : nt!KeExpandKernelStackAndCalloutEx+0x2c90f fffff880`017a70eb     : fffffa80`32e148d0 00000000`00000000 fffffa80`3aef21a0 00000000`00000000 : tcpip!FlReceiveNetBufferListChain+0xb210 fffff880`01770ad6     : fffff800`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ndis!ndisMIndicateNetBufferListsToOpen+0xdb11 fffff880`016fd599     : fffffa80`3aef21a0 00000000`00000002 00000000`00000001 00000000`00000001 : ndis!ndisMDispatchReceiveNetBufferLists+0x1d612 fffff880`016f37a4     : 00000000`00010303 00000000`00000000 00000000`00000001 fffff880`016f2900 : ndis!ndisMDispatchReceiveNetBufferListsWithLock+0x8913 fffff880`016f3719     : 00000000`00000000 fffff880`05885759 fffffa80`32e02010 00000000`00000000 : ndis!ndisMTopReceiveNetBufferLists+0x2414 fffff880`016f36b0     : 00000000`00000000 00000000`00000009 00000000`00000000 00000000`00000001 : ndis!ndisFilterIndicateReceiveNetBufferLists+0x2915 fffff880`058858e1     : fffffa80`32e02010 00000000`00000001 00000000`00000001 fffffa80`32dc65e0 : ndis!NdisFIndicateReceiveNetBufferLists+0x5016 fffff880`0170bc24     : fffffa80`3aef21a0 fffffa80`32dc65e0 00000000`00000001 fffffa80`32dc65e0 : npcap+0x58e117 fffff880`0627c778     : 00000000`00000000 00000000`00000001 00000000`00000000 00000000`00000000 : ndis! ?? ::FNODOBFM::`string'+0xc72f18 fffff880`0627c3d1     : fffffa80`325ad001 00000000`00000000 00000000`00000000 fffffa80`32611000 : E1G6032E+0x77819 fffff880`016ea9b6     : fffffa80`32dd1670 00000000`00000000 fffffa80`3aef21a0 00000000`00000018 : E1G6032E+0x3d11a fffff800`0409fcbc     : fffffa80`32dd1698 fffff800`00000000 00000000`00000000 fffff800`04243180 : ndis!ndisInterruptDpc+0x1b61b fffff800`040f642a     : fffff800`04243180 fffff800`042531c0 00000000`00000000 fffff880`016ea800 : nt!KiRetireDpcList+0x1bc1c 00000000`00000000     : fffff800`054d7000 fffff800`054d1000 fffff800`054d6c00 00000000`00000000 : nt!KiIdleLoop+0x5a0: kd> .trap 0xfffff880`01938d18NOTE: The trap frame does not contain all registers.Some register values may be zeroed or incorrect.Unable to get program counterrax=0000000000000000 rbx=0000000000000000 rcx=0000000000000000rdx=0000000000000000 rsi=0000000000000000 rdi=0000000000000000rip=c328c48348000001 rsp=5718738949106b89 rbp=3301b04128ec8348 r8=0000000000000000  r9=0000000000000000 r10=0000000000000000r11=0000000000000000 r12=0000000000000000 r13=0000000000000000r14=0000000000000000 r15=0000000000000000iopl=0 vip vif ov up ei pl zr na po nc9090:0001 ??              ???rax=402cfaff00000060 rbx=0000000000000000 rcx=0000000000000020rdx=fffffa8032c2f198 rsi=0000000000000000 rdi=0000000000000000rip=fffff880018884bd rsp=fffff800054d5c68 rbp=fffffa8032c2f110 r8=0000000000000028  r9=0000000000000001 r10=00000000000080fer11=0000000000000000 r12=0000000000000000 r13=0000000000000000r14=0000000000000000 r15=0000000000000000iopl=0         nv up ei pl nz na pe nctcpip!memmove+0xbd:fffff880`018884bd 488941e0        mov     qword ptr [rcx-20h],rax ds:00000000`00000000=????????????????Resetting default scope
漏洞是在tcpip!Ipv6pReassembleDatagram函数中发生了NULL解引用,该操作系统的函数调用链可以看到是在tcpip!memmove+0xbd发生0地址写入奔溃,我们通过IDA逆向分析。
BytesNeededa = (char *)NdisGetDataBuffer((PNET_BUFFER)v14, BytesNeeded, 0i64, 1u, 0); v16 = IppCopyPacket(v7, a1); if ( !v16 )   goto LABEL_8; *(_WORD *)(a2 + 140) = __ROR2__(v29, 8); memmove(BytesNeededa, (const void *)(a2 + 136), 0x28ui64); memmove(BytesNeededa + 40, *(const void **)(a2 + 96), *(unsigned __int16 *)(a2 + 104)); BytesNeededa[*(unsigned __int16 *)(a2 + 184)] = *(_BYTE *)(a2 + 188);
一共有两处使用了tcpip!memmove,而BytesNeededa来自(char *)NdisGetDataBuffer((PNET_BUFFER)v14, BytesNeeded, 0i64, 1u, 0)
NDIS_EXPORTED_ROUTINE PVOID NdisGetDataBuffer(  [in]           NET_BUFFER *NetBuffer,  [in]           ULONG      BytesNeeded,  [in, optional] PVOID      Storage,  [in]           ULONG      AlignMultiple,  [in]           ULONG      AlignOffset);

从官方的MSDN可以的知,该值可以是指针也可能是NULL,而在下面没有经过判断就往内存写入,如果当内存的地址为0时,就触发了BSOD。

通过逆向分析发现NdisGetDataBuffer有几处if判断可能会将其写入0。

NdisGetDataBuffer在NetBuffer->CurrentMdlOffset赋值后if判断的时条件语句没有为真从而执行else语句块时返回0。

经过调试发现NdisRetreatNetBufferDataStart函数NetBuffer->DataLength赋值为0x28。
NDIS_STATUS __stdcall NdisRetreatNetBufferDataStart(PNET_BUFFER NetBuffer, ULONG DataOffsetDelta, ULONG DataBackFill, NET_BUFFER_ALLOCATE_MDL_HANDLER AllocateMdlHandler){  unsigned int v5; // ecx  _MDL *v7; // rax  unsigned int v8; // ecx  unsigned int v9; // edx  _MDL *v11; // rax  ULONG v12; // ecx  ULONG v13; // [rsp+38h] [rbp+10h] BYREF   v5 = NetBuffer->DataOffset;                   // v5=0  if ( v5 >= DataOffsetDelta )                  // v5=0;dataoffsetdelta=28  {    v7 = NetBuffer->MdlChain;    NetBuffer->DataLength += DataOffsetDelta;    v8 = v5 - DataOffsetDelta;    for ( NetBuffer->DataOffset = v8; v7; v8 -= v9 )    {      v9 = v7->ByteCount;      if ( v8 < v9 )        break;      v7 = v7->Next;    }    NetBuffer->Link.Region = (unsigned __int64)v7;    goto LABEL_5;  }  v13 = DataBackFill + DataOffsetDelta - v5;  if ( !AllocateMdlHandler )                    // AllocateMdlHandler=true    AllocateMdlHandler = ndisAllocateMdl;  v11 = (_MDL *)((__int64 (__fastcall *)(ULONG *))AllocateMdlHandler)(&v13);  if ( v11 )                                    // v11=true  {    v11->Next = NetBuffer->MdlChain;    v12 = v13;    NetBuffer->MdlChain = v11;    NetBuffer->Link.Region = (unsigned __int64)v11;    NetBuffer->DataOffset += v12 - DataOffsetDelta;    v8 = NetBuffer->DataOffset;    NetBuffer->DataLength += DataOffsetDelta;   // NetBuffer->DataLength=28LABEL_5:    NetBuffer->CurrentMdlOffset = v8;    return 0;  }  return -1073741670;}
Netbuffer在IDA中是没有这个Struct的这里也说一下怎么添加一个Struct
Shift+F1,右键Insert,粘贴添加即可。

这样IDA就可以识别了。


看看简化后的逻辑代码。
  if ( v15 < (unsigned __int16)BytesNeeded )  {    if ( NdisRetreatNetBufferDataStart(netbuffer, (unsigned __int16)BytesNeeded, 0, NetioAllocateMdl_0) < 0 )    {LABEL_8:      IppRemoveFromReassemblySet((PKSPIN_LOCK)(v7 + 20168));      NetioDereferenceNetBufferList_0(v13, 0i64);      goto LABEL_24;    }  }  else  {    netbuffer->DataOffset -= (unsigned __int16)BytesNeeded;    netbuffer->DataLength += (unsigned __int16)BytesNeeded;// ((a2+104)+40)   2个字节    netbuffer->CurrentMdlOffset = v15 - (unsigned __int16)BytesNeeded;  }  BytesNeededa = (char *)NdisGetDataBuffer(netbuffer, BytesNeeded, 0i64, 1u, 0);
如果第一个if条件为真第二个不成立的时候就直接到NdisGetDataBuffer,下断点到tcpip!Ipv6pReassembleDatagram并单步调试。
0: kd> ptcpip!Ipv6pReassembleDatagram+0xa:fffff880`01923a8a 53              push    rbx0: kd> ptcpip!Ipv6pReassembleDatagram+0xb:fffff880`01923a8b 55              push    rbp0: kd> ptcpip!Ipv6pReassembleDatagram+0xc:fffff880`01923a8c 56              push    rsi0: kd> ptcpip!Ipv6pReassembleDatagram+0xd:fffff880`01923a8d 57              push    rdi0: kd> ptcpip!Ipv6pReassembleDatagram+0xe:fffff880`01923a8e 4154            push    r120: kd> ptcpip!Ipv6pReassembleDatagram+0x10:fffff880`01923a90 4155            push    r130: kd> ptcpip!Ipv6pReassembleDatagram+0x12:fffff880`01923a92 4156            push    r140: kd> ptcpip!Ipv6pReassembleDatagram+0x14:fffff880`01923a94 4157            push    r150: kd> ptcpip!Ipv6pReassembleDatagram+0x16:fffff880`01923a96 4883ec58        sub     rsp,58h0: kd> ptcpip!Ipv6pReassembleDatagram+0x1a:fffff880`01923a9a 440fb74a68      movzx   r9d,word ptr [rdx+68h]0: kd> ptcpip!Ipv6pReassembleDatagram+0x1f:fffff880`01923a9f 8b426c          mov     eax,dword ptr [rdx+6Ch]0: kd> ptcpip!Ipv6pReassembleDatagram+0x22:fffff880`01923aa2 418af8          mov     dil,r8b0: kd> ptcpip!Ipv6pReassembleDatagram+0x25:fffff880`01923aa5 4103c1          add     eax,r9d0: kd> ptcpip!Ipv6pReassembleDatagram+0x28:fffff880`01923aa8 488bea          mov     rbp,rdx0: kd> ptcpip!Ipv6pReassembleDatagram+0x2b:fffff880`01923aab 898424b8000000  mov     dword ptr [rsp+0B8h],eax0: kd>tcpip!Ipv6pReassembleDatagram+0x32:fffff880`01923ab2 83c028          add     eax,28h0: kd> ptcpip!Ipv6pReassembleDatagram+0x35:fffff880`01923ab5 89442430        mov     dword ptr [rsp+30h],eax0: kd> ptcpip!Ipv6pReassembleDatagram+0x39:fffff880`01923ab9 418d4128        lea     eax,[r9+28h]0: kd> ptcpip!Ipv6pReassembleDatagram+0x3d:fffff880`01923abd 898424a8000000  mov     dword ptr [rsp+0A8h],eax0: kd> ptcpip!Ipv6pReassembleDatagram+0x44:fffff880`01923ac4 488b81d0000000  mov     rax,qword ptr [rcx+0D0h]0: kd>tcpip!Ipv6pReassembleDatagram+0x4b:fffff880`01923acb 33c9            xor     ecx,ecx0: kd>tcpip!Ipv6pReassembleDatagram+0x4d:fffff880`01923acd 488b5808        mov     rbx,qword ptr [rax+8]0: kd>tcpip!Ipv6pReassembleDatagram+0x51:fffff880`01923ad1 488b03          mov     rax,qword ptr [rbx]0: kd>tcpip!Ipv6pReassembleDatagram+0x54:fffff880`01923ad4 4c8bb088020000  mov     r14,qword ptr [rax+288h]0: kd>tcpip!Ipv6pReassembleDatagram+0x5b:fffff880`01923adb ff152ff80100    call    qword ptr [tcpip!_imp_KeGetCurrentProcessorNumberEx (fffff880`01943310)]0: kd>tcpip!Ipv6pReassembleDatagram+0x61:fffff880`01923ae1 488d0d48edefff  lea     rcx,[tcpip!IppReassemblyNetBufferListsComplete (fffff880`01822830)]0: kd>tcpip!Ipv6pReassembleDatagram+0x68:fffff880`01923ae8 448be8          mov     r13d,eax0: kd>tcpip!Ipv6pReassembleDatagram+0x6b:fffff880`01923aeb 488b8330030000  mov     rax,qword ptr [rbx+330h]0: kd>tcpip!Ipv6pReassembleDatagram+0x72:fffff880`01923af2 4533c9          xor     r9d,r9d0: kd>tcpip!Ipv6pReassembleDatagram+0x75:fffff880`01923af5 4e8b3ce8        mov     r15,qword ptr [rax+r13*8]0: kd>tcpip!Ipv6pReassembleDatagram+0x79:fffff880`01923af9 49c1e508        shl     r13,80: kd>tcpip!Ipv6pReassembleDatagram+0x7d:fffff880`01923afd 4533c0          xor     r8d,r8d0: kd>tcpip!Ipv6pReassembleDatagram+0x80:fffff880`01923b00 4d03ae284e0000  add     r13,qword ptr [r14+4E28h]0: kd>tcpip!Ipv6pReassembleDatagram+0x87:fffff880`01923b07 488bd5          mov     rdx,rbp0: kd>tcpip!Ipv6pReassembleDatagram+0x8a:fffff880`01923b0a c644242800      mov     byte ptr [rsp+28h],00: kd>tcpip!Ipv6pReassembleDatagram+0x8f:fffff880`01923b0f 8364242000      and     dword ptr [rsp+20h],00: kd>tcpip!Ipv6pReassembleDatagram+0x94:fffff880`01923b14 e8f3d7f2ff      call    tcpip!NetioAllocateAndReferenceNetBufferAndNetBufferList (fffff880`0185130c)0: kd>tcpip!Ipv6pReassembleDatagram+0x99:fffff880`01923b19 4c8be0          mov     r12,rax0: kd>tcpip!Ipv6pReassembleDatagram+0x9c:fffff880`01923b1c 4885c0          test    rax,rax0: kd>tcpip!Ipv6pReassembleDatagram+0x9f:fffff880`01923b1f 7517            jne     tcpip!Ipv6pReassembleDatagram+0xb8 (fffff880`01923b38)0: kd>tcpip!Ipv6pReassembleDatagram+0xb8:fffff880`01923b38 488b7008        mov     rsi,qword ptr [rax+8]0: kd>tcpip!Ipv6pReassembleDatagram+0xbc:fffff880`01923b3c 8b9c24a8000000  mov     ebx,dword ptr [rsp+0A8h]0: kd>tcpip!Ipv6pReassembleDatagram+0xc3:fffff880`01923b43 8b4610          mov     eax,dword ptr [rsi+10h]0: kd>tcpip!Ipv6pReassembleDatagram+0xc6:fffff880`01923b46 0fb7d3          movzx   edx,bx0: kd>tcpip!Ipv6pReassembleDatagram+0xc9:fffff880`01923b49 3bc2            cmp     eax,edx0: kd>tcpip!Ipv6pReassembleDatagram+0xcb:fffff880`01923b4b 724e            jb      tcpip!Ipv6pReassembleDatagram+0x11b (fffff880`01923b9b)0: kd>tcpip!Ipv6pReassembleDatagram+0x11b:fffff880`01923b9b 4c8d0dbeaff2ff  lea     r9,[tcpip!NetioAllocateMdl (fffff880`0184eb60)]0: kd>tcpip!Ipv6pReassembleDatagram+0x122:fffff880`01923ba2 4533c0          xor     r8d,r8d0: kd>tcpip!Ipv6pReassembleDatagram+0x125:fffff880`01923ba5 488bce          mov     rcx,rsi0: kd>tcpip!Ipv6pReassembleDatagram+0x128:fffff880`01923ba8 ff15c2020200    call    qword ptr [tcpip!_imp_NdisRetreatNetBufferDataStart (fffff880`01943e70)]0: kd>tcpip!Ipv6pReassembleDatagram+0x12e:fffff880`01923bae 85c0            test    eax,eax0: kd>tcpip!Ipv6pReassembleDatagram+0x130:fffff880`01923bb0 79a6            jns     tcpip!Ipv6pReassembleDatagram+0xd8 (fffff880`01923b58)0: kd>tcpip!Ipv6pReassembleDatagram+0xd8:fffff880`01923b58 8364242000      and     dword ptr [rsp+20h],00: kd> rrax=0000000000000000 rbx=0000000000000028 rcx=0000000000000038rdx=fffffa8033468541 rsi=fffffa8032587400 rdi=fffffa80322db002rip=fffff88001923b58 rsp=fffff80000b9dcd0 rbp=fffffa8033f5c6e0 r8=fffffa8033468540  r9=fffff8800184eb60 r10=fffffa8033468020r11=fffffa8033468540 r12=fffffa80325872d0 r13=fffffa80321ba900r14=fffff88001969870 r15=fffffa80334308d0iopl=0         nv up ei pl zr na po nccs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
没有进入到else语句而直接到了NdisGetDataBuffer处理,初步明白了原因,继续分析tcpip!Ipv6pReceiveFragment函数tcpip!Ipv6pReceiveFragment是处理包分片,它将数据排列后处理对最后一个分片包到来时进行重组。

包分片其实在上学的时候就应该说过了,如果数据包的大小超过最大传输单元(MTU)的时候就会重组,从而还原一条完整的流。

Ipv6pReassembleDatagram是主要的问题函数,用来处理嵌套分片包时NET_BUFFER结构中读取扩展头的长度+ sizeof(IPv6_header)字节。IPv6头的大小从上面的动态调试得知为0x28。


上面提到过MSDN指出NdisGetDataBuffer是会返回NULL的情况,可以使NET_BUFFER为NULL,NdisGetDataBuffer则返回NULL,而当在上下文被引用时则会触发BSOD空指针引用。

POC中可以看到通过特制的扩展头identification来使程序触发异常,关于包重组的细节在蝶澈的文章(https://bbs.pediy.com/thread-266955.htm)中阐述的我认为已经算是全网最详细的了,这里不再复述。


总结

协议栈的漏洞近几年MSRC也是极其少见,而该漏洞问题出现在空指针引用所以目前只能触发拒绝服务。关于TCP/IP的漏洞本人也是第一次分析,自己动手调试做下来遇到的问题也不少但也是一步步解决,漏洞挖掘和分析着实是一个拼细心和耐心的一份工作,所以文中如有错误的地方不吝赐教。

看雪ID:badboyl

https://bbs.pediy.com/user-home-748627.htm

*本文由看雪论坛 badboyl 原创,转载请注明来自看雪社区

# 往期推荐

1.堆、UAF之PWN从实验到原理

2.Frida inlineHook原理分析及简单设计一款AArch64 inlineHook工具

3.PWN学习笔记【格式化字符串漏洞练习】

4.Il2Cpp恢复符号过程分析

5.记一次安全产品的漏洞挖掘

6.CVE-2016-3309提权漏洞学习笔记

球分享

球点赞

球在看

点击“阅读原文”,了解更多!


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458458572&idx=1&sn=be165db07a411d492fd227c006a66cf6&chksm=b18e294686f9a050d7fab03d070e4b37c1012a93750e00774bfd8ae810ac7c2f384bad083896#rd
如有侵权请联系:admin#unsafe.sh