searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

如何在高通平台通过驱动漏洞绕过地址随机化

2024-08-21 09:43:15
22
0

概述

本文档主要是针对高通平台驱动fastrpc某个漏洞介绍以下内容:一是漏洞情况分析,和提权过程部分流程,如绕过内核地址随机化(KASLR)。

提权过程

DoubleFree

从《漏洞成因》文档可以看出,该漏洞本质是竞态导致的UAF。发生UAF的函数有fastrpc_mmap_on_dsp()和fastrpc_mmap_free()。这里我们主要关注后者,相关代码如下:
图片1.png

图片2.png

图片3.png

从上述代码可以看出,该函数根据map的数据进行清理。程序首先需要使该函数成功执行kfree函数(行732),使得map对应的SLAB发生Double Free。为了完成上述目的,程序需要针对该函数逻辑堆喷已经释放的SLAB。这里关键点是map->flags和map->refs字段。

首先,我希望该函数执行695行处的分支,原因是该分支需要构造的数据最少,且逻辑简单。所以,map->flags的值需要为FASTRPC_DMAHANDLER_NOMAP。当flags为上述值时,该函数会执行675处的逻辑。为了使kfree()执行,这里要使map->refs为1。其他字段均为0,这样该函数可以欢快地执行kfree(),导致Double Free产生。为了完成该目标,我使用了setxattr系统调用进行堆喷,最终会调用setxattr():

图片4.png

该函数会为kvalue分配空间(行434),长度由用户控制,然后从用户拷贝数据(行440)。所以,我可以分配指定长度、内容可用的SLAB。堆喷成功后,会导致同一个SLAB在SLUB的freelist的链表中出现两次,这意味着后续kmalloc()会将同一个SLAB返回两次(这是攻击的核心点)。

目前,SLUB的freelist状态如下:
图片5.png

注意这里实际上是同一个SLAB:

图片6.png

由于kmalloc()是从通用的SLUB中分配SLAB(比如kmalloc-256),所以待分配的SLAB的前8个字节存放下一个待分配的SLAB地址(图示红色区域),从而形成单向链表。

信息泄露

为了绕过内核地址随机化(KASLR),我需要泄露内核某个全局变量的地址。这里用的是seq_file结构体。该结构体定义如下:

图片7.png

当用户进程打开/proc/下某个节点时(比如/proc/cpuinfo),内核seq_open()会创建相应的seq_file对象。选择该对象的原因是:一是它使用的SLAB与发生Double Free 的map使用的SLAB一样大,意味着该类对象会出现两个对象使用同一个SLAB的情况;二是该结构体中的buf字段与SLUB存放下一个待分配的SLAB地址的偏移相同;三是当用户进程读取节点内容时(read /proc/cpuinfo),内核会在buf中格式化信息,然后将buf中的信息拷贝至用户态;四是该结构体中的op字段指向全局变量cpuinfo_op。

我通过打开多个/proc/cpuinfo节点使内核分配多个seq_file。其中有两个seq_file会使用同一个SLAB:

图片8.png

此时,我读取victim_fd1中的数据,内核会在buf中格式化字符串。读取的长度是offsetof(seq_file, op),读取成功后,seq_file对象会记录用户读取到哪个位置,下次再读取时,将从上次读取的末尾开始继续拷贝。

此时我先关闭另外一个/proc/cpuinfo文件(相关fd为leak_fd),此时freelist指向该seq_file使用过的SLAB(B):
图片9.png

然后我释放victim_fd0,freelist指向该seq_file使用过的SLAB,同时,将B的地址保存在前8个字节位置(也就是buf的位置):

图片10.png

由于victim_fd1仍然使用该SLAB,经过上述过程后,seq_file->buf被SLUB“篡改”为B的地址,此时,再从victim_fd1中读取时,将把B遗留的历史信息读取出来,实际也是seq_file的数据,这样就可以读出cpuinfo_op的地址,从而绕过内核地址随机化。

