作者:林以
公眾號:支付寶安全實驗室

Oracle在北京時間4月15日發布了本年度第二次的Critical Patch Update Advisory,并在最新版VirtualBox(6.1.6)中修復了支付寶光年安全實驗室@鶩望與@林以提交的USB XHCI模塊的堆越界讀寫漏洞。這篇文章將對此漏洞進行分析。

VirtualBox USB XHCI漏洞模塊介紹

VirtualBox是一款虛擬化軟件,由于其開源屬性,在個人用戶中盛行。VirtualBox大部分模塊是開源的,但是部分模塊是以二進制插件包的形式發布,包括了,USB 2.0與 3.0虛擬設備,VirtualBox RDP協議模塊,硬盤加密,NVMe以及用于 Intel的 PXE引導部分。CVE-2020-2905 漏洞存在于 VirtualBox二進制插件包中的 USB 3.0 XHCI模塊。USB協議目前有三代接口標準,OHCI、UHCI都是 USB1.1的接口標準,而 EHCI是對應 USB2.0的接口標準,最新的 xHCI是 USB3.0的接口標準。在這里我們只需關注 XHCI協議的數據結構。

漏洞分析

漏洞簡介

該漏洞存在于二進制插件包 VBoxEhciR3.so中,VBoxEhciR3.so包括了 Ehci以及 Xhci的實現。VirtualBox在 6.1版本之后將插件包中的二進制的符號都給 strip了,這里我們以 6.0.14帶符號版本進行分析。復現環境中宿主機與虛擬機均為 Ubuntu,宿主機(Host)版本:

虛擬機(Guest)

漏洞成因

該漏洞是個數組越界讀寫,存在于 xhciR3WriteEvent函數, iIntr 參數可以被攻擊者控制。從IDA Pro的 Structures段可以得知 aInterrupters 數組只有8個元素(下圖所示),但是iIntr的值卻可以是0~1023。iIntr用來對 aInterrupters數組進行索引,但代碼未對iIntr值進行校驗,因此造成了堆溢出。

逆向分析回溯調用流,可發現,xhciR3WriteEvent的調用路徑是:

xhciR3WorkerLoop->xhciR3PostXferEvent->xhciR3WriteEvent

具體而言,當xhci模塊正常啟動時,它會調用xhciR3WorkerLoop函數。在該函數中,宿主機的xhci驅動會與虛擬機通過xhci命令進行通信。宿主機會等待xhci相應的物理寄存器的讀寫來進行響應。后面的文章我們將通過理清XHCI協議的相應數據結構來進行分析。

XHCI協議數據結構分析

虛擬機通過讀寫宿主機的物理地址來與宿主機響應驅動進行通信。通過在虛擬機中執行cat/proc/iomem命令,我們可以得知宿主機相應的驅動與其映射出來的物理地址,如下我們可知,xhci驅動對應的物理地址范圍是0xf1810000-0xf181ffff,0x10000個字節大小。

而xhci驅動會將物理地址轉換成xhci協議中的寄存器,當我們在虛擬機對物理地址進行讀寫時,其實就是對xhci協議的相應寄存器進行讀寫,讀者可查閱XHC Ispecification[1]來對xhci協議進行深入了解。

該漏洞的觸發需要CRCR以及DCBAAP兩個寄存器的配合:

CRCR寄存器

CRCR(Command Ring Control)寄存器存儲的內容用于對xhchi驅動進行控制,存儲著dequeue pointer,指針指向trb ring,trb ring是個數組存儲著trb結構體。對應到CRCR寄存器,存儲的是Command TRBs。Command TRBs包含了17個commands用來對宿主機xhci驅動發起命令,而xhciR3WorkerLoop函數就是在輪詢處理Command TRBs的command,包括了Enable Slot Command,Address Device Command,Stop Endpoint Command等commands,在specification 6.4.3節中定義。

