Linux 内核 TEE 子系统中UAF漏洞的模糊测试和利用 - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

Linux 内核 TEE 子系统中UAF漏洞的模糊测试和利用

h1apwn 技术 2022-02-24 16:50:00
238914
收藏

导语:最近在 Linux 内核 TEE 子系统中发现了一个释放后重引用(UAF)漏洞,影响版本小于等于 5.15.11,分配了CVE编号 CVE-2021-44733。

最近在 Linux 内核 TEE 子系统中发现了一个释放后重引用(UAF)漏洞,影响版本小于等于 5.15.11,分配了CVE编号 CVE-2021-44733。

简单的UAF无法进一步利用,在对漏洞代码路径做了进一步分析,简单写了个PoC测试后发现是可以覆盖Linux内核中的函数指针的,本文没有提供权限提升的漏洞利用代码,但是在环境设置部分提供了运行OPTTE和漏洞利用的测试环境。

0x01 背景信息

TEE是Trusted Execution Environment,也就是可信执行环境,通常用于数字版权保护(Digital Rights Management)、移动支付保护、敏感数据保护。TEE的实现是基于ARM TrustZone。

需要介绍的另一个概念是REE,也就是Rich Execution Environment,被称为通用执行环境,这是所有移动设备的通用运行环境,运行Android、iOS 系统。OS的代码量庞杂很容易出现漏洞,OS可以读写APP软件中的所有数据,存在大量针对REE的高级攻击技术和漏洞利用代码。

TEE受硬件机制的保护,TEE隔离于REE,只能通过特定入口和TEE进行通信;TEE可以访问REE的内存,可以抵御某些硬件攻击。

TEE实质上是一个可信子操作系统,比如最常见的ARM CPU上的TrustZone,运行在CPU芯片中的子OS,TEE驱动程序会处理TEE OS和上层操作之间的通信。

TEE 子系统会对TEE驱动程序进行注册初始化、会管理Linux 和 TEE的共享内存、会为TEE提供通用API。

驱动程序注册初始化步骤:
1. 根据设备类型,构造所需描述驱动的结构体。该结构体需要继承struct device_driver结构,并给几个重要的成员初始化。
2. 通过module_init宏调用驱动程序的初始化函数xx_init_module,在初始化函数中注册驱动程序。
3.驱动程序会遍历总线上的struct device和struct device_driver两条链表,调用总线的match函数,对设备与驱动程序进行匹配。
4.如果设备与驱动程序匹配成功,则调用驱动程序的probe函数。

什么是注册驱动程序:
初始化函数中调用的xx_register_driver函数就是注册驱动程序,初始化函数执行其实非常简单,执行一下xx_register_driver函数就会返回,这也是Linux驱动程序的标准注册流程:module_init-->xx_init_module-->xx_register_driver。

TEE接口

include/uapi/linux/tee.h中的结构体和宏定义提供了TEE的通用使用接口,用户空间和客户端可通过打开/dev/tee[0-9] 或 /dev/teepriv[0-9] 连接TEE驱动程序。

下面是在include/uapi/linux/tee.h中定义的结构体接口:

TEE_IOC_SHM_ALLOC 分配共享内存并返回用户空间可以映射的文件描述符。当用户空间不再需要文件描述符时,它应该被关闭。当不再需要共享内存时,应该使用 munmap() 取消映射以允许重用内存。

TEE_IOC_VERSION 让用户空间知道此驱动程序处理哪个 TEE 及其功能。

TEE_IOC_OPEN_SESSION 打开一个到可信应用程序的新会话。

TEE_IOC_INVOKE 调用可信应用程序中的函数。

TEE_IOC_CANCEL 可以取消正在进行的 TEE_IOC_OPEN_SESSION 或 TEE_IOC_INVOKE。

TEE_IOC_CLOSE_SESSION 关闭与可信应用程序的会话。

mmap会将一个文件和其他对象映射到内存空间中。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。munmap执行相反的操作,删除特定地址区域的对象映射。

