华为TrustZone CHINADRM_COMMON_TA漏洞
此通报包含有关以下漏洞的信息:
CVE-2021-40052 漏洞-2021-40052 CencDecrypt 中的目标大小错误memcpy_s
HWPSIRT-2021-27669 访问全局变量时缺少锁定
HWPSIRT-2021-11381 初始化前打开会话
HWPSIRT-2021-11309 会话 ID 是指针
我们发现 3 个影响华为CHINADRM_COMMON_TA的漏洞,这些漏洞可导致以 S-EL0 身份执行的可信应用程序遭到入侵:
访问全局变量时缺乏锁定,导致双重释放和释放后使用问题
在初始化之前可以打开会话,从而导致空指针取消引用
会话 ID 是指针,导致堆指针信息泄露
我们还发现了一个影响华为CHINADRM_COMMON_TA可信应用程序的其他错误:
中的目标大小错误,导致潜在的 ION 缓冲区溢出memcpy_s
CencDecrypt
正如加载 trustlet 时在日志中显示的那样,它是多会话。因此,在访问或修改全局变量时必须格外小心。不幸的是,这个 trustlet 没有做任何形式的锁定,所以出现了许多竞争条件问题。
[GTask] TA name: CHINADRM_COMMON_TA, UUID: 95b9ad1e, ELF: 361867, stack: 300000, heap: 1179648, multi session: True, keepalive: False, singleInstance: True
如下面的代码片段所示,访问会话列表时不会进行锁定。
int g_sessions_count; /* in the BSS */
list_head g_sessions_list; /* in the BSS */int CDRMC_FindSession(container_t *container, session_t **session_p) {
// ...
if (g_sessions_count && container) {
if (list_contains(&container->list, &g_sessions_list)) {
*session_p = container->session;
return 0;
} else { /* ... */ }
} else {
// ...
return -1;
}
// ...
}
因此,可能会出现两个内核位于同一指令窗口中的争用条件,从而导致会话被释放两次。CDRMC_CloseSession
注意:也可以触发释放后使用,让一个内核使用会话(读取或写入会话),而另一个内核释放会话。
int CDRMC_CloseSession(container_t *container) {
// ...
if (CDRMC_FindSession(container, &session)) { /* ... */ }
/* --- start of the race window --- */
if (container->session) {
LicenseExtractInfoCleanup(&container->session->inner);
CDRMR_SecureMemory_Free(container->session);
container->session = NULL;
}
/* --- end of the race window --- */
list_del(&container->list);
CDRMR_SecureMemory_Free(container);
--g_sessions_count;
// ...
}
触发此双重释放的概念证明会导致以下崩溃:
[HM] [ERROR][228]unmap errno = 22
[HM] ERROR: free: __munmap return code= -1
[HM] ERROR: free: double free
[HM] Dump SPI notification entries:
[HM] ----------
[HM] Stats: SHADOW.tx=0 SHADOW.rx=0 WAKEUP.tx=467 WAKEUP.rx=467
[HM] Stats: SET_AFFINITY.tx=0 SET_AFFINITY.rx=0
[HM] Dump current threads:
[HM] ---------
[HM] CPU0: name=/teesmcmgr.elf
[HM] ctx_map[ta=0/0 ca=0/0 target=0/0 exit=0/0]
...
这种缺乏锁定是所有全局变量所共有的。例如,也可以通过 、、 各种证书缓存等而不是会话列表来利用它。g_cipherHandle
g_cencCipherHandle
全局会话列表在函数(命令 ID #1)中初始化。如果未显式调用此命令,则列表将处于未初始化状态。CDRMC_Initialize
int g_sessions_count; /* in the BSS */
list_head g_sessions_list; /* in the BSS */int CDRMC_Initialize() {
// ...
INIT_LIST_HEAD(&g_sessions_list);
g_sessions_count = 0;
// ...
}
顾名思义,该函数可用于打开会话。它首先调用以确保存储在中的值还不是有效的会话。如果找不到会话或列表为空(即 ),此函数将返回 -1。由于错误路径仅在返回 0 时才被采用,因此即使列表未初始化,也会继续执行。因此,新分配的会话容器的指针将为 NULL 并递增。这在以后可能会导致 null 指针取消引用。CDRMC_OpenSession
CDRMC_FindSession
container_p
g_sessions_count == 0
CDRMC_FindSession
CDRMC_OpenSession
next
g_sessions_count
int CDRMC_OpenSession(container_t **container_p) {
// ...
if (!CDRMC_FindSession(*container_p, &session)) {
/* ...error... */
}
session = CDRMR_SecureMemory_Malloc(0x2CA8);
container = CDRMR_SecureMemory_Malloc(0xC);
memset_s(session, 0x2CA8, 0, 0x2CA8);
memset_s(container, 0xC, 0, 0xC);
// ...
session->container = container;
container->session = session;
list_add(&container->list, &g_sessions_list);
++g_sessions_count;
*container_p = container;
// ...
}
例如,可以使用函数中的调用(命令 ID #0x29)触发 null 指针取消引用。CDRMC_FindSession
CDRMS_SetPolicy
int CDRMS_SetPolicy(uint32_t paramTypes, TEE_Param params[4]) {
// ...
container_t *container = params[3].memref.buffer;
CDRMC_FindSession(container, &session);
// ...
}
触发此空指针取消引用的概念证明会导致以下崩溃:
[HM] [ERROR][2171]vmem_as_ondemand_prepare failed
[HM] [ERROR][2496]process 1e00000028 (tid: 40) data abort:
[HM] [ERROR][2498]Bad memory access on address: 0x0, fault_code: 0x92000006
[HM]
[HM] Dump task states for tcb
[HM] ----------
[HM] name=[CHINADRM_COMMON] tid=40 is-idle=0 is-curr=0
[HM] state=BLOCKED@MEMFAULT sched.pol=0 prio=46 queued=1
[HM] aff[0]=ff
[HM] flags=1000 smc-switch=0 ca=7849 prefer-ca=7849
[HM] Registers dump:
[HM] ----------
[HM] 32 bits userspace stack dump:
[HM] ----------
[HM] <CDRMC_FindSession+0x3c/0xdc>
[HM] <CDRMS_SetPolicy>+0xd0/0x1fc
[HM] <CDRMS_SetPolicy>+0xd0/0x1fc
[HM] <TA_InvokeCommandEntryPoint>+0x31c/0x1358
[HM] <tee_task_entry>+0x398/0xcd4
[HM] Dump task states END
CA 用来引用会话的会话 ID 是指向结构的堆分配实例的指针。此结构在 中分配,指针在第一个值的第一个值中返回给 CA。CDRMC_OpenSession
TEE_Param
TEE_Result TA_InvokeCommandEntryPoint(
void *sessionContext,
uint32_t commandID,
uint32_t paramTypes,
TEE_Param params[4])
{
switch (commandID) {
case 0x20u:
// ...checking of the paramTypes...
container_t *container = NULL;
retval = CDRMC_OpenSession(&container);
params->value.a = container;
params->value.b = retval;
break;
// ...
}
}
在运行第一个概念验证代码时,我们确实可以观察到返回给 CA 的指针:
Session = 1014db0 (retval = 0)
此信息泄漏可能会派上用场,例如在利用会话列表中的 UAF 时。
memcpy_s
CencDecrypt
¶该函数包含多个调用。其中一些具有不正确的目标大小参数。例如,在上面的代码片段中显示的不正确情况下,目标大小应考虑到值将被复制到 。CencDecrypt
memcpy_s
*decrypt->outbuf_len_p - offset
offset
decrypt->outbuf
int CencDecrypt(asym_decrypt_t *decrypt, int algorithm) {
// CORRECT memcpy_s arguments
if (memcpy_s(
&decrypt->outbuf[offset],
*decrypt->outbuf_len_p - offset,
&decrypt->inbuf[offset],
params_->subSamples[idx].sample_dword_0)) {
tee_print(0, "%s %d:copy clear Header data failed\n ", "[error]", 0x50B);
// ...
}
// ...
// INCORRECT memcpy_s arguments
if (memcpy_s(
&decrypt->outbuf[offset],
*decrypt->outbuf_len_p, // <-- the destination size is incorrect
&decrypt->inbuf[offset],
drmInfo_dword_8_times_0x10)) {
tee_print(0, "%s %d:copy payload pattern clear data failed\n ", "[error]", 0x40A);
// ...
}
// ...
}
我们没有尝试触发此错误,但它可能导致映射的 ION 缓冲区中的缓冲区溢出。
我们验证了这些漏洞是否影响了以下设备:
麒麟990:P40 专业版 (ELS)
请注意,其他型号可能已受到影响。
名字 | 严厉 | CVE漏洞 | 补丁 |
---|---|---|---|
访问全局变量时缺少锁定 | 低 | 不适用 | 固定 |
初始化前打开会话 | 低 | 不适用 | 固定 |
会话 ID 是指针 | 低 | 不适用 | 固定 |
目标大小错误memcpy_s CencDecrypt | 高 | CVE-2021-40052 漏洞-2021-40052 | 2022 年 8 月 |
2021年12月09日 - 向华为PSIRT发送漏洞报告。
2022年1月12日 - 华为PSIRT确认该漏洞报告。
2022年8月1日 - 华为PSIRT表示,此问题已在2022年8月更新中修复。
从 2022 年 11 月 30 日至 2023 年 7 月 19 日 - 我们定期交换有关公告发布的信息。
二进制漏洞(更新中)
其它课程
windows网络安全防火墙与虚拟网卡(更新完成)
windows文件过滤(更新完成)
USB过滤(更新完成)
游戏安全(更新中)
ios逆向
windbg
恶意软件开发(更新中)
还有很多免费教程(限学员)
更多详细内容添加作者微信