二进制漏洞分析-11.华为TrustZone TEE_SERVICE_MULTIDRM漏洞(上)
2023-11-26 09:33:27 Author: 安全狗的自我修养(查看原文) 阅读量:5 收藏

二进制漏洞分析-5.华为安全监控漏洞(SMC MNTN OOB 访问)

二进制漏洞分析-10.华为TrustZone TEE_SERVICE_VOICE_REC漏洞

此通报包含有关以下漏洞的信息:

  • CVE-2021-46881 漏洞 MDrm_TA_CMD_OEMCrypto_LoadKeys中的堆缓冲区溢出

  • CVE-2021-40034 漏洞 MDrm_TA_CMD_OEMCrypto_LoadEntitledContentKeys中的堆缓冲区溢出

  • CVE-2021-46882 漏洞-2021-46882 MDrm_TA_CMD_OEMCrypto_RefreshKeys中的堆缓冲区溢出

  • CVE-2021-46883 漏洞CVE-2021-46883 MDrm_TA_OEMCryptoUsageTable_LoadUsageTableHeader中的堆缓冲区溢出

  • CVE-2021-46884 漏洞 MDrm_TA_CMD_OEMCrypto_CopyBuffer中的 OOB 写入访问权限

  • CVE-2021-46885 漏洞CVE-2021-46885 MDrm_TA_CMD_Provision_GetRequest中的 OOB 读取访问权限

  • CVE-2021-46886 漏洞 MDrm_TA_CMD_OEMCrypto_RewrapDeviceRSAKey30中的 OOB 读取访问权限

  • CVE-2021-46814 漏洞 MDrm_TA_CMD_OEMCrypto_DecryptCENC中的 OOB 读取访问权限

华为TEE_SERVICE_MULTIDRM TA符合GlobalPlatform TEE Internal Core API。因此,它从位于正常环境中的客户端应用程序接收命令。这些命令由函数处理。TA_InvokeCommandEntryPoint

堆缓冲区溢出MDrm_TA_CMD_OEMCrypto_LoadEntitledContentKeys

第一个堆缓冲区溢出位于以下函数中:MDrm_TA_CMD_OEMCrypto_LoadEntitledContentKeys

int MDrm_TA_CMD_OEMCrypto_LoadEntitledContentKeys(int paramTypes, TEE_Param params[4]) {
// [...]
cur_ptr = params[0].memref.buffer;
size_left = params[0].memref.size;
uint32_t *alloc;
// [...]

ret = MDrm_Utils_ReadU32(cur_ptr, size_left, &user1);
if (ret) goto EXIT;
cur_ptr += 4; size_left -= 4;

ret = MDrm_Utils_ReadU32(cur_ptr, size_left, &user2);
if (ret) goto EXIT;
cur_ptr += 4; size_left -= 4;

ret = MDrm_Memory_Calloc(8 * sizeof(uint32_t) * user2, &alloc);
if (ret) goto EXIT;

for (int i = 0; i != user2; ++i) {
for (int j = 0; j != 8; ++j) {
ret = MDrm_Utils_ReadU32(cur_ptr, size_left, &alloc[i*8+j]);
if (ret) goto EXIT;
cur_ptr += 4; size_left -= 4;
}
}

ret = MDrm_TA_CryptoKeyLadder_LoadEntitledContentKeys(
user1, &params[1], user2, alloc);

EXIT:
MDrm_free(alloc);
return ret;
}

调用 的第一个参数上存在整数溢出。是来自 中的缓冲区的用户控制值。例如,通过给出值,分配的大小将为 。MDrm_Memory_Callocuser2params[0]user20x800000010x80000001 * 0x20 = 0x20

user2然后用作循环计数器。循环的每次迭代都会从缓冲区读取 8 个整数值,并将其读取到堆分配的缓冲区中。由于分配的缓冲区小于预期,这允许攻击者使用受控数据溢出缓冲区。此外,还可以通过限制缓冲区的大小来控制溢出大小,当到达缓冲区末尾时,将返回错误代码。params[0]params[0]MDrm_Utils_ReadU32