TEE有两种客户端:普通客户端和请求者客户端,请求者客户端是TEE在Linux OS中的辅助进程,用于访问资源,比如文件系统访问等。普通客户端会打开 /dev/tee[0-9]*,请求者kehu客户端会打开 /dev/teepriv[0-9]。

/dev/目录下是Linux的外部设备文件,注意不是驱动文件,Linux会将所有设备认为是文件。

客户端和 TEE 之间的大部分通信对驱动程序来说是不透明的。驱动程序的主要工作是接收来自客户端的请求,将它们转发到 TEE 并将结果发回。在请求方的情况下,通信在另一个方向进行,TEE 向请求方发送请求,然后请求方将结果发回。

TEE是在安全环境中运行的可信操作系统,例如 ARM CPU 上的 TrustZone。TEE 驱动程序会处理与 TEE 通信所需的细节,驱动程序更重要的职责是为基于 Globalplatform TEE 客户端 API 规范的 TEE 提供通用 API,而且还管理 Linux 和 TEE 之间的共享内存。该子系统可以通过CONFIG_OPTEE在 ARM 架构的内核配置中进行配置来启用。

The secure world包含表示为 OP-TEE OS 的可信操作系统。在此操作系统之上,可以运行受信任应用程序 (TA),这些应用程序可以在隔离环境中执行某些操作,参见图 1。

image-20220117152205863.png

图 1:TEE 概述

The normal world 包括Linux 用户空间和内核空间,可以使用客户端应用程序 (CA) 和 TEE 子系统公开的 API 与这些应用程序交互。CA 可以向特定 TA 打开会话并调用 TA 实现的功能。在 TA 和 CA 之间来回传递任何参数都是使用共享内存完成的。接下来描述使用所有相关系统调用的 CA 和 TA 之间的交互。

1、CA 打开/dev/tee[0-9]以与驱动程序通信。对于使用这些 API 的传统方式,这是使用 libteec 隐式完成的。

2、CA 可以使用IOCTL TEE_IOC_SHM_ALLOC。这将分配共享内存并返回一个文件描述符,用户空间可以将其用作 mmap 的一部分。

3、下一步是使用IOCTL TEE_IOC_OPEN_SESSION和指定特定 TA 的 uuid建立会话。这个 uuid 在 TA 的编译过程中是硬编码的。

4、为了调用 TA 中的特定函数,CA 通过指定函数的标识符以及输入参数来调用该函数,这里使用的是TEE_IOC_INVOKE。

5、当 CA 完成所有请求后,可以使用TEE_IOC_CLOSE_SESSION关闭会话。

image.png

图 2:CA 和 TA 之间的会话

客户端和 TEE 之间的大部分通信对驱动程序来说是不透明的。驱动程序的主要工作是管理上下文、接收来自客户端的请求、将它们转发到 TEE 并将结果发回 。

0x02 对 TEE 驱动器的模糊测试

CVE-2021-44733 是使用 syzkaller 模糊测试发现的,下面提供了相关的描述文件。ioctl$TEE_SHM_REGISTER_FD只是 Linaro内核树的一部分,根据 syzkaller 文档正确配置后,“Setting up the environment”中提供的环境就可以用于模糊测试了。

#include   
resource fd_tee0[fd]
resource session_resource[int32]
  
