二进制漏洞分析-7.华为TrustZone Vsim_Sw漏洞
2023-11-21 07:10:30 Author: 安全狗的自我修养(查看原文) 阅读量:6 收藏

华为TrustZone Vsim_Sw漏洞

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

如果你是想谈业务合作,直接翻到底联系作者。

  1. 不闲聊,直接说重点,我能不能做,你有没有预算,相关先介绍(我介绍技术、或者方案产品,你介绍需求带预算)就完事。

  2. 云桌面开发相关: 虚拟化(usb、usb透传、显示器、网卡、磁盘、声卡、摄像头)模块。

  3. 安全产品(dlp/edr/沙箱)开发相关:文件单/双缓冲透明加解密、网络防火防墙、所有通用外设管控(用户层版/驱动层版)模块、其它管理(恶意进程、模块等)。

  4. 通用开发相关:注入、hook、产品方案编写与设计、非黑灰产逆向、具体单独小功能编写。

如果你想系统学习二进制漏洞技能,往最后翻,或者直接翻到底联系作者。

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

  • HWPSIRT-2022-46490 TA_InvokeCommandEntryPoint中有限的任意函数调用

  • HWPSIRT-2022-09056 VSIM_CmdSaveAllMaincard中的整数溢出

  • HWPSIRT-2022-21738 VsimSaveOpiMainParam、VsimSaveOpiSlaveParam 和 VsimModemSendDhVsimData 中的堆栈缓冲区溢出

  • HWPSIRT-2022-87812 GenerateMasterMsg 中的参数缓冲区过度读取

  • HWPSIRT-2022-67695 VsimEncryptoString 中的参数缓冲区溢出

有限的任意函数调用TA_InvokeCommandEntryPoint

在 中,当收到来自正常世界的请求时,该函数将使用命令 ID 来检索相应的处理程序。但是,命令 ID 不受限制。如果攻击者能够泄露 的地址,他们将能够从 trustlet 应用程序地址空间中检索任意函数指针,从而执行任意代码。TA_InvokeCommandEntryPointg_cmds

TEE_Result TA_InvokeCommandEntryPoint(
void *sessionContext,
uint32_t commandID,
uint32_t paramTypes,
TEE_Param params[4])
{
// [...]
handler_fptr = g_cmds[commandID];
if (handler_fptr) {
ret = handler_fptr(sessionContext, paramTypes, params);
// [...]
}
// [...]
}

为了完全控制可以使用哪些函数指针,可以将它们放置在缓冲区中,这些缓冲区通常映射在从 .TEE_Param0x70003000

触发此 bug 的概念验证会导致崩溃:0xa3cf69c

[HM] [ERROR][2171]vmem_as_ondemand_prepare failed
[HM] [ERROR][2496]process 1d00000028 (tid: 40) data abort:
[HM] [ERROR][2498]Bad memory access on address: 0xa3cf69c, fault_code: 0x92000006
[HM]
[HM] Dump task states for tcb
[HM] ----------
[HM] name=[vsim_sw] 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=8463 prefer-ca=8463
[HM] Registers dump:
[HM] ----------
[HM] 32 bits userspace stack dump:
[HM] ----------
[HM] <TA_InvokeCommandEntryPoint+0x100/0x1d8>
[HM] <TA_InvokeCommandEntryPoint>+0xf4/0x1d8
[HM] <tee_task_entry>+0x398/0xcd4
[HM] Dump task states END
[HM]

堆栈缓冲区溢出 ,以及VsimSaveOpiMainParamVsimSaveOpiSlaveParamVsimModemSendDhVsimData

命令 #0x32 由函数处理,该函数是使用前两个输入缓冲区及其各自大小调用的包装器。VSIM_CmdSaveOptimisedMainParamVSIM_CmdSaveOptimisedMainParamTEE_Param

uint32_t VSIM_CmdSaveOptimisedMainParam(
void *sessionContext,
uint32_t paramTypes,
TEE_Param params[4])
{
// [...]
params[3].value.a = VsimSaveOpiMainParam(
params[0].memref.buffer,
params[0].memref.size,
params[1].memref.buffer,
params[1].memref.size);
return 0;
// [...]
}