0条评论
0 / 1000
txyzj
4文章数
0粉丝数
txyzj
4 文章 | 0 粉丝
原创

如何在高通平台通过驱动漏洞绕过地址随机化

2024-08-21 09:43:15
22
0

概述

本文档主要是针对高通平台驱动fastrpc某个漏洞介绍以下内容:一是漏洞情况分析,和提权过程部分流程,如绕过内核地址随机化(KASLR)。

提权过程

DoubleFree

从《漏洞成因》文档可以看出,该漏洞本质是竞态导致的UAF。发生UAF的函数有fastrpc_mmap_on_dsp()和fastrpc_mmap_free()。这里我们主要关注后者,相关代码如下:
图片1.png

图片2.png

图片3.png

从上述代码可以看出,该函数根据map的数据进行清理。程序首先需要使该函数成功执行kfree函数(行732),使得map对应的SLAB发生Double Free。为了完成上述目的,程序需要针对该函数逻辑堆喷已经释放的SLAB。这里关键点是map->flags和map->refs字段。

首先,我希望该函数执行695行处的分支,原因是该分支需要构造的数据最少,且逻辑简单。所以,map->flags的值需要为FASTRPC_DMAHANDLER_NOMAP。当flags为上述值时,该函数会执行675处的逻辑。为了使kfree()执行,这里要使map->refs为1。其他字段均为0,这样该函数可以欢快地执行kfree(),导致Double Free产生。为了完成该目标,我使用了setxattr系统调用进行堆喷,最终会调用setxattr():

图片4.png

该函数会为kvalue分配空间(行434),长度由用户控制,然后从用户拷贝数据(行440)。所以,我可以分配指定长度、内容可用的SLAB。堆喷成功后,会导致同一个SLAB在SLUB的freelist的链表中出现两次,这意味着后续kmalloc()会将同一个SLAB返回两次(这是攻击的核心点)。

目前,SLUB的freelist状态如下:
图片5.png

注意这里实际上是同一个SLAB:

图片6.png

由于kmalloc()是从通用的SLUB中分配SLAB(比如kmalloc-256),所以待分配的SLAB的前8个字节存放下一个待分配的SLAB地址(图示红色区域),从而形成单向链表。

信息泄露

为了绕过内核地址随机化(KASLR),我需要泄露内核某个全局变量的地址。这里用的是seq_file结构体。该结构体定义如下:

图片7.png

当用户进程打开/proc/下某个节点时(比如/proc/cpuinfo),内核seq_open()会创建相应的seq_file对象。选择该对象的原因是:一是它使用的SLAB与发生Double Free 的map使用的SLAB一样大,意味着该类对象会出现两个对象使用同一个SLAB的情况;二是该结构体中的buf字段与SLUB存放下一个待分配的SLAB地址的偏移相同;三是当用户进程读取节点内容时(read /proc/cpuinfo),内核会在buf中格式化信息,然后将buf中的信息拷贝至用户态;四是该结构体中的op字段指向全局变量cpuinfo_op。

我通过打开多个/proc/cpuinfo节点使内核分配多个seq_file。其中有两个seq_file会使用同一个SLAB:

图片8.png

此时,我读取victim_fd1中的数据,内核会在buf中格式化字符串。读取的长度是offsetof(seq_file, op),读取成功后,seq_file对象会记录用户读取到哪个位置,下次再读取时,将从上次读取的末尾开始继续拷贝。

此时我先关闭另外一个/proc/cpuinfo文件(相关fd为leak_fd),此时freelist指向该seq_file使用过的SLAB(B):
图片9.png

然后我释放victim_fd0,freelist指向该seq_file使用过的SLAB,同时,将B的地址保存在前8个字节位置(也就是buf的位置):

图片10.png

由于victim_fd1仍然使用该SLAB,经过上述过程后,seq_file->buf被SLUB“篡改”为B的地址,此时,再从victim_fd1中读取时,将把B遗留的历史信息读取出来,实际也是seq_file的数据,这样就可以读出cpuinfo_op的地址,从而绕过内核地址随机化。

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0