Windows Server中的 WINS 伺服器遠程內存損壞漏洞分析
漏洞概要
在2016年12月,FortiGuard Labs發現並報告了Microsoft Windows Server中的WINS Server遠程內存損壞漏洞。在2017年6月,微軟向FortiGuard實驗室答覆說:「要修復程序漏洞需要對代碼進行全面徹底的檢查,WINS所提供的功能會被DNS所取代,微軟已經建議客戶將其遷移出去。也就是說,由於修復漏洞所需要的工作量,Microsoft不會修補此漏洞。相反,Microsoft是建議用戶使用DNS來替換WINS。
此漏洞影響的版本涉及到Windows Server 2008,2012和2016。之所以存在此漏洞是因為在處理格式錯誤的WINS數據包時會觸發遠程內存損壞。
在本文中,我想分享一下這個漏洞的一些細節。
漏洞復現
要復現此漏洞,請按照以下步驟操作。
1. 在受影響的Windows Server版本中的「伺服器管理器」中安裝「WINS伺服器」。本文中,我們正在使用的是Windows Server 2016.按照「伺服器管理器」的安裝嚮導,然後選中「WINS伺服器」選項。請參見圖1中的操作。
圖1.安裝WINS Server服務
2. 打開「控制面板」 - >「管理工具」 - >「WINS」。然後導航到「WINS」 - >「複製夥伴」,右鍵單擊「複製夥伴」,然後選擇「新建複製夥伴」。見下圖中的操作。
圖2.創建WINS複製夥伴
3. 在彈出的對話框中,輸入WINS伺服器IP地址,然後單擊確定。請注意,WINS伺服器的IP地址必須是攻擊者的主機的IP地址。在我的測試中,IP地址為10.0.0.1。請參見圖3中的操作。
圖3.輸入WINS伺服器IP地址
4. 在另一台機器上,如Windows 7 x64(這台主機的IP地址必須是你在步驟3中輸入的WINS伺服器的IP地址),然後在CLI中運行PoC,如「trigger_poc.py」。發送數據包後,你就可以看到Windows Server 2016上的WINS Server服務會停止工作,或者會使用新的pid自動重新啟動進程。你可以繼續運行PoC,直到由於遠程內存的損壞而導致WINS Server服務完全停止工作。捕獲的攻擊報文如圖4所示。
圖4.捕獲的攻擊報文
漏洞分析
存在此漏洞的根本原因在於Windows Server未正確處理多個掛起的WINS-Replication會話。所以讓我們先來看看捕獲的數據包。參見圖5。
圖5.攻擊數據包中的數據
圖6.「int 29h」,錯誤代碼為0xC0000409
「int 29h」是在Windows 8或更新版本中發現的新的安全聲明。它有許多斷言。在這裡,斷言在偽代碼中檢查了以下條件:損壞的列表指針。
if (((Entry->Flink)->Blink) != Entry){ mov ecx,3 int 29h }
當我們建立了多個掛起的WINS-Replication會話時,列表指針將被破壞。根本原因是將同一個緩衝區多次釋放到了列表池。請參閱以下代碼:
.text:00007FF7F87E35D4 DeallocEnt proc near ; CODE XREF: CommAssocDeallocAssoc+2Ap .text:00007FF7F87E35D4 ; CommAssocDeallocDlg+2Ap .text:00007FF7F87E35D4 ; DATA XREF: ... .text:00007FF7F87E35D4 .text:00007FF7F87E35D4 arg_0 = qword ptr 8 .text:00007FF7F87E35D4 arg_8 = qword ptr 10h .text:00007FF7F87E35D4 arg_10 = qword ptr 18h .text:00007FF7F87E35D4 arg_20 = qword ptr 28h .text:00007FF7F87E35D4 arg_28 = qword ptr 30h .text:00007FF7F87E35D4 .text:00007FF7F87E35D4 mov [rsp+arg_0], rbx .text:00007FF7F87E35D9 mov [rsp+arg_8], rsi .text:00007FF7F87E35DE mov [rsp+arg_10], r8 .text:00007FF7F87E35E3 push rdi .text:00007FF7F87E35E4 sub rsp, 20h .text:00007FF7F87E35E8 mov rbx, r9 .text:00007FF7F87E35EB mov rsi, r8 .text:00007FF7F87E35EE mov rdi, rdx ---> rdi points to the head of the list (rdx, named entry A here) which equals sAssocQueHd global variable .text:00007FF7F87E35F1 mov rcx, r8 ; lpCriticalSection .text:00007FF7F87E35F4 call cs:__imp_EnterCriticalSection .text:00007FF7F87E35FA nop .text:00007FF7F87E35FB inc dword ptr [rbx] .text:00007FF7F87E35FD mov eax, [rbx] .text:00007FF7F87E35FF mov rbx, [rsp+28h+arg_20] ; ---> rbx points to the entry B, which will be deallocated .text:00007FF7F87E3604 mov [rbx+10h], eax .text:00007FF7F87E3607 mov rax, [rdi+8] .text:00007FF7F87E360B cmp [rax], rdi .text:00007FF7F87E360E jz short loc_7FF7F87E3617 .text:00007FF7F87E3610 mov ecx, 3 .text:00007FF7F87E3615 int 29h ; Win8: RtlFailFast(ecx) .text:00007FF7F87E3617 .text:00007FF7F87E3617 loc_7FF7F87E3617: ; CODE XREF: DeallocEnt+3Aj .text:00007FF7F87E3617 mov [rbx], rdi ---> entry B』s Blink points to entry A .text:00007FF7F87E361A mov [rbx+8], rax ---> entry B』s Flink points to entry C .text:00007FF7F87E361E mov [rax], rbx ----> set entry C』s Blink to entry B .text:00007FF7F87E3621 mov [rdi+8], rbx ----> set entry A』s Flink to entry B .text:00007FF7F87E3625 mov rdi, [rsp+28h+arg_28] .text:00007FF7F87E362A cmp dword ptr [rdi], 64h...
在上面的列表中,Flink指針指向列表中的下一個複習,Blink指針指向列表中的上一個對象。
在PoC中,在會話1,2,3之後發送兩個數據包並保持處於掛起狀態(用過發送TCP重置數據包這兩個會話不會被終止),首先使用B指針調用釋放分配函數,例如0x1f11306ff70 。A(ListHead)指針始終等於全局變數sAssocQueHd。分配是在父函數中完成的。所以在B被釋放之後,C將不存在於第一個釋放列表中。關係如下表所示。
之後用B指針第二次調用釋放分配函數,它仍然等於0x1f11306ff70。A(ListHead)等於全局變數sAssocQueHd。所以在B被釋放之後,沒有添加新的條目。條目關係如下圖所示。
你可以清楚地看到, 釋放分配函數被調用了兩次,B中的列表元素Flink和Blink指向了它們自己。這會導致列表錯誤。
那麼這個deallocate函數將被第三次調用。所以「int 29h」由於列表指針檢查被破壞而觸發。
if (((Entry->Flink)->Blink) != Entry) { mov ecx,3 int 29h }
在以下函數中處理帶有Assoc_Ctx的WREPL_REPL_UPDATE2數據包時,對象指針將會設置為相同的指針:
.text:00007FF7F87E0190 ProcTcpMsg proc near ; CODE XREF: MonTcp+4C5p .text:00007FF7F87E0190 ; DATA XREF: .pdata:00007FF7F88077D4o .text:00007FF7F87E0190 ...... .text:00007FF7F87E0284 loc_7FF7F87E0284: ; CODE XREF: ProcTcpMsg+EDj .text:00007FF7F87E0284 mov ecx, [r15+4] ---> netlong here was obtained from the second packet (Wirehark parses it as "WINS-Replication WREPL_REPL_UPDATE2"), "Assoc_Ctx"="00 00 00 3f". .text:00007FF7F87E0288 call cs:__imp_ntohl .text:00007FF7F87E028E mov esi, eax ---> here esi=0x3f .text:00007FF7F87E0290 mov ecx, [r15+8] ; netlong ...... .text:00007FF7F87E0382 loc_7FF7F87E0382: ; CODE XREF: ProcTcpMsg+1EAj .text:00007FF7F87E0382 lea ecx, [rsi-1] .text:00007FF7F87E0385 mov rax, qword ptr cs:xmmword_7FF7F8804D28 .text:00007FF7F87E038C mov rbx, [rax+rcx*8] ; ---> here rbx = poi(7FF7F8804D28)+0x3e*8, because rcx is obtained from Assoc_Ctx=0x3f -1 .text:00007FF7F87E0390 xor esi, esi
從上面的代碼段可以看出,一旦獲得了對象指針poi(poi(7FF7F8804D28)+0x3e*8
,最終的目標指針(之前傳遞給條目B的指針)在第一次調用釋放分配函數時是確定的,它被分配了B指針。在第二次和第三次調用釋放函數時,最終的目標指針(入口B指針)保持不變。在我的測試中,它是1306 1306 ff70 f1。這將導致內存損壞。
注意:poi是獲取地址的值的函數。
總而言之,該漏洞是由於複製命令WREPL_REPL_UPDATE2(這是觸發此漏洞的關鍵)處理多個(> 3)掛起的WINS複製會話所導致的。其結果是相同的列表條目被多次釋放,這就導致了遠程內存損壞。
漏洞緩解措施
我們鼓勵那些易受攻擊的Microsoft Windows Server的所有用戶立即從WINS伺服器進行遷移。另外,針對此漏洞,已經部署了Fortinet IPS解決方案的企業組織已經通過MS.Windows.WINS.Server.Remote.Memory.Corruption簽名得到保護。
點擊展開全文
※Erebus以Linux勒索軟體的方式重出江湖,勒索韓國公司100萬美元
※深度解密:美國近2億選民身份信息泄漏始末
※基於USB armory 製作一個USB惡意軟體分析器
※英國軍工巨頭BAE將大規模尖端監控軟體Evident售往中東
※惠普印表機爆遠程命令執行漏洞,黑客可任意操縱你的印表機
TAG:嘶吼RoarTalk |
※Windows 上的 SSH?使用 PowerShell Remoting 遠程管理 Windows 伺服器
※配置SAP Solution Manager連接監控遠程Microsoft SQL Server
※從Linux到Windows的PowerShell遠程處理
※影響所有Windows版本遠程桌面應用的CredSSP漏洞分析
※如何將Mikrotik/Cisco日誌保存到遠程SYSLOG伺服器
※Microsoft Exchange Server遠程代碼執行漏洞-高危
※YellowScan公司的無人機用高密度、遠程LiDAR Surveyor Ul
※Windows和Ubuntu系統如何遠程連接Linux伺服器
※看我如何通過Tor Onion在Windows中執行遠程Shell
※硬體黑客工具Packet Squirrel之二:實現openVPN遠程訪問
※PS4 Remote Play登錄iOS平台,你可以使用iPhone/iPad遠程玩PS4遊戲了
※iPhone接收Taiwan旗幟表情時奔潰——遠程IOS bug?
※遠程控制軟體AnyDesk—完美替代teamviwer
※Oracle WebLogic Server反序列化遠程代碼執行漏洞成焦點
※ManageEngine Applications Manager 遠程代碼執行漏洞
※簡記siteserver遠程模板下載Getshell漏洞
※通過SSRF漏洞攻擊Docker遠程API獲取伺服器Root許可權
※使用JuiceSSH在安卓手機上管理遠程VPS伺服器,linux系統
※支持HoloLens,AR遠程協同應用HoloMeeting發布
※Windows遠程及本地運行Linux的GUI程序