VsimSaveOpiMainParam首先处理全局缓冲区,用户可以通过发送命令 #0x6 来设置该缓冲区。g_main_cardVSIM_CmdSaveAllMaincard

unsigned int VsimSaveOpiMainParam(
void *ibuf0_addr,
uint32_t ibuf0_size,
void *ibuf1_addr,
uint32_t ibuf1_size)
{
char* card_elems_array[22];
uint32_t card_elems_nb = 0;
// [...]
main_card_data = vsim_malloc("vsim_card.c", 0xA1D, 0x6128, 0);
// [...]
vsim_memmove_s(main_card_data, 0x6128, &g_main_card, 0x6128);
uint32_t card_elems_nb = vsim_strsplinum(main_card_data + 0x5818, "|");
vsim_split(card_elems_array, main_card_data + 0x5818, "|");
// [...]

VsimSaveOpiMainParam调用拆分主卡数据缓冲区每个字符,并将生成的块存储到 String 数组中。vsim_split|card_elems_array

void vsim_split(char **bufs_array, char *inbuf, char *separator)
{
char* buf = NULL;
while (buf = vsim_strtok(inbuf, separator))
*bufs_array++ = buf;
}

问题是从不检查参数的大小,只要在字符串中遇到,就会向 添加一个新条目。由于大小为 22,如果我们指定一个包含超过 22 个字符的条目,我们将开始溢出 的堆栈帧。例如,这可以通过替换调用函数的堆栈帧指针来导致代码执行,就像我们在Huawei_TSS_TA公告中所做的那样。vsim_splitbufs_arrayseparatorinbufbufs_arraycard_elems_arrayg_main_card|VsimSaveOpiMainParam

此漏洞的第二次出现可以在以下函数中找到:VsimSaveOpiSlaveParam

unsigned int VsimSaveOpiSlaveParam(
void *ibuf0_addr,
uint32_t ibuf0_size,
void *ibuf1_addr,
uint32_t ibuf1_size)
{
char* card_elems_array[22];
// ...
memset(card_elems_array, 0, sizeof(card_elems_array));
// ...
card_0x6128 = vsim_malloc("vsim_card.c", 0xA1D, 0x6128u, v9);
// ...
vsim_memmove_s(card_0x6128, 0x6128u, &g_slave_card, 0x6128u);
card_elems_nb = vsim_strsplinum(card_0x6128 + 0x5818, "|");
vsim_split(card_elems_array, card_0x6128 + 0x5818, "|");
// ...
}

这个需要设置,也可以由用户完成。g_slave_card

此漏洞的第三次出现可以在以下函数中找到:VsimModemSendDhVsimData

unsigned int VsimModemSendDhVsimData(int card_type, int a2) {
// ...
char *card_array[30];
// ...
memset(card_array, 0, sizeof(card_array));
// ...
card_data = vsim_malloc("vsim_modem_chicago.c", 0x1FD, 0x6128, 0);
ReadCard(card_data, card_type);
// ...
card_array_str = card_data + 0x5018;
vsim_strncat(card_array_str, 0x800, "|", 1);
card_unkn_str = card_data + 0x5818;
vsim_strncat(card_array_str, 0x800, card_unkn_str, strlen(card_unkn_str));
// ...
card_array_len = vsim_strsplinum(card_array_str, "|");
vsim_split(card_array, card_array_str, "|");
// ...
}

这需要用户设置 或 。g_master_cardg_slave_card

触发此 bug 的概念验证会导致崩溃:0x6778000

[HM] [ERROR][2171]vmem_as_ondemand_prepare failed
[HM] [ERROR][2496]process 1d00000028 (tid: 40) data abort:
[HM] [ERROR][2498]Bad memory access on address: 0x6778000, fault_code: 0x92000047
[HM]
[HM] Dump task states for tcb
[HM] ----------
[HM] name=[vsim_sw] 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=9110 prefer-ca=9110
[HM] Registers dump:
[HM] ----------
[HM] 32 bits userspace stack dump:
[HM] ----------
[HM] <vsim_split+0x40/0x80>
[HM] <vsim_split>+0x4c/0x80
[HM] <VsimSaveOpiMainParam>+0x208/0x400
[HM] invalid fp. backtrace abort
[HM] Dump task states END
[HM]
[HM] [ERROR][2519]process 1d00000022 (tid: 34) instruction fault:
[HM] [ERROR][2520]Bad addr: 0xffffff8797e01c94
[HM] Dump task states for tcb
[HM] ----------
[HM] name=[vsim_sw] 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] <pthread_join+0x28/0x14c>
[HM] <?>+0x0/0x0
[HM] invalid fp. backtrace abort
[HM] Dump task states END
[HM]

