【技术分享】两个CVE案例分析:如何利用Android中的可信区域

admin 2023-12-07 17:18:14 AnQuanKeInfo 来源:ZONE.CI 全球网 0 阅读模式

http://p5.qhimg.com/t019cf9db2a0c730917.png

翻译:overXsky

预估稿费:200RMB(不服你也来投稿啊!)

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿

前言

本文将从实际出发,讲述如何一步步地利用Android中的可信区域(TrustZone)。这里我使用的是华为海思的可信执行环境(Trusted Execution Environment,TEE)。首先我找到了一个可以获得内核权限的漏洞,然后我又发现了一个可以在TEE中执行任意代码的漏洞。以上试验结果证明了在华为海思可信执行环境中任何本地应用都可以执行shellcode这一概念的可行性。

 

背景

“ARM®TrustZone®技术是一种针对各种客户端和服务器计算平台(包括手机,平板电脑,可穿戴设备和企业系统)的安全性的全系统方法。”使用可信区域技术开发的设备能够支持完整的可信执行环境。可信执行环境运行在一个被称作“安全模式”的特殊CPU模式上,这样安全模式使用的内存和安全函数就能够对正常使用环境隐藏自身。通过这种方式,Android的开发商可以提供种类丰富的安全功能,比如指纹识别、数字版权管理(DRM)、内核保护、安全启动等等。你可以在可信区域的官方网站或者探索genode.org来获取更多的信息。

华为海思的可信执行环境符合最近的全球可信执行环境平台规范,但是它的实现却完全没有文档依据可循。通过逆向它的固件,一些日志文件让我大致理解了它的架构:

http://p7.qhimg.com/t013f1c7f9b00e48843.png

下面就上图做简要说明:

TZDriver “ev/tc_ns_client”是一个内核级驱动,它给用户空间的客户端与可信执行环境之间的通信提供了接口,就如同高通安全可执行环境(QSEE)中的“/dev/qseecom”一样。两者唯一的区别在于,在使用华为海思芯片的mate7上每个本地应用都能够访问TZDriver,而高通的qseecom只能被一部分系统进程访问到。

TA是Trusted Application即可信任应用程序的缩写,它是elf格式的文件。每个可信应用程序都提供了与安全相关的服务,比如安全存储(TA_SecStorage)、安全启动、密钥存储(原文为keystone,应为key store之误,译者注)、指纹识别(TA_FingerPrints)等等。

TEEGlobalTask 是可信执行环境的用户模式下第一个可信任应用程序。它能够加载elf模块,能够将外部调用调度至其他可信任应用程序的子服务。

RTOSck是可信执行环境的核心,它是华为自主研发的实时操作系统,跟uC/OS-II有些类似。RTOSck还包含了指纹识别驱动,它只能通过TA_FingerPrints来访问,以此从设备传感器上读取指纹图像。

 

CVE-2015-4421:存在于/dev/tc_ns_client中的漏洞

安全监视器调用(SMC)主要用于进入安全监视器模式并执行安全监视器内核服务调用。 该指令只能在特权模式下执行。 所以如果用户进程试图向安全区域发送畸形的SMC来利用可信执行环境,那么它首先必须获得内核级别的权限。

“/dev/ tc_ns_client”是一个内核驱动程序,它能够为用户空间的客户端和其他内核模块提供ioctl接口。 客户端使用其“TCAPI”与安全区域进行通信。 驱动程序的文件权限是“rw-rw-rw-”,其SE上下文为“u:object_r:device:s0“。用户模式下的任何客户端都可以访问此驱动程序。

客户端使用TC_NS_ClientParam 结构体向驱动程序发送缓冲区指针,然后驱动程序向可信执行环境请求安全监视器调用,并将返回的值复制给TC_NS_ClientParam中的指针。

以下是TC_NS_ClientParam结构体的代码:

typedef union {
struct {
unsigned int buffer; //ptr of buffer
unsigned int offset; //size of buffer
unsigned int size_addr;
} memref;
struct {
unsigned int a_addr; //ptr of a 4-bytes   buffer
unsigned int b_addr; //ptr of a 4-bytes   buffer
} value;
} TC_NS_ClientParam;