openat$tee0(fd const[AT_FDCWD], dev ptr[in, string["/dev/tee0"]], flags flags[open_flags], mode flags[open_mode]) fd_tee0
ioctl$TEE_OPEN_SESSION(fd fd_tee0, cmd const[0x8010a402], arg ptr[inout, tee_ioctl_buf_data_session])
ioctl$TEE_INVOKE(fd fd_tee0, cmd const[0x8010a403], arg ptr[inout, tee_ioctl_buf_data_invoke])
ioctl$TEE_CANCEL(fd fd_tee0, cmd const[0x8008a404], arg ptr[in, tee_ioctl_buf_data_cancel])
ioctl$TEE_CLOSE_SESSION(fd fd_tee0, cmd const[0x8004a405], arg ptr[in, tee_ioctl_buf_data_close])
ioctl$TEE_VERSION(fd fd_tee0, cmd const[0x800ca400], arg ptr[out, tee_ioctl_buf_data_version])
ioctl$TEE_SHM_ALLOC(fd fd_tee0, cmd const[0xc010a401], arg ptr[inout, tee_ioctl_buf_data_shm_alloc])
ioctl$TEE_SHM_REGISTER(fd fd_tee0, cmd const[0xc018a409], arg ptr[inout, tee_ioctl_buf_data_shm_register])
ioctl$TEE_SHM_REGISTER_FD(fd fd_tee0, cmd const[0xc018a408], arg ptr[inout, tee_ioctl_buf_data_shm_register_fd])
ioctl$TEE_SUPPL_RECV(fd fd_tee0, cmd const[0x8010a406], arg ptr[inout, tee_ioctl_buf_suppl_recv])
ioctl$TEE_SUPPL_SEND(fd fd_tee0, cmd const[0x8010a407], arg ptr[inout, tee_ioctl_buf_suppl_send])
  
# COMMON
#=======================================================
  
define TEE_IOCTL_UUID_LEN   16
  
tee_ioctl_param_struct {
    attr    flags[TEE_IOCTL_PARAM_ATTR_TYPE, int64]
    a       int64
    b       int64
    c       int64
}
  
TEE_IOCTL_PARAM_ATTR_TYPE = 0, 1, 2, 3, 5, 6, 7
TEE_LOGIN = 0, 1, 2, 4, 5, 6
  
 
  
# OPEN SESSION
#=======================================================
  
tee_ioctl_buf_data_session {
    buf_ptr ptr64[inout, tee_ioctl_open_session_struct]
    buf_len len[buf_ptr, int64]
}
  
tee_ioctl_open_session_struct {
    uuid        array[int8, TEE_IOCTL_UUID_LEN] (in)
    clnt_uuid   array[int8, TEE_IOCTL_UUID_LEN] (in)
    clnt_login  flags[TEE_LOGIN, int32]         (in)
    cancel_id   int32                           (in)
    session     session_resource                (out)
    ret         int32                           (out)
    ret_origin  int32                           (out)
    num_params  len[params, int32]              (in)
    params      array[tee_ioctl_param_struct]   (in)
}
  
# INVOKE
#=======================================================
  
tee_ioctl_buf_data_invoke {
    buf_ptr ptr64[inout, tee_ioctl_invoke_struct]
    buf_len len[buf_ptr, int64]
}
  
tee_ioctl_invoke_struct {
    func        int32                           (in)
    session     session_resource                (in)
    cancel_id   int32                           (in)
    ret         int32                           (out)
    ret_origin  int32                           (out)
    num_params  len[params, int32]              (in)
    params      array[tee_ioctl_param_struct]   (in)
}
    
# CANCEL SESSION
#=======================================================
  
tee_ioctl_buf_data_cancel {
    cancel_id   int32               (in)
    session     session_resource    (in)
}
    
# CLOSE SESSION
#=======================================================
  
tee_ioctl_buf_data_close {
    session session_resource    (in)
}
    
# VERSION
#=======================================================
  
tee_ioctl_buf_data_version {
    impl_id     int32   (out)
    impl_caps   int32   (out)
    gen_caps    int32   (out)
}
    
# SHM ALLOC
#=======================================================
  
tee_ioctl_buf_data_shm_alloc {
    size        int64               (inout)
    flags       const[0, int32]     (inout)
    id          int32               (out)
}
   
# SHM REGISTER
#=======================================================
  
tee_ioctl_buf_data_shm_register {
    addr    int64               (in)
    length  int64               (inout)
    flags   const[0, int32]     (inout)
    id      int32               (out)
}
   
# SHM REGISTER FD
#=======================================================
  
tee_ioctl_buf_data_shm_register_fd {
    fd      int64               (in)
    size    int64               (out)
    flags   const[0, int32]     (in)
    id      int32               (out)
} [align[8]]
   
