聯發科晶片Rootkit漏洞分析(CVE-2020-0069)

ADLab發表於2020-07-01

一、漏洞背景

2020年3月,谷歌修補了一個存在於聯發科晶片中的安全漏洞(CVE-2020-0069),漏洞影響20餘款聯發科晶片和數百萬Android裝置。該漏洞存在於MediaTek Command Queue驅動(CMDQ命令佇列驅動),允許本地攻擊者實現對實體記憶體地址的任意讀寫,從而導致許可權提升。


二、受影響國產手機型號

Huawei GR3 TAG-L21

Huawei Y5II

Huawei Y6II MT6735 series

Lenovo A5

Lenovo C2 series

Lenovo Tab E7

Lenovo Tab E8

Lenovo Tab2 A10-70F

Meizu M5c

Meizu M6

Meizu Pro 7 Plus

Oppo A59 series

Oppo A5s

Oppo A7x -- up to Android 8.x

Oppo F5 series/A73 -- up to A.39

Oppo F7 series -- Android 8.x only

Oppo F9 series -- Android 8.x only

Oppo R9xm series

Xiaomi Redmi 6/6A series

ZTE Blade A530

ZTE Blade D6/V6

ZTE Quest 5 Z3351S


三、CMDQ驅動簡析

DMA(直接記憶體訪問)是允許專用硬體直接從主儲存器(RAM)傳送或接收資料的一種特性。其目的是透過允許大記憶體訪問而不過多佔用CPU來加速系統。MediaTek Command Queue驅動(CMDQ命令佇列驅動)允許從使用者層與DMA控制器通訊,以實現媒體或顯示相關的任務。

基於Redmi 6/6A 原始碼分析,在cmdq_driver.h標頭檔案中,宣告cmdq驅動的IOCTL呼叫如下:

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


(1)CMDQ_IOCTL_ALLOC_WRITE_ADDRESS指令為分配一個DMA緩衝區

(2)CMDQ_IOCTL_FREE_WRITE_ADDRESS指令為釋放一個DMA緩衝區

(3)CMDQ_IOCTL_READ_WRITE_ADDRESS指令為讀取一個DMA緩衝區中的資料

(4)CMDQ_IOCTL_EXEC_COMMAND指令執行傳送其他命令


1、 分配過程

透過CMDQ_IOCTL_ALLOC_WRITE_ADDRESS呼叫cmdqCoreAllocWriteAddress ()函式,分配一個DMA緩衝區,該函式關鍵程式碼實現如下:

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)



然後,呼叫cmdq_core_alloc_hw_buffer()函式分配DMA緩衝區,pWriteAddr->va是虛擬地址,pWriteAddr->pa為實體地址,兩者一一對應。並清理緩衝區。

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


最後,將實體地址賦值到*paStart,並將pWriteAddr結構體新增到gCmdqContext.writeAddrList連結串列中。


2、 執行命令過程


在CMDQ_IOCTL_EXEC_COMMAND呼叫中,採用cmdqCommandStruct結構體作為引數,結構體定義如下:

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


pVABase指向使用者層存放命令的緩衝區,緩衝區大小放在blockSize中。其中cmdqReadAddressStruct結構體定義如下:

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


DmaAddresses是要讀取的實體地址,讀取的值存放在values中。在CMDQ_IOCTL_EXEC_COMMAND命令的執行過程,實現程式碼如下:

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


函式呼叫路徑如下:

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


Cmdq_core_acquire_task()函式會將command繫結到task中執行。具體實現如下:

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


呼叫cmdq_core_find_free_task()函式獲取一個空閒task。拿到空閒task並進行一些初始化設定,然後開始呼叫cmdq_core_insert_read_reg_command()函式執行命令。

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


該函式實現分析,先複製使用者層傳入的命令到DMA緩衝區中。

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


pCommandDesc->pVABase是存放命令的記憶體起始地址。複製完命令後,後面分幾種方式結尾。

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