然而,驱动程序在边界检查中犯了一个错误。 伪代码如下:

static int TC_NS_SMC_Call(TC_NS_ClientContext
*client_context,TC_NS_DEV_File   *dev_file, bool is_global){
....
// 建立 TC_NS_SMC_CMD 结构体
....
// 执行 SMC 指令
TC_NS_SMC(smc_cmd_phys);
// 复制 smc_cmd.operation_phys的结果给调用者
buffer(client_param.value)
if(client_operation->params[0].value.a>   0xbfffffff){
//driver think caller is from kernel space
*(u32 *)client_param->value.a_addr =   operation-
>params[i].value.a;
}
else{
//driver think caller is from user space
copy_to_user(....);
}
if(client_operation->params[0].value.b   > 0xbfffffff){
*(u32 *)client_param->value.b_addr =   operation-
>params[i].value.b;
}
else{
copy_to_user(....);
}
....
}

如果我们在用户模式发送内核指针会怎么样? 驱动程序将直接复制结果而不使用copy_to_user。所以我们就有机会给内核空间写入一个给定的值。如果可信执行环境返回的值低于0xc0000000,我们就可以通过“ret2user”获得root权限。

具体步骤如下图所示:

http://p3.qhimg.com/t0154bbeb4bd335f842.png

我选择可信执行环境系统的内部时间作为给定的返回值。可信执行环境中的全局服务提供了时间查询接口:cmd_id =“GLOBAL_CMD_ID_TEE_TIME”。

以下是“main_task”中的伪代码。

int get_sys_time()
{
int result; // r0@1
tag_TC_NS_Operation *v1; // r3@1
unsigned int v2; // [sp+0h] [bp-10h]@1
int v3; // [sp+4h] [bp-Ch]@1
get_time((int)&v2);
result = 0;
v1 = dword_5E2E0->operation_phys;
v1->params[0].value.a = v2; //秒
v1->params[0].value.b = 1000 * v3; //毫秒,指定值
return result;
}

可信执行环境中的毫秒将被写入ptmx-> fops指针,并且可以触发“ret2user”的漏洞利用。


CVE-2015-4422:可信执行环境系统中的漏洞

执行SMC指令时,指向TC_NS_SMC_CMD结构体的物理地址将被发送到可信执行环境。利用这一点特性,我通过使用一个变异格式的TC_NS_SMC_CMD结构,就可以将一个字节数据写入几乎任何物理地址。

typedef struct   tag_TC_NS_SMC_CMD{
unsigned int uuid_phys; //uuid的物理地址
unsigned int cmd_id;
unsigned int dev_file_id;
unsigned int context_id;
unsigned int agent_id;
unsigned int operation_phys;//物理地址或内核缓冲区
unsigned int login_method;
unsigned int login_data;
unsigned int err_origin;
bool started;
} TC_NS_SMC_CMD;

由于在“TEEGlobalTask”中没有边界检查,我们可以修改除了TEE内核占用以外的任意物理内存。例如,让我们回顾一下“TEEGlobalTask” 中get_sys_time()的伪代码:

int get_sys_time()
{
int result; // r0@1
tag_TC_NS_Operation *v1; // r3@1
unsigned int v2; // [sp+0h] [bp-10h]@1
int v3; // [sp+4h] [bp-Ch]@1
get_time((int)&v2);
result = 0;
//operation_phys 是安全区域里的一个物理地址
v1 = dword_5E2E0->operation_phys;
//operation_phys+4 和 operation_phys+8 将被修改
*(int*)(operation_phys + 4) = v2;
*(int*)(operation_phys + 8)= 1000 * v3;
return result;
}

“Operation_phys + 4”和“operation_phys + 8”将被可信执行环境的内部时间覆盖。如果可信执行环境的当前内部时间为“0x0000AABB,0xCCDDEEFF”,则内存中覆盖的值在小端序系统中对应为“BB AA 00 00,FF EE DD CC”。 “BB”是秒数的最后一个字节,并且在0x00到0xFF之间循环。