# SUPPLICANT RECV
#=======================================================
  
tee_ioctl_buf_suppl_recv {
    func        int32                           (in)
    num_params  len[params, int32]              (inout)
    params      array[tee_ioctl_param_struct]   (inout)
}
  
  
# SUPPLICANT SEND
#=======================================================
  
tee_ioctl_buf_suppl_send {
    ret         int32                           (out)
    num_params  len[params, int32]              (in)
    params      array[tee_ioctl_param_struct]   (in)
}

模糊测试中的崩溃是由于持有互斥对象时 task _ struct 的 use-after-free 漏洞:

==================================================================
BUG: KASAN: use-after-free in __mutex_lock.constprop.0+0x118c/0x11c4
Read of size 4 at addr 863b0714 by task optee_example_r/244
 
CPU: 0 PID: 244 Comm: optee_example_r Tainted: G      D           5.14.0 #151
Hardware name: Generic DT based system
[] (unwind_backtrace) from [] (show_stack+0x20/0x24)
[] (show_stack) from [] (dump_stack_lvl+0x5c/0x68)
[] (dump_stack_lvl) from [] (print_address_description.constprop.0+0x38/0x304)
[] (print_address_description.constprop.0) from [] (kasan_report+0x1c0/0x1dc)
[] (kasan_report) from [] (__mutex_lock.constprop.0+0x118c/0x11c4)
[] (__mutex_lock.constprop.0) from [] (mutex_lock+0x128/0x13c)
[] (mutex_lock) from [] (tee_shm_release+0x4b0/0x6cc)
[] (tee_shm_release) from [] (dma_buf_release+0x1b8/0x2f0)
[] (dma_buf_release) from [] (__dentry_kill+0x4c4/0x678)
[] (__dentry_kill) from [] (dput+0x630/0xba4)
[] (dput) from [] (__fput+0x3b4/0x900)
[] (__fput) from [] (task_work_run+0x15c/0x230)
[] (task_work_run) from [] (do_exit+0x103c/0x3770)
[] (do_exit) from [] (do_group_exit+0x134/0x3ac)
[] (do_group_exit) from [] (get_signal+0x7d8/0x2f28)
[] (get_signal) from [] (do_work_pending+0x984/0x154c)
[] (do_work_pending) from [] (slow_work_pending+0xc/0x20)
Exception stack(0x85743fb0 to 0x85743ff8)
3fa0:                                     00023108 00000080 00000000 00000000
3fc0: 66bca2d0 66bca2d0 66bca2d0 000000f0 66bca2d0 66bca340 00000000 6ec00b0c
3fe0: 66bc9cc8 66bc9cb8 00011655 66c80c20 000e0130 00023108
 
Allocated by task 242:
 set_alloc_info+0x48/0x50
 __kasan_slab_alloc+0x48/0x58
 kmem_cache_alloc+0x14c/0x314
 copy_process+0x2014/0x7b18
 kernel_clone+0x244/0xfc8
 sys_clone+0xc8/0xec
 ret_fast_syscall+0x0/0x58
 0x6ec00a10
 
Freed by task 67:
 kasan_set_track+0x28/0x30
 kasan_set_free_info+0x20/0x34
 __kasan_slab_free+0xdc/0x108
 kmem_cache_free+0x80/0x394
 __put_task_struct+0x2b4/0x35c
 delayed_put_task_struct+0x104/0x384
 rcu_core+0x91c/0x2a68
 __do_softirq+0x2fc/0xfb8
 
Last potentially related work creation:
 kasan_record_aux_stack+0xb8/0xc0
 call_rcu+0x9c/0xfd0
 put_task_struct_rcu_user+0x9c/0xbc
 finish_task_switch+0x534/0xa10
 __schedule+0x934/0x1adc
 schedule_idle+0x9c/0x120
 do_idle+0x2ec/0x434
 cpu_startup_entry+0x18/0x1c
 start_kernel+0x3ec/0x430
 