這17個commands中,我們需要關注Stop Endpoint Command,xhciR3WorkerLoop就是在處理Stop Endpoint Commahnd中觸發了漏洞。我們就以Stop Endpoint Command TRB為例子來介紹TRB數據結構。一個TRB數據長128bits,在Stop Endpoint Command TRB中,前12個字節都是保留使用的,最后4個字節才有意義。其中TRB Type字段就是表明該TRB的類型,如果我們要發送Stop Endpoint Command,我們就要將該字段設為對應的值,Stop Endpoint Command對應值15。Slot ID最大值為32,即XHCI中最多擁有32個slot,slot的定義為:“Device Slot refers to the xHC interface associated with an individual USB device,e.g. the associated Device Context Base Address Array entry,a Doorbell Array register,and its Device Context.”

DCBAAP寄存器

DCBAAP(Device Context Base Address Array Pointer Register)存儲著指向Device Context Base Address Array的指針,該指針通過slot id來進行索引。而Device Context Base Address Array數組存儲著Device Context Data Structure數據結構,Device Context Data Structure共有 32個入口,第一個入口是Slot Context Data Structure,其余的入口是Endpoint Context Data Structure。

漏洞具體觸發方式

回到xhciR3WorkerLoop函數:

攻擊者需要首先調用CR_ENABLE_SLOT命令來開啟對應的slot,不然后續處理的時候遇到對應的slot沒開啟,程序會直接返回,在這里我們可以將所有32個 slot都開啟。

在CR_STOP_ENDPOINT命令處理代碼中,v134即slot id,通過v37 = xhciR3FetchDevCtxAddr(v2, v134);將對應slot id的Device Context Base Address Array的地址取出存到v37中,隨后在pfnPCIPhysRead調用中讀取 32字節到 icc_0變量中,由上文的XHCI協議數據結構分析中的Device Context Base Address Array結構分析可知,前32個字節應該是slot context數據結構。

隨后,驅動會調用xhciR3PostXferEvent函數,該函數的第二個參數為(unsigned __int16)(HIWORD(icc_0.resvd[0]) >> 6),即為被控制的icc_0中的數據。

參數(unsigned __int16)(HIWORD(icc_0.resvd[0]) >> 6)會傳至uIntTgt變量,最后會傳到xhciR3WriteEvent函數的iIntr參數,實現控制aInterrupters中的index的值。

由上述分析可知icc_0中存儲著slot context結構,我們需要分析出 (unsigned __int16)(HIWORD(icc_0.resvd[0]) >> 6)對應的 slot context中的字段,以此來控制iIntr。查看 IDA Pro中 icc_0 結構體的定義,我們可以得知 (unsigned __int16)(HIWORD(icc_0.resvd[0]) >> 6)是Slot Context Data Structure中的Interrupter Target字段。該字段有10bits長,值范圍是0~1023,意味著我們可以越界寫1023個元素長。

總結而言,分析清楚這些數據結構對應的關系之后,我們就可以構造poc來觸發該漏洞了,還有一些校驗字段由于篇幅原因略去分析了,讀者可以根據 specification以及 VirtualBox代碼的實現來bypass對應的校驗。

補丁分析

VirtualBox在6.1.6版本修復了該漏洞,查看補丁,漏洞修復很簡單,將iIntr值限定在0~7中。

可利用性分析

攻擊者可以進行越界寫,比如在函數xhciR3WriteEvent中變量v4是被攻擊者控制的,下面代碼會將v4 的值寫入v7->errp中,v7即是從aInterrupters數組中取出的越界的地址。

攻擊者通過內存布局,將代碼中的關鍵數據結構布局到越界寫的數據內容之后,可覆蓋關鍵數據結構的值,從而造成虛擬機逃逸。

引用

關于作者

支付寶光年安全實驗室: 隸屬于支付寶安全實驗室。通過對基礎軟件及設備的安全研究,達到全球頂尖破解能力,致力于保障螞蟻金服及行業金融級基礎設施安全。因發現并報告行業系統漏洞,數十次獲得Google、Apple等國際廠商致謝。

掃碼關注支付寶安全實驗室微信公眾號,干貨不斷!


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1188/