有了这个漏洞,我们就可以在特定的时间(适当的秒数)在任何物理地址写入一个字节的数据。

 

在可信执行环境系统中执行代码

基于上述信息,一个本地应用也可以访问本来只能由可信执行环境访问的物理内存。 在本节中我们来谈谈如何在TEEGlobalTask上下文环境中实现代码执行。

通过对华为海思芯片的可信执行环境的固件逆向和一些黑盒测试,我得到一些好消息和一些坏消息。好消息是,固件中几乎没有任何漏洞防护功能——没有ASLR,没有DEP,没有“r-x”.text段,没有堆栈溢出保护…几乎就只有一个传统的RTOS在里面。 坏消息是,我们不知道在哪里修补才能改变原来的代码流并跳转到我们的shellcode。 换句话说,我们需要知道“TEEGlobalTask”的基地址。

另一个由“TEEGlobalTask”提供的接口有一个有趣的函数,名为 “ALLOC_EXCEPTION_MEM”。它允许普通的区域提供物理地址到“RTOSck”——可信执行环境的内核。 当可信执行环境中的任务崩溃时,RTOSck可能会向这个给定的物理地址写入一些崩溃信息。 当然,前提是这个物理地址可以被普通的区域访问。

所以我向SMC请求了一个无效的物理地址从而使其崩溃。 下面就是一个RTOSck崩溃信息的例子:

http://p0.qhimg.com/t019a838f849e4b5ace.png

这个信息显示$ PC崩溃地址是0x2E103050,因此我怀疑 “TEEGlobalTask”的基地址是0x2E100000。现在我可以给“TEEGlobalTask”打一些补丁使它跳转到我事先在普通区域布置下的shellcode,然后从外部触发补丁代码执行,搞定。

 

从传感器获取指纹图像

前面提到,只有“TA_Fingerprint”可以通过系统调用“__FPC_readImage”从传感器读取指纹图像。

不幸的是,代码执行漏洞是在“TEE_GlobalTask”的上下文环境下,也就是说,指纹读取请求将由于RTOSck进行的安全检查而被拒绝。

所以我需要找到一个RTOSck的漏洞来绕过安全检查。

signed int __fastcall   sys_call_overwrite(int a1, int a2)
{
signed int v2; // r3@2
int v4; // [sp+0h] [bp-14h]@1
int v5; // [sp+4h] [bp-10h]@1
v5 = a1;
v4 = a2;
if ( *(_DWORD *)a1 == 0x13579BDF )
{
// 写入 (*(int*)(arg1 + 0x18C) + 7) >> 3 给 arg2
*(_WORD *)v4 = (unsigned int)(*(_DWORD *)(v5   + 0x18C) + 7)>> 3;
v2 = 0;
}
return v2;
}
}

这是一个没有任何输入检查的存在于RTOSck中的系统调用,我可以通过覆盖可信执行环境内核占用的内存来修改安全检查代码。

现在代码执行漏洞已经能够通过调用“__FPC_readImage”来获取指纹图像。

 

总结

通过这些漏洞利用,一款本地应用程序就能够获取指纹图像或其他加密数据,能够禁用调制解调器映像和可信任应用程序的签名验证,加载任何模块到可信执行环境并修改eFuse数据。

尽管TrustZone设计的初衷是为了解决安全问题,通过一些手段的实施我们仍然可以利用其中的安全隐患来达到想要的目的。


后话

有网友放出了exploit,附链接:

https://www.reddit.com/r/hacking/comments/3fy821/huawei_mate_7_trustzone_exploitcve20154421/

另外,国外网友的博客中表明,搭载Android 5.0和高通骁龙芯片的设备由于也使用了可信区域技术,所以也会受到该漏洞影响:

http://www.jorgejamil.com/single-post/2016/05/08/FDE-Fail-on-Android-50

截止今年9月,全球Android设备中,Android 5.0市场占有率仍高达13.1%,在所有Android系统版本中排名第四。

https://p2.ssl.qhimg.com/t016bd47a23e41eaa1c.png

 


weinxin
版权声明
本站原创文章转载请注明文章出处及链接,谢谢合作!
评论:0   参与:  0