The buggy address belongs to the object at 863b0700
 which belongs to the cache task_struct of size 1664
The buggy address is located 20 bytes inside of
 1664-byte region [863b0700, 863b0d80)
The buggy address belongs to the page:
page:f09c9565 refcount:1 mapcount:0 mapping:00000000 index:0x0 pfn:0x463b0
head:f09c9565 order:3 compound_mapcount:0 compound_pincount:0
flags: 0x10200(slab|head|zone=0)
raw: 00010200 00000000 00000122 82802e00 00000000 80120012 ffffffff 00000001
page dumped because: kasan: bad access detected
 
Memory state around the buggy address:
 863b0600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 863b0680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>863b0700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                 ^
 863b0780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 863b0800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================

这是通过关闭TEE_IOC_SHM_ALLOC中的所有文件描述符而触发的,在我们的例子中,一个不同的线程会打开一个会话,指向一个不存在的 TA。通过 Syzkaller 重现此问题,并通过对TEE_ioc_open_session 的调用,我们发现属于 kmalloc-64缓存的对象中存在另一个 UAF:

==================================================================
BUG: KASAN: use-after-free in tee_shm_put+0x8c/0x98
Read of size 4 at addr 86467020 by task optee_example_h/216
 
CPU: 0 PID: 216 Comm: optee_example_h Not tainted 5.14.0 #21
Hardware name: Generic DT based system
[] (unwind_backtrace) from [] (show_stack+0x10/0x14)
[] (show_stack) from [] (dump_stack_lvl+0x40/0x4c)
[] (dump_stack_lvl) from [] (print_address_description.constprop.0+0x5c/0x2d8)
[] (print_address_description.constprop.0) from [] (kasan_report+0x1b4/0x1d0)
[] (kasan_report) from [] (tee_shm_put+0x8c/0x98)
[] (tee_shm_put) from [] (tee_ioctl+0x1578/0x2e44)
[] (tee_ioctl) from [] (sys_ioctl+0x918/0x1e70)
[] (sys_ioctl) from [] (ret_fast_syscall+0x0/0x58)
Exception stack(0x86417fa8 to 0x86417ff0)
7fa0:                   00000080 00000000 00000003 8010a402 200001c0 00000003
7fc0: 00000080 00000000 00423018 00000036 66c562d0 66c55e10 66c562d0 6ebebafc
7fe0: 66c55cb0 66c55ca0 004114bd 66cebd72
 
Allocated by task 216:
 tee_shm_alloc+0x15c/0x7e8
 tee_ioctl+0x8d0/0x2e44
 sys_ioctl+0x918/0x1e70
 ret_fast_syscall+0x0/0x58
 0x66c55ca0
 
Freed by task 215:
 kasan_set_free_info+0x20/0x34
 __kasan_slab_free+0xdc/0x108
 kfree+0x98/0x294
 tee_shm_release+0x1dc/0x610
 dma_buf_release+0x180/0x2a0
 __dentry_kill+0x488/0x6ac
 __fput+0x2f0/0x7b4
 task_work_run+0x178/0x230
 do_work_pending+0xaf8/0x10a8
 slow_work_pending+0xc/0x20
 0x66d5bd16
 
The buggy address belongs to the object at 86467000
 which belongs to the cache kmalloc-64 of size 64
The buggy address is located 32 bytes inside of
 64-byte region [86467000, 86467040)
The buggy address belongs to the page:
page:(ptrval) refcount:1 mapcount:0 mapping:00000000 index:0x0 pfn:0x46467
flags: 0x200(slab|zone=0)
raw: 00000200 00000000 00000122 82401200 00000000 00200020 ffffffff 00000001
page dumped because: kasan: bad access detected
 
Memory state around the buggy address:
 86466f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 86466f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>86467000: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
                       ^
 86467080: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
 86467100: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
==================================================================

