Linux 内核 TEE 子系统中UAF漏洞的模糊测试和利用
2022-2-24 16:50:0 Author: www.4hou.com(查看原文) 阅读量:52 收藏

导语:最近在 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/[email protected]/T/

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

如若转载,请注明原文地址


文章来源: https://www.4hou.com/posts/DWLK
如有侵权请联系:admin#unsafe.sh