我们通过概念验证触发了此 bug,并获得了以下崩溃:

[HM] [ERROR][2171]vmem_as_ondemand_prepare failed
[HM] [ERROR][2496]process 1f00000028 (tid: 40) data abort:
[HM] [ERROR][2498]Bad memory access on address: 0x1032000, fault_code: 0x92000047
[HM]
[HM] Dump task states for tcb
[HM] ----------
[HM] name=[TEE_SERVICE_MUL] 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=7015 prefer-ca=7015
[HM] Registers dump:
[HM] ----------
[HM] 32 bits userspace stack dump:
[HM] ----------
[HM] <MDrm_TA_CMD_OEMCrypto_LoadEntitledContentKeys+0x19c/0x27c>
[HM] <MDrm_TA_CMD_OEMCrypto_LoadEntitledContentKeys>+0x174/0x27c
[HM] <tee_task_entry>+0x398/0xcd4
[HM] Dump task states END
[HM]
[HM] [ERROR][2171]vmem_as_ondemand_prepare failed
[HM] [ERROR][2496]process 1f00000022 (tid: 34) data abort:
[HM] [ERROR][2498]Bad memory access on address: 0x41414149, fault_code: 0x92000046
[HM]
[HM] Dump task states for tcb
[HM] ----------
[HM] name=[TEE_SERVICE_MUL] tid=34 is-idle=0 is-curr=0
[HM] state=BLOCKED@MEMFAULT sched.pol=0 prio=49 queued=1
[HM] aff[0]=ff
[HM] flags=1000 smc-switch=0 ca=0 prefer-ca=0
[HM] Registers dump:
[HM] ----------
[HM] 32 bits userspace stack dump:
[HM] ----------
[HM] <?>+0x0/0x0
[HM] invalid fp. backtrace abort
[HM] Dump task states END
[HM]

可以利用此堆缓冲区溢出来获取任意读取和写入功能,我们将在本通报的“利用利用”部分中演示。

堆缓冲区溢出MDrm_TA_CMD_OEMCrypto_LoadKeys

可以在函数中找到类似的堆缓冲区溢出:MDrm_TA_CMD_OEMCrypto_LoadKeys

int MDrm_TA_CMD_OEMCrypto_LoadKeys(int paramTypes, TEE_Param params[4]) {
// [...]
cur_ptr = params[0].memref.buffer;
size_left = params[0].memref.size;
uint32_t *alloc;
// [...]

// 5 calls to MDrm_Utils_ReadU32
// [...]

ret = MDrm_Utils_ReadU32(cur_ptr, size_left, &read_val);
if (ret) goto EXIT;
cur_ptr += 4; size_left -= 4;

ret = MDrm_Memory_Calloc(10 * sizeof(uint32_t) * read_val, alloc);
if (ret) goto EXIT;

for (i = 0; i != read_val; ++i) {
for (int j = 0; j != 10; ++j) {
ret = MDrm_Utils_ReadU32(cur_ptr, size_left, &alloc[i*10+j]);
if (ret) goto EXIT;
cur_ptr += 4; size_left -= 4;
}
}

// 5 calls to MDrm_Utils_ReadU32
// [...]
ret = MDrm_TA_CryptoKeyLadder_LoadKeys(...);

EXIT:
MDrm_free(alloc);
return ret;
}

根本原因与上一个 bug 完全相同。例如,通过赋予值 0x6666667,分配的大小将为 。read_val0x6666667 * 0x28 = 0x18

我们通过概念验证触发了此 bug,并获得了以下崩溃:

[HM] [ERROR][2171]vmem_as_ondemand_prepare failed
[HM] [ERROR][2496]process 1f00000028 (tid: 40) data abort:
[HM] [ERROR][2498]Bad memory access on address: 0x1281000, fault_code: 0x92000047
[HM]
[HM] Dump task states for tcb
[HM] ----------
[HM] name=[TEE_SERVICE_MUL] 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=7265 prefer-ca=7265
[HM] Registers dump:
[HM] ----------
[HM] 32 bits userspace stack dump:
[HM] ----------
[HM] <MDrm_TA_CMD_OEMCrypto_LoadKeys+0x2d8/0x484>
[HM] <MDrm_TA_CMD_OEMCrypto_LoadKeys>+0x2b4/0x484
[HM] <tee_task_entry>+0x398/0xcd4
[HM] Dump task states END
[HM]
[HM] [ERROR][2171]vmem_as_ondemand_prepare failed
[HM] [ERROR][2496]process 1f00000022 (tid: 34) data abort:
[HM] [ERROR][2498]Bad memory access on address: 0x41414149, fault_code: 0x92000046
[HM]
[HM] Dump task states for tcb
[HM] ----------
[HM] name=[TEE_SERVICE_MUL] tid=34 is-idle=0 is-curr=0
[HM] state=BLOCKED@MEMFAULT sched.pol=0 prio=49 queued=1
[HM] aff[0]=ff
[HM] flags=1000 smc-switch=0 ca=0 prefer-ca=0
[HM] Registers dump:
[HM] ----------
[HM] 32 bits userspace stack dump:
[HM] ----------
[HM] <?>+0x0/0x0
[HM] invalid fp. backtrace abort
[HM] Dump task states END
[HM]

堆缓冲区溢出MDrm_TA_CMD_OEMCrypto_RefreshKeys

可以在函数中找到类似的堆缓冲区溢出:MDrm_TA_CMD_OEMCrypto_RefreshKeys

int MDrm_TA_CMD_OEMCrypto_RefreshKeys(int paramTypes, TEE_Param params[4]) {
// [...]
cur_ptr = params[0].memref.buffer;
size_left = params[0].memref.size;
uint32_t *alloc;
// [...]

// 1 call to MDrm_Utils_ReadU32
// [...]

ret = MDrm_Utils_ReadU32(cur_ptr, size_left, &read_val);
if (ret) goto EXIT;
cur_ptr += 4; size_left -= 4;

ret = MDrm_Memory_Calloc(6 * sizeof(uint32_t) * read_val, alloc);
if (ret) goto EXIT;

for (i = 0; i != read_val; ++i) {
for (int j = 0; j != 6; ++j) {
ret = MDrm_Utils_ReadU32(cur_ptr, size_left, &alloc[i*6+j]);
if (ret) goto EXIT;
cur_ptr += 4; size_left -= 4;
}
}

ret = MDrm_TA_CryptoKeyLadder_RefreshKeys(...);

EXIT:
MDrm_free(alloc);
return ret;
}

根本原因与上一个 bug 完全相同。例如,通过赋予值 0x6666667,分配的大小将为 。read_val0x80000001 * 0x18 = 0x18

我们通过概念验证触发了此 bug,并获得了以下崩溃:

[HM] [ERROR][2171]vmem_as_ondemand_prepare failed
[HM] [ERROR][2496]process 1f00000028 (tid: 40) data abort:
[HM] [ERROR][2498]Bad memory access on address: 0xc96000, fault_code: 0x92000047
[HM]
[HM] Dump task states for tcb
[HM] ----------
[HM] name=[TEE_SERVICE_MUL] 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=7182 prefer-ca=7182
[HM] Registers dump:
[HM] ----------
[HM] 32 bits userspace stack dump:
[HM] ----------
[HM] <MDrm_TA_CMD_OEMCrypto_RefreshKeys+0x1b4/0x23c>
[HM] <MDrm_TA_CMD_OEMCrypto_RefreshKeys>+0x18c/0x23c
[HM] <tee_task_entry>+0x398/0xcd4
[HM] Dump task states END
[HM]
[HM] [ERROR][2171]vmem_as_ondemand_prepare failed
[HM] [ERROR][2496]process 1f00000022 (tid: 34) data abort:
[HM] [ERROR][2498]Bad memory access on address: 0x41414149, fault_code: 0x92000046
[HM]
[HM] Dump task states for tcb
[HM] ----------
[HM] name=[TEE_SERVICE_MUL] tid=34 is-idle=0 is-curr=0
[HM] state=BLOCKED@MEMFAULT sched.pol=0 prio=49 queued=1
[HM] aff[0]=ff
[HM] flags=1000 smc-switch=0 ca=0 prefer-ca=0
[HM] Registers dump:
[HM] ----------
[HM] 32 bits userspace stack dump:
[HM] ----------
[HM] <?>+0x0/0x0
[HM] invalid fp. backtrace abort
[HM] Dump task states END
[HM]