该漏洞是通过对 TEE 驱动程序进行模糊测试而发现的,无需与系统上运行的现有 TA 建立任何会话。这可以通过 syzkaller 中的伪系统调用进一步扩展,以便建立和启动与某个 TA 的会话。

0x03 根本原因分析

漏洞的根本原因是tee_shm:dmabuf对象寿命跟踪的设计问题。驱动程序的设计目的是让用户空间在调用tee_ioctl_shm_alloc()后保留唯一的引用计数。

假设如果能在驱动程序的 IDR 对象中仍然找到该对象,则对 dmabuf 的引用仍然有效并且其引用计数可以递增。事实证明,这只是部分正确的。dmabuf 内存仍由 dmabuf 驱动程序拥有,但它可能正在被销毁,并且无法通过再次使引用计数非零来停止。

触发漏洞的场景是多线程应用程序,其中一个线程关闭 dmabuf 文件描述符,同时另一个线程调用 IOCTL 命令TEE_IOC_OPEN_SESSION或TEE_IOC_INVOKE引用该共享内存。

当用户空间关闭 fd 时,跟踪 dmabuf 的销毁将在内核中运行以下代码:

  1. fput()

  2. fput_many() >> 文件引用计数为零,窗口开启。

  3. [task_work gets scheduled]

  4. __fput

  5. dput

  6. dma_buf_release

  7. tee_shm_release

    1. mutex_lock(teedev->mutex)

    2. idr_remove(teedev->idr, shm->id)>> 无法再从用户空间引用 shm 对象,窗口关闭。

    3. mutex_unlock()

这意味着 IDR Table及其互斥锁不能保证dmabuf和相应的tee_shm仍然有效,通过调用 tee_shm_get_from_id ()来竞争 fput ()的进程可以获得对即将停止的 shm 的引用。

/**
 * tee_shm_get_from_id() - Find shared memory object and increase reference
 * count
 * @ctx:    Context owning the shared memory
 * @id:     Id of shared memory object
 * @returns a pointer to 'struct tee_shm' on success or an ERR_PTR on failure
 */
struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id)
{
    struct tee_device *teedev;
    struct tee_shm *shm;
 
    if (!ctx)
        return ERR_PTR(-EINVAL);
 
    teedev = ctx->teedev;
    mutex_lock(&teedev->mutex);
    shm = idr_find(&teedev->idr, id);
    if (!shm || shm->ctx != ctx)
        shm = ERR_PTR(-EINVAL);
    else if (shm->flags & TEE_SHM_DMA_BUF)
        get_dma_buf(shm->dmabuf);
    mutex_unlock(&teedev->mutex);
    return shm;
}

0x04 利用 UAF 漏洞

为了利用此漏洞,必须在对象被释放之后和触发 UAF 之前进行重新分配。

在调用tee_shm_get_from_id()之后,函数tee_shm_put()会被调用,该函数对dma_buf_put()的输入参数tee_shm:dmabuf对象进行解析。

/**
 * tee_shm_put() - Decrease reference count on a shared memory handle
 * @shm:    Shared memory handle
 */
void tee_shm_put(struct tee_shm *shm)
{
    if (shm->flags & TEE_SHM_DMA_BUF)
        dma_buf_put(shm->dmabuf);
}
EXPORT_SYMBOL_GPL(tee_shm_put);

该tee_shm对象可以在 UAF 之前重新分配,因为它属于 kmalloc-64 缓存,必须重新分配:

伪造 tee_shm, tee_shm:dmabuf,dma_buf:file对象
设置 file->f_count = 1
制作一个file:file_operations将fasync函数指针设置为任意地址的对象

然后在__fput()调用dma_buf_put()whenfile->f_count为零后调用此函数。

PAN (Privileged Access Never) 缓解了这种情况,因为必须在用户空间内存中引用伪造的对象才能在file:f_ops结构中设置任意函数指针。因此CONFIG_CPU_SW_DOMAIN_PAN必须禁用它才能在提供的环境中工作。