参数缓冲区过度读取GenerateMasterMsg

命令 (ID #0x6) 调用的函数中存在缓冲区过度读取。TEE_ParamGenerateMasterMsgVSIM_CmdSaveAllMaincard

uint32_t VSIM_CmdSaveAllMaincard(
void *sessionContext,
uint32_t paramTypes,
TEE_Param params[4])
{
// [...]
void* ibuf1_addr = params[1].memref.buffer;
uint32_t ibuf1_size = params[1].memref.size;
void* ibuf2_addr = params[2].memref.buffer;
uint32_t ibuf2_size = params[2].memref.size;
// [...]

if (ibuf1_size <= 0x591B || ibuf2_size <= 0x591B)
goto ERROR;

// [...]
GenerateAllMasterMsg(
ibuf1_addr, ibuf1_size,
ibuf2_addr, ibuf2_size,
hashSimLen_2, smid, hash_buf);
// [...]
}

此命令的处理程序首先调用 ,将第二个和第三个输入缓冲区作为其他用户控制值中的参数。处理程序还确保输入缓冲区的大小大于 0x591C。GenerateAllMasterMsgTEE_Param

uint32_t GenerateAllMasterMsg(
const void *mainEm,
uint32_t mainEmLen,
const void *mainSm,
uint32_t mainSmLen,
uint32_t hashSimLen,
const char *smid,
char *hash_buf)
{
// [...]
GenerateMasterMsg(mainEm, mainEmLen, 1, emMsg, &emMsgLen);
// [...]
}

GenerateAllMasterMsg然后将 ,即 ,传递给 。mainEmparams[1].memref.bufferGenerateMasterMsg

uint32_t GenerateMasterMsg(
char *mainEm,
uint32_t mainEmLen,
uint32_t msg_hash_count,
char *msg_hashes_out,
uint32_t *msg_hashes_out_len)
{
while ( 1 )
{
// [...]
diffLen = *(uint32_t)(mainEm + 0x5918);
diff = mainEm + 0x591C;
// [...]
mainEm = diff + 0x410 * diffLen;
}
}

最后,将遍历并检索不同的值,例如位于 .但是,由于仅检查大小是否大于 并且 因为使用用户控制的值进行更新,因此可以使点超出输入缓冲区的边界。GenerateMasterMsgmainEMdiffLenmainEm + 0x5918VSIM_CmdSaveAllMaincard0x591CmainEmdiffLenmainEmTEE_Param

触发此 bug 的概念验证会导致 崩溃 ,该地址位于 param 输入缓冲区之后:0x70015234

[HM] [ERROR][2171]vmem_as_ondemand_prepare failed
[HM] [ERROR][2496]process 1d00000028 (tid: 40) data abort:
[HM] [ERROR][2498]Bad memory access on address: 0x70015234, fault_code: 0x92000007
[HM]
[HM] Dump task states for tcb
[HM] ----------
[HM] name=[vsim_sw] 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=9152 prefer-ca=9152
[HM] Registers dump:
[HM] ----------
[HM] 32 bits userspace stack dump:
[HM] ----------
[HM] <GenerateMasterMsg.constprop.1+0x1d4/0x700>
[HM] <?>+0x0/0x0
[HM] <GenerateAllMasterMsg>+0x15c/0x2bc
[HM] <VSIM_CmdSaveAllMaincard>+0x27c/0xcc0
[HM] <TA_InvokeCommandEntryPoint>+0x11c/0x1d8
[HM] <tee_task_entry>+0x398/0xcd4
[HM] Dump task states END
[HM]

整数溢出VSIM_CmdSaveAllMaincard

命令处理程序 (ID #6) 中存在整数溢出。VSIM_CmdSaveAllMaincard

此函数首先计算在部分和输入缓冲区(以及其他事项)上计算的摘要。然后,它会检查输入缓冲区中包含的此摘要的签名是否有效。params[1]params[2]param[0]

如果签名正确,它会解析其中包含的原始“卡数据”并保存它。然后,它解析其中包含的原始“哈希卡数据”并保存它。该漏洞存在于计算将分配用于保存“哈希卡数据”的临时缓冲区的大小时。params[1]params[2]

unsigned int VSIM_CmdSaveAllMaincard(void *sessionContext, uint32_t paramTypes, TEE_Param params[4]) {
// ...
hashSimLen = *(uint32_t *)(params[0].memref.buffer + 0x44);
allDiffLen = *(uint32_t *)(params[0].memref.buffer + 0x48);
smid = ibuf0_addr + 0x4C;
hash_buf = vsim_malloc("vsim_card.c", 0x6E9, 0x100, 0);
// ...
GenerateAllMasterMsg(params[1].memref.buffer,
params[1].memref.size,
params[2].memref.buffer,
params[2].memref.size,
hashSimLen, smid, hash_buf);
// ...
VsimVerifyServerSign(6, hash_buf, params[0].memref.buffer);
vsim_free(hash_buf_1);
// ...
if ( ibuf1_size_1 != 1 ) { /* ... */ }
if ( ibuf2_size_1 != 1 ) {
hash_card_len = 0x5918 * hashSimLen + 0x410 * allDiffLen + 0x48;
hash_card = vsim_malloc("vsim_card.c", 0x750, hash_card_len, 0);
// ...
vsim_memset(hash_card, hash_card_len, 0, hash_card_len);
vsim_memmove_s(hash_card_, 0x41, smid, strlen(smid));
// ...
}
// ...
}

此缓冲区的此大小为 ,其中每次乘法都可能导致整数溢出,因为 和 值由用户控制。触发溢出更容易,而不是因为后者用于对 的调用。例如,通过将值指定为 0 和 0xfc0fc0fc for ,我们得到 .这种方式将是大小为 8 的堆分配缓冲区。0x5918 * hashSimLen + 0x410 * allDiffLen + 0x48hashSimLenallDiffLenallDiffLenhashSimLenGenerateAllMasterMsghashSimLenallDiffLen0x5918 * 0 + 0x410 * 0xfc0fc0fc + 0x48 = 0x8hash_card

由于分配之后的调用使用 0x41 字节的固定目标大小,并且具有完全由用户控制的源,因此我们具有完全受控的堆缓冲区溢出。然后,可以使用传统的堆利用技术来获得任意内存读/写。vsim_memmove_s

触发此 bug 的概念证明会导致稍后调用时检测到页脚损坏:TEE_Free

[vsim_sw-1] [Trace] VsimSaveHashCard: save hash card, smLen=22812
[vsim_sw-1] [Trace] vsim_memmove_s: dstLen=65
[vsim_sw-1] [Trace] vsim_memmove_s: srcLen=64
[vsim_sw-1] [Trace] VsimSaveFile: save file begin.
[vsim_sw-1] [Trace] VsimStorageMode: use cache, g_vsimStorageMode=2
[vsim_sw-1] [Trace] vsim_rpmb_save_file: rpmb save file begin.
[vsim_sw-1] [Trace] vsim_rpmb_save_file: rpmb save file success.
[vsim_sw-1] [Trace] VsimCacheHashNum: VsimCacheHashNum start
[vsim_sw-1] [Trace] VsimCacheHashNum: hashNum->hashSimLen=0
[vsim_sw-1] [Trace] VsimCacheHashNum: hashNum->allDiffLen=-66076420
[vsim_sw-1] [Trace] vsim_memmove_s: dstLen=8
[vsim_sw-1] [Trace] vsim_memmove_s: srcLen=8
[vsim_sw-1] [Trace] VsimCacheHashNum: VsimCacheHashNum end
[vsim_sw-1] [Trace] VsimSaveHashCard: save hash card success!
[HM] ERROR: free: corrupted footer
[vsim_sw-1] [Trace] VsimSaveMainSimData: save maincard ret=0x0

参数缓冲区溢出VsimEncryptoString

该函数由命令处理程序 (ID #0x15) 调用,用于加密参数输入缓冲区的内容。然后将密文放入参数输出缓冲区中。这是缓冲区溢出可能的地方。VsimEncryptoStringVSIM_CmdCrypto

unsigned int VSIM_CmdCrypto(void *sessionContext, uint32_t paramTypes, TEE_Param params[4]) {
// ...
VsimEncryptoString(
5,
params[1].memref.buffer,
params[1].memref.size,
params[2].memref.buffer,
&params[2].memref.size);
// ...
}
unsigned int VsimEncryptoString(
uint32_t type,
uint8_t *ibuf1_addr,
uint32_t ibuf1_size,
uint8_t *obuf2_addr,
uint32_t *obuf2_size_p)
{
// ...
len = 0;
buf = vsim_malloc("vsim_crypto.c", 0x2C, ibuf1_size + 0x20, 0);
// ...
VsimAesCbcPkcs5paddingEncryptIv(output, 0x20, ibuf1_addr, ibuf1_size, buf, &len);
// ...
vsim_memmove_s(obuf2_addr, len, buf, len);
*obuf2_size_p = len;
vsim_free(buf);
return 0;
}

在堆上分配一个大小足以容纳 IV 和密文的临时缓冲区。该函数使用参数输入缓冲区作为输入,使用临时缓冲区作为输出。然后使用 将临时缓冲区复制到参数输出缓冲区中,但目标大小与源大小相同,如果参数输出缓冲区小于输入缓冲区,则会导致缓冲区溢出。VsimAesCbcPkcs5paddingEncryptIvvsim_memmove_s

触发此 bug 的概念证明会导致位于参数输出缓冲区之后的地址发生以下崩溃:

[HM] [ERROR][2171]vmem_as_ondemand_prepare failed
[HM] [ERROR][2496]process 1d00000028 (tid: 40) data abort:
[HM] [ERROR][2498]Bad memory access on address: 0x7002301f, fault_code: 0x92000047
[HM]
[HM] Dump task states for tcb
[HM] ----------
[HM] name=[vsim_sw] 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=7060 prefer-ca=7060
[HM] Registers dump:
[HM] ----------
[HM] 32 bits userspace stack dump:
[HM] ----------
[HM] <memset+0x14/0xe0>
[HM] <memset_s>+0x28/0x38
[HM] invalid fp. backtrace abort
[HM] Dump task states END
[HM]
[HM] [TRACE][1212]pid=44 exit_status=130

受影响的设备

我们验证了这些漏洞是否影响了以下设备:

  • 麒麟990:P40 专业版 (ELS)

请注意,其他型号可能已受到影响。

补丁

名字严厉CVE漏洞补丁
有限的任意函数调用TA_InvokeCommandEntryPoint危急不适用(*)固定
整数溢出VSIM_CmdSaveAllMaincard危急不适用(*)固定
堆栈缓冲区溢出 ,以及VsimSaveOpiMainParamVsimSaveOpiSlaveParamVsimModemSendDhVsimData不适用固定
参数缓冲区过度读取GenerateMasterMsg不适用固定
参数缓冲区溢出VsimEncryptoString不适用固定

(*)华为关于APP漏洞的中、高、严重声明:

它们通过AppGallery升级来解决。通常,不会为此类漏洞分配 CVE 编号。

时间线

  • 2022年1月06日 - 向华为PSIRT发送漏洞报告。

  • 2022年3月22日 - 华为PSIRT确认该漏洞报告。

  • 从 2022 年 11 月 30 日至 2023 年 7 月 19 日 - 我们定期交换有关公告发布的信息。

二进制漏洞(更新中)

其它课程

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

windows文件过滤(更新完成)

USB过滤(更新完成)

游戏安全(更新中)

ios逆向

windbg

恶意软件开发(更新中)

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

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


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