堆缓冲区溢出MDrm_TA_OEMCryptoUsageTable_LoadUsageTableHeader

可以在函数中找到类似的堆缓冲区溢出:MDrm_TA_OEMCryptoUsageTable_LoadUsageTableHeader

int MDrm_TA_OEMCryptoUsageTable_LoadUsageTableHeader(TEE_Param *param1, uint32_t *a2) {
// [...]
// HMAC/SHA256 verification and AES/CBC/PKCS5 decryption of param1

cur_ptr = plaintext.memref.buffer;
size_left = plaintext.memref.size;
uint64_t *alloc;

// [...]
// 1 call to read_u64_update_ptrs

ret = MDrm_Utils_ReadU32(cur_ptr, size_left, &read_val);
if (ret) goto EXIT;
cur_ptr += 4; size_left -= 4;

ret = MDrm_Memory_Calloc(sizeof(uint64_t) * read_val, alloc);
if (ret) goto EXIT;

for (i = 0; !ret && i != read_val; ++i)
ret = read_u64_update_ptrs(&cur_ptr, &size_left, &alloc[i]);

// [...]
// loading of the usage table header

EXIT:
return ret;
}

根本原因与上一个 bug 完全相同。例如,通过赋予值 0x20000001,分配的大小将为 。read_val0x20000001 * 8 = 8

不幸的是,我们无法通过概念验证来触发此错误,因为输入数据首先经过身份验证和解密,并且我们没有找到一种独立的方法来泄漏这些操作中使用的密钥(但我们可以使用另一个错误来做到这一点)。

OOB 写入访问权限MDrm_TA_CMD_OEMCrypto_CopyBuffer

函数中有一个 OOB 写入访问权限,可以通过函数中开始的代码路径访问:MDrm_TA_Decryption_CopyBufferMDrm_TA_CMD_OEMCrypto_CopyBuffer

int MDrm_TA_CMD_OEMCrypto_CopyBuffer(int paramTypes, TEE_Param params[4]) {
// [...]
cur_ptr = params[0].memref.buffer;
size_left = params[0].memref.size;
memset_s(&cpybuf, 0x10, 0, 0x10);
// [...]

ret = MDrm_Utils_ReadU32(cur_ptr, size_left, &session_id);
// [...]

ret = MDrm_Utils_ReadU32(cur_ptr, size_left, &cpybuf.type);
// [...]

ret = MDrm_TA_ION_MemoryMap(
params[1].memref.buffer, params[1].memref.size, 1, 1, &ionbuf);
// [...]

switch (cpybuf.type) {
// [...]
case 1:
cpybuf.buf = params[2];
ret = MDrm_Utils_ReadU32(cur_ptr, size_left, &cpybuf.offset);
// [...]
break;
// [...]
}

ret = MDrm_Utils_ReadU32(cur_ptr, size_left, &val_read);
// [...]

MDrm_TA_Decryption_CopyBuffer(session_id, &ionbuf, &cpybuf, val_read);
// [...]

if (ionbuf.memref.buffer)
ret = MDrm_TA_ION_MemoryUnMap(
ionbuf.memref.buffer, ionbuf.memref.size, 1, params[1].memref.buffer);

return ret;
}

MDrm_TA_CMD_OEMCrypto_CopyBuffer从缓冲区中读取两个整数值和 。然后,它将 ION 缓冲区映射到 .如果为 1,则从缓冲区读取另一个整数值 。最后,它读取另一个值并调用 .session_idcpybuf.typeparams[0]params[1]ionbufcpybuf.typecpybuf.offsetparams[0]MDrm_TA_Decryption_CopyBuffer

