freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

99+
联发科芯片Rootkit漏洞分析(CVE-2020-0069)
ADLab 2020-07-06 13:58:58 371784
所属地 北京

一、漏洞背景

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调用如下:

772334_MW592MV7PPNJZH4.jpg

(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缓冲区,该函数关键代码实现如下:

772334_T9D2BMMJVD6CJNM.jpg

然后,调用cmdq_core_alloc_hw_buffer()函数分配DMA缓冲区,pWriteAddr->va是虚拟地址,pWriteAddr->pa为物理地址,两者一一对应。并清理缓冲区。

772334_P55NBJKCT2H4TPE.jpg

最后,将物理地址赋值到*paStart,并将pWriteAddr结构体添加到gCmdqContext.writeAddrList链表中。

2、 执行命令过程

在CMDQ_IOCTL_EXEC_COMMAND调用中,采用cmdqCommandStruct结构体作为参数,结构体定义如下:

772334_TUFH3JRDCDJ5JNS.jpg

pVABase指向用户层存放命令的缓冲区,缓冲区大小放在blockSize中。其中cmdqReadAddressStruct结构体定义如下:

772334_9Z9MU4VHW2M4T9N.jpg

DmaAddresses是要读取的物理地址,读取的值存放在values中。在CMDQ_IOCTL_EXEC_COMMAND命令的执行过程,实现代码如下:

772334_J94BVV997WYENZ5.jpg

函数调用路径如下:

772334_GZC75PTQG2N6E3Z.jpg

Cmdq_core_acquire_task()函数会将command绑定到task中执行。具体实现如下:

772334_ZHJ4UKASFF4M8DA.jpg

调用cmdq_core_find_free_task()函数获取一个空闲task。拿到空闲task并进行一些初始化设置,然后开始调用cmdq_core_insert_read_reg_command()函数执行命令。

772334_R32CDBFYXJG5UP2.jpg

该函数实现分析,先拷贝用户层传入的命令到DMA缓冲区中。

772334_58YZ7JDP6JMHSX6.jpg

pCommandDesc->pVABase是存放命令的内存起始地址。拷贝完命令后,后面分几种方式结尾。

772334_5SZRAU4GUFD7XWV.jpg

这里不做深究,最后拷贝EOC和JUMP指令结尾。这里也是将用户层传入的命令拷贝过来。

772334_DB7Y3QPRHTTYGMA.jpg

从cmdq_core_acquire_task()函数中返回后,如下:

772334_WG8WERE9K7GVS66.jpg

调用cmdq_core_consume_waiting_list()函数执行task。先从等待队列中获取task。

772334_J8DUBJDTWMA2YSS.jpg

然后,获取空闲内核线程。

772334_22TXMQ9WAU3QVV9.jpg

最后,将task绑定到thread中去执行。

772334_T4ECXV6CTMQUKYV.jpg

四、读写命令分析

以cmdq_test.c测试代码为例,分析理解一个完整的读写命令构造。cmdq驱动中定义了两类寄存器,一类是地址寄存器用于存放地址,一类是数值寄存器用于存放读取或写入的数值。

772334_F8SQXWXFJYCHUQ4.jpg

regResults是虚拟地址,调用cmdq_core_alloc_hw_buffer()函数分配一个dma地址,regResultsMVA与之对应,然后设置regResults中的数据。开始拼接读取和写入命令:

772334_6DX7YUZD5AKZFZ4.jpg

将regResults[0]的地址写入CMDQ_DATA_REG_DEBUG_DST类型的地址寄存器中。

772334_N74WJ7AVUMF5H22.jpg

然后,从CMDQ_DATA_REG_DEBUG_DST地址寄存器中读取数据并写入到CMDQ_DATA_REG_DEBUG数值寄存器中。这时候,CMDQ_DATA_REG_DEBUG数值寄存器中的值应该为0xdeaddead。

772334_GS67MKP4BUEM6PP.jpg

接着,将regResults[1]的地址转存到CMDQ_DATA_REG_DEBUG_DST地址寄存器中。

772334_G28JKG9ATKJ2RTH.jpg

最后,将CMDQ_DATA_REG_DEBUG数值寄存器中的0xdeaddead写入到CMDQ_DATA_REG_DEBUG_DST地址寄存器中保存的regResults[1]的地址中。即regResults[1]=0xdeaddead。判断regResults[0]和regResults[1]是否相等。

772334_BSU89A8ASY4M74D.jpg

如果相等,说明读写成功。

五、PoC分析与测试

(1)PoC代码中,执行写操作的关键代码如下:

772334_Y35YURXJUH9TJFT.jpg

写入过程中,先将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代码中,执行读操作的关键代码如下:

772334_GPTK6MDNNYXGYWV.jpg

读取过程中,第一步先将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。

772334_JUXAKC3DCZ8NP43.jpg

六、参考链接

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

# 数据泄露 # 系统安全 # 系统安全 # 数据安全 # 数据安全 # Android
本文为 ADLab 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
ADLab LV.5
启明星辰积极防御实验室
  • 36 文章数
  • 44 关注者
DeepSeek启示:深度揭秘基于PTX的GPU底层优化技术
2025-03-20
银狐突袭!DeepSeek本地化部署暗藏“致命陷阱”
2025-03-20
使用DeepSeek-R1在固件漏洞挖掘领域的新实践
2025-03-19
文章目录