這裡不做深究,最後複製EOC和JUMP指令結尾。這裡也是將使用者層傳入的命令複製過來。

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


從cmdq_core_acquire_task()函式中返回後,如下:

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


呼叫cmdq_core_consume_waiting_list()函式執行task。先從等待佇列中獲取task。

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


然後,獲取空閒核心執行緒。

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)

最後,將task繫結到thread中去執行。

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


四、讀寫命令分析


以cmdq_test.c測試程式碼為例,分析理解一個完整的讀寫命令構造。cmdq驅動中定義了兩類暫存器,一類是地址暫存器用於存放地址,一類是數值暫存器用於存放讀取或寫入的數值。

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


regResults是虛擬地址,呼叫cmdq_core_alloc_hw_buffer()函式分配一個dma地址,regResultsMVA與之對應,然後設定regResults中的資料。開始拼接讀取和寫入命令:

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


將regResults[0]的地址寫入CMDQ_DATA_REG_DEBUG_DST型別的地址暫存器中。

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


然後,從CMDQ_DATA_REG_DEBUG_DST地址暫存器中讀取資料並寫入到CMDQ_DATA_REG_DEBUG數值暫存器中。這時候,CMDQ_DATA_REG_DEBUG數值暫存器中的值應該為0xdeaddead。

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


接著,將regResults[1]的地址轉存到CMDQ_DATA_REG_DEBUG_DST地址暫存器中。

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


最後,將CMDQ_DATA_REG_DEBUG數值暫存器中的0xdeaddead寫入到CMDQ_DATA_REG_DEBUG_DST地址暫存器中儲存的regResults[1]的地址中。即regResults[1]=0xdeaddead。判斷regResults[0]和regResults[1]是否相等。

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


如果相等,說明讀寫成功。


五、PoC分析與測試


(1)PoC程式碼中,執行寫操作的關鍵程式碼如下:

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


寫入過程中,先將value[count]移動到CMDQ_DATA_REG_DEBUG數值暫存器中,然後將pa_address+offset地址移動到CMDQ_DATA_REG_DEBUG_DST地址暫存器中,最後將CMDQ_DATA_REG_DEBUG數值暫存器中的value寫入到CMDQ_DATA_REG_DEBUG_DST地址暫存器中儲存的pa_address+offset地址中,即*(pa_address+offset) = value[count]。


(2)PoC程式碼中,執行讀操作的關鍵程式碼如下:

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


讀取過程中,第一步先將pa_address+offset地址移動到CMDQ_DATA_REG_DEBUG_DST地址暫存器中,然後從CMDQ_DATA__REG_DEBUG_DST地址暫存器中儲存的地址pa_address+offset中讀取資料放到CMDQ_DATA_REG_DEBUG資料暫存器中,再將dma_address+offset地址移動到CMDQ_DATA_REG_DEBUG_DST地址暫存器中,最後將CMDQ_DATA_REG_DEBUG數值暫存器中儲存的資料寫入到CMDQ_DATA_REG_DEBUG_DST地址暫存器中儲存的dma_address+offset地址中,即*(dma_address + offset) = *(pa_address + offset)。


3)在Reami6測試機中,執行PoC測試,成功將Linux修改成minix。

聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


六、參考連結

1、https://github.com/MiCode/Xiaomi_Kernel_OpenSource/tree/cactus-p-oss/drivers/misc/mediatek/cmdq

2、https://github.com/quarkslab/CVE-2020-0069_poc/blob/master/jni/kernel_rw.c

3、https://blog.quarkslab.com/cve-2020-0069-autopsy-of-the-most-stable-mediatek-rootkit.html

4、https://forum.xda-developers.com/android/development/amazing-temp-root-mediatek-armv8-t3922213

5、https://source.android.com/security/bulletin/2020-03-01


聯發科晶片Rootkit漏洞分析(CVE-2020-0069)


相關文章