此外,为了成功地重新分配空闲的shm对象,IOCTL调用TEE_IOC_OPEN_会话或TEE_IOC_INVOKE必须由执行文件描述符关闭和堆喷线程的线程抢占,该线程填充kmalloc-64缓存。为了实现这一点,内核必须配置CONFIG_PREEMPT。在这个PoC中,Nicolas Fabretti的文章中的堆喷是基于阻塞sendmsg()使用的。

总之,free和UAF必须发生在同一个系统调用中。除此之外,释放也很难触发,因为它需要在系统调用中进行竞争。释放后,它与实际UAF之间会有一个时间窗口,在这个时间窗口中,必须执行堆喷来重新分配释放的对象。下图显示了漏洞代码中涉及的线程及其角色。

image.png

图 3:漏洞利用代码中的线程

三种类型的线程连续运行。为了抢占系统调用线程,它以尽可能低的优先级SCHED_IDLE运行,而其他线程的优先级设置为SCHED_OTHER。因为我们使用的是blocking sendmsg(),所以每次喷洒都必须在自己的线程中运行,并且必须在触发UAF的同一个CPU内核上运行,因为每个内核都保留自己的kmalloc缓存。在步骤1b)中,还有许多释放线程将文件描述符从共享内存分配中关闭。有关UAF漏洞触发和函数指针覆盖的完整利用代码,请参见[10]。

0x05 设置OPTEE 环境

要使用存在漏洞的内核和 OPTEE 重现环境,可以从以下存储库克隆并使用以下方法构建:

$ mkdir optee-qemu && cd optee-qemu
$ repo init -u https://github.com/pjlantz/optee-qemu.git
$ repo sync
$ cd build
$ make toolchains -j2
$ make run

成功构建后,会出现三个控制台,一个用于 QEMU - 在 QEMU 控制台中按“c”以启动。第二个控制台显示secure world的输出,最后一个控制台将引导至 Linux以 root 身份登录。

运行Exploit代码,直到FaseNc函数指针设置为0x22000000。

until optee_exploit | grep "0x22000000" /var/log/messages; do sleep 0.01; done

由于PXN在PC=0x22000000时会阻止执行,因此操作将停止。利用策略可能会因内核版本而异,也可能会执行内核ROP并进行堆栈旋转,或者使vDSO区域可写并将paylaod写入。在未来的工作中,研究使用ret2dir和一些physmap喷雾是否可以绕过PAN也可能是有趣的。通过在linux/中设置CONFIG_CPU_SW_DOMAIN_PAN=y,可以在内核中启用PAN。配置。在真正的硬件上,它默认在ARMv8上启用。1和AArch64,对于ARMv7和AArch32,可以使用此设置对PAN进行软件仿真[8]。

0x06 参考资料

[1] CVE-2021-44733 - https://nvd.nist.gov/vuln/detail/CVE-2021-44733

[2] TEE subsystem - https://www.kernel.org/doc/html/latest/staging/tee.html

[3] Globalplatform TEE API - https://globalplatform.org/specs-library/?filter-committee=tee

[4] OP-TEE OS - https://github.com/OP-TEE/optee_os

[5] BKK16-110: A Gentle Introduction to Trusted Execution and OP-TEE - https://connect.linaro.org/resources/bkk16/bkk16-110/

[6] Syzkaller - https://github.com/google/syzkaller

[7] Lexfo's security blog, by Nicolas Fabretti: CVE-2017-11176: A step-by-step Linux Kernel exploitation - https://blog.lexfo.fr/cve-2017-11176-linux-kernel-exploitation-part3.html

[8] Linux Kernel Security Subsystem: Exploit Methods/Userspace data usage - http://kernsec.org/wiki/index.php/Exploit_Methods/Userspace_data_usage

[9] [PATCH v2] tee: handle lookup of shm with reference count 0 - https://lore.kernel.org/lkml/20211215092501.1861229-1-jens.wiklander@linaro.org/T/

[10] Proof of concept exploit - https://github.com/pjlantz/optee_examples/tree/master/exploit/host

如若转载,请注明原文地址
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务