华为TrustZone Vsim_Sw漏洞
二进制漏洞分析-5.华为安全监控漏洞(SMC MNTN OOB 访问)
如果你是想谈业务合作,直接翻到底联系作者。
不闲聊,直接说重点,我能不能做,你有没有预算,相关先介绍(我介绍技术、或者方案产品,你介绍需求带预算)就完事。
云桌面开发相关: 虚拟化(usb、usb透传、显示器、网卡、磁盘、声卡、摄像头)模块。
安全产品(dlp/edr/沙箱)开发相关:文件单/双缓冲透明加解密、网络防火防墙、所有通用外设管控(用户层版/驱动层版)模块、其它管理(恶意进程、模块等)。
通用开发相关:注入、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_InvokeCommandEntryPoint
g_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_Param
0x70003000
触发此 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]
VsimSaveOpiMainParam
VsimSaveOpiSlaveParam
VsimModemSendDhVsimData
¶命令 #0x32 由函数处理,该函数是使用前两个输入缓冲区及其各自大小调用的包装器。VSIM_CmdSaveOptimisedMainParam
VSIM_CmdSaveOptimisedMainParam
TEE_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_card
VSIM_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_split
bufs_array
separator
inbuf
bufs_array
card_elems_array
g_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_card
g_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_Param
GenerateMasterMsg
VSIM_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。GenerateAllMasterMsg
TEE_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
然后将 ,即 ,传递给 。mainEm
params[1].memref.buffer
GenerateMasterMsg
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;
}
}
最后,将遍历并检索不同的值,例如位于 .但是,由于仅检查大小是否大于 并且 因为使用用户控制的值进行更新,因此可以使点超出输入缓冲区的边界。GenerateMasterMsg
mainEM
diffLen
mainEm + 0x5918
VSIM_CmdSaveAllMaincard
0x591C
mainEm
diffLen
mainEm
TEE_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 + 0x48
hashSimLen
allDiffLen
allDiffLen
hashSimLen
GenerateAllMasterMsg
hashSimLen
allDiffLen
0x5918 * 0 + 0x410 * 0xfc0fc0fc + 0x48 = 0x8
hash_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) 调用,用于加密参数输入缓冲区的内容。然后将密文放入参数输出缓冲区中。这是缓冲区溢出可能的地方。VsimEncryptoString
VSIM_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,
¶ms[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 和密文的临时缓冲区。该函数使用参数输入缓冲区作为输入,使用临时缓冲区作为输出。然后使用 将临时缓冲区复制到参数输出缓冲区中,但目标大小与源大小相同,如果参数输出缓冲区小于输入缓冲区,则会导致缓冲区溢出。VsimAesCbcPkcs5paddingEncryptIv
vsim_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 | 危急 | 不适用(*) | 固定 |
堆栈缓冲区溢出 ,以及VsimSaveOpiMainParam VsimSaveOpiSlaveParam VsimModemSendDhVsimData | 低 | 不适用 | 固定 |
参数缓冲区过度读取GenerateMasterMsg | 低 | 不适用 | 固定 |
参数缓冲区溢出VsimEncryptoString | 低 | 不适用 | 固定 |
(*)华为关于APP漏洞的中、高、严重声明:
它们通过AppGallery升级来解决。通常,不会为此类漏洞分配 CVE 编号。
2022年1月06日 - 向华为PSIRT发送漏洞报告。
2022年3月22日 - 华为PSIRT确认该漏洞报告。
从 2022 年 11 月 30 日至 2023 年 7 月 19 日 - 我们定期交换有关公告发布的信息。
二进制漏洞(更新中)
其它课程
windows网络安全防火墙与虚拟网卡(更新完成)
windows文件过滤(更新完成)
USB过滤(更新完成)
游戏安全(更新中)
ios逆向
windbg
恶意软件开发(更新中)
还有很多免费教程(限学员)
更多详细内容添加作者微信