int MDrm_TA_Decryption_CopyBuffer(int session_id, TEE_Param *ionbuf, copy_buf_t *cpybuf, int val_read) {
// [...]
TEE_Param outbuf;
// [...]

is_type_2 = 0;
ret = check_copybuf(ionbuf, cpybuf, &outbuf, &is_type_2);

if (!ret && !is_type_2) {
if (MDrm_TA_OEMCryptoEngine_FindSession(session_id, &session)) {
memcpy_s(outbuf.memref.buffer, ionbuf->memref.size,
ionbuf->memref.buffer, ionbuf->memref.size);
} else {
// [...]
}
}

// [...]
return ret;
}

MDrm_TA_Decryption_CopyBuffer调用。如果检查成功且不是 2,则调用 。如果会话 ID 无效,则它将从 into 复制,大小为 。是输入参数之一,所以让我们看看如何设置 .check_copybufcpybuf.typeMDrm_TA_OEMCryptoEngine_FindSessionionbuf->memref.bufferoutbuf.memref.bufferionbuf->memref.sizeionbufcheck_copybufoutbuf

int check_copybuf(TEE_Param *ionbuf, copy_buf_t *cpybuf, TEE_Param *outbuf, uint8_t *is_type_2) {
// [...]
TEE_Param *out_ionbuf;
// [...]

if (cpybuf.type == 1) {
cpybuf_buf = cpybuf->buf.memref.buffer;
cpybuf_size = cpybuf->buf.memref.size;

if (ionbuf->memref.size + cpybuf->offset <= cpybuf_size) {
outbuf->memref.size = ionbuf->memref.size;

is_secure_mem = 0;
ret = MDrm_TA_ION_IsSecureMemory(cpybuf_buf, cpybuf_size, &is_secure_mem);
if (!is_secure_mem)
return 0x77771001;

ret = MDrm_TA_ION_MemoryMap(cpybuf_buf, cpybuf_size, 0, 1, &out_ionbuf);
outbuf->memref.buffer = out_ionbuf->memref.buffer + cpybuf->offset;
return ret;
}
return 0x77770007;
}
// [...]
return ret;
}

check_copybuf,如果类型为 1,则检查 + <= 。它还确保从安全内存中分配。然后,它调用将其映射到 .最后,设置为 + 和 。ionbuf->memref.sizecpybuf->offsetcpybuf->buf.memref.sizecpybufMDrm_TA_ION_MemoryMapout_ionbufoutbuf->memref.bufferout_ionbuf->memref.buffercpybuf->offsetoutbuf->memref.sizeionbuf->memref.size

问题是加法时可能出现的整数溢出。例如,如果大小为 0x1000,则通过指定偏移量 ,总和将为 。因此,可以指定一个“负”偏移量,该偏移量将通过检查,从而位于 之前。ionbuf->memref.size + cpybuf->offset-0x1000 = 0xfffff0000x1000 + 0xfffff000 = 0outbuf->memref.bufferout_ionbuf->memref.buffer

回到 ,将 copy from 复制到我们的 out-of-bounds 值中。MDrm_TA_Decryption_CopyBuffermemcpy_sionbuf->memref.bufferoutbuf.memref.buffer

虽然我们为此错误编写了一些概念证明,但它并没有触发崩溃。我们认为这是在内存之前/内存中映射的,并且由于我们只能在范围内指定偏移量,因此 OOB 访问发生在映射的内存上。ionbufcpybufoutbuf[ -(ionbuf->memref.size) ; cpybuf_size - ionbuf->memref.size ]

二进制漏洞(更新中)

其它课程

windows网络安全防火墙与虚拟网卡(更新完成)

windows文件过滤(更新完成)

USB过滤(更新完成)

游戏安全(更新中)

ios逆向

windbg

恶意软件开发(更新中)

还有很多免费教程(限学员)

更多详细内容添加作者微信


文章来源: http://mp.weixin.qq.com/s?__biz=MzkwOTE5MDY5NA==&mid=2247490062&idx=1&sn=f5b234a3a0223dca7d990362dceff5fa&chksm=c13f2947f648a0518ab8c66eb32c694ee315043e954abc52a20c3b6d8eefc3a624575441401d&scene=0&xtrack=1#rd
如有侵权请联系:admin#unsafe.sh