二进制漏洞分析-5.华为安全监控漏洞(SMC MNTN OOB 访问)
二进制漏洞分析-10.华为TrustZone TEE_SERVICE_VOICE_REC漏洞
此通报包含有关以下漏洞的信息:
CVE-2021-46813 漏洞 GetOCSPResponse 中缺少长度检查
CVE-2021-46813 漏洞 NOVEL_CHDRM_Copyordecrypt中缺少长度和偏移检查
CVE-2021-46813 漏洞 NOVEL_CHDRM_SetDRMCertData中缺少长度检查
CVE-2021-40062 漏洞 缺少长度检查DRM_Secure_Store_Read
CVE-2021-40056 漏洞 getvaluewithtypeandindex 中缺少长度检查
CVE-2021-40057 漏洞 Secure_Store_EncryptWrite 和 Secure_Store_PlainWrite 中缺少长度检查
CVE-2021-40058 漏洞 NOVEL_CHDRM_SetRegisterResData中缺少长度检查
CVE-2021-40060 漏洞 调用NOVEL_CHDRMw_MemCompare时长度检查缺失/错误
CVE-2021-46813 漏洞 find_tlv_data中的整数下溢
CVE-2022-39003 漏洞 getvaluewithtypeandindex 中的 OOB 访问
HWPSIRT-2022-77114 未经检查的 Malloc 返回值
HWPSIRT-2021-84851 缺少长度检入pack_tlv_data
HWPSIRT-2021-40855 调用unpack_tlv_data后缺少长度检查
HWPSIRT-2021-36582 堆栈/堆/BSS 指针泄漏DRM_AES_Encrypt_xxx
HWPSIRT-2021-78954 unpack_tlv_data中的整数下溢
我们发现多个漏洞影响华为TASK_PHONE_NOVELCHD可信应用程序。为了使报告简明扼要,我们尝试对类似的漏洞进行重新组合。我们最终得到了下面给出的类别。
缺少长度检查导致TEE_Param输出缓冲区的 39 个缓冲区溢出pack_tlv_data
缺少长度检查导致 25 个缓冲区溢出(23 个堆栈分配,2 个堆分配)DRM_Secure_Store_Read
缺少长度检查,导致 13 个堆栈缓冲区溢出getvaluewithtypeandindex
缺少长度检查导致 14 个堆栈缓冲区溢出GetOCSPResponse
缺少长度签入并导致 12 个堆栈缓冲区溢出Secure_Store_EncryptWrite
Secure_Store_PlainWrite
缺少长度和偏移检查,导致:NOVEL_CHDRM_Copyordecrypt
1 堆栈缓冲区溢出
6 次 ION 缓冲液 OOB 写入
3 个 ION 缓冲液 OOB 读数
缺少长度检查导致 2 个堆栈缓冲区溢出NOVEL_CHDRM_SetDRMCertData
缺少长度检查导致:NOVEL_CHDRM_SetRegisterResData
1 堆栈缓冲区溢出
1 BSS 缓冲区溢出
调用后缺少长度检查,导致 6 堆缓冲区溢出unpack_tlv_data
堆栈/堆/bss 指针泄漏DRM_AES_Encrypt_xxx
整数下溢导致 OOB 读取/缓冲区过度读取unpack_tlv_data
整数下溢导致 OOB 读取/缓冲区过度读取find_tlv_data
未经检查的 malloc 返回值导致 10 个空指针取消引用
pack_tlv_data
¶该函数用于将 TLV 数据打包到输出缓冲区中。输出缓冲区的大小由用户控制,在写入之前从不检查,如果缓冲区不够大,无法写入其中的数据,则会导致缓冲区溢出。pack_tlv_data
void pack_tlv_data(uint8_t type, uint8_t *value, uint32_t length, uint8_t *outbuf, uint32_t *outbuf_size) {
outbuf[0] = type;
*(uint32_t *)(outbuf + 1) = bswap32(length);
if (length)
NOVEL_CHDRMw_Memcpy(outbuf + 5, value, length);
*outbuf_size = length + 5;
}
例如,我们将查看对 in 的易受攻击的调用,这是命令 ID #0x1 的处理程序。pack_tlv_data
NOVEL_CHDRM_GetDeviceID
TEE_Result TA_InvokeCommandEntryPoint(
void *sessionContext,
uint32_t commandID,
uint32_t paramTypes,
TEE_Param params[4])
{
/* [...] */
if (commandID == 1) {
DRM_CheckParamType(paramTypes, 5, 6, 0, 0);
/* [...] */
NOVEL_CHDRM_GetDeviceID(params[1].memref.buffer, ¶ms[1].memref.size);
}
/* [...] */
}
NOVEL_CHDRM_GetDeviceID
传递输出缓冲区及其大小,而无需事先验证。无论其实际大小如何,这都会写入 0x20 个字节。例如,如果我们提供大小为 0x8 字节的输出缓冲区,则会导致 0x18 字节的缓冲区溢出。TEE_Param
obuf1_addr
obuf1_size
pack_tlv_data
obuf1_addr
TEE_Param
int NOVEL_CHDRM_GetDeviceID(uint8_t *obuf1_addr, uint32_t *obuf1_size) {
pack_tlv_data(END_OF_CONTENT, &OTPChipIDHex, 0x20, obuf1_addr, obuf1_size);
return 0;
}
在这个特定示例中,TA 不会崩溃。但是有些调用具有可控大小,然后能够跨越页面边界,导致崩溃。pack_tlv_data
我们确定了 39 个易受攻击的调用,所有调用都写入了输出缓冲区的 OOB:pack_tlv_data
TEE_Param
地址 | 访客 | 冲击 |
---|---|---|
0x1420 | NOVEL_CHDRM_GetDeviceID+20 | 0x20 字节缓冲区溢出params[1] |
0x1540 | NOVEL_CHDRM_GetSerialNumber+10c | n 字节缓冲区溢出params[1] |
0x1638 | NOVEL_CHDRM_GetSecurityReqData+公元前 | 0x10 字节缓冲区溢出params[1] |
0x165c | NOVEL_CHDRM_GetSecurityReqData+E0 | 0x20 字节缓冲区溢出params[1] |
0x169c | NOVEL_CHDRM_GetSecurityReqData+120 | 4 字节缓冲区溢出params[1] |
0x1740 | NOVEL_CHDRM_GetSecurityReqData+1C4 | n 字节缓冲区溢出params[1] |
0x1774 | NOVEL_CHDRM_GetSecurityReqData+1F8 | n 字节缓冲区溢出params[1] |
0x199c | NOVEL_CHDRM_GetSecurityReqData+420 | n 字节缓冲区溢出params[1] |
0x1a44 | NOVEL_CHDRM_GetSecurityReqData+4C8 | n 字节缓冲区溢出params[1] |
0x1d30 | NOVEL_CHDRM_GetSignature+22c | n 字节缓冲区溢出params[1] |
0x2004 | NOVEL_CHDRM_GetAttestationSignature+244 | n 字节缓冲区溢出params[1] |
0x2828 | NOVEL_CHDRM_GetDRMTime+40 | 4 字节缓冲区溢出params[1] |
0x28d0 | NOVEL_CHDRM_GetTAVersion+90 | n 字节缓冲区溢出params[1] |
0x2f90 | NOVEL_CHDRM_GetLicenseReqData+66 8 | 1 字节缓冲区溢出params[1] |
0x30ec | NOVEL_CHDRM_GetLicenseReqData+7C4 | 0x14 字节缓冲区溢出params[1] |
0x3154 | NOVEL_CHDRM_GetLicenseReqData+82摄氏度 | 0x10 字节缓冲区溢出params[1] |
0x3184 | NOVEL_CHDRM_GetLicenseReqData+85摄氏度 | 4 字节缓冲区溢出params[1] |
0x31bc | NOVEL_CHDRM_GetLicenseReqData+894 | n 字节缓冲区溢出params[1] |
0x31e8 | NOVEL_CHDRM_GetLicenseReqData+8C0 | 0x20 字节缓冲区溢出params[1] |
0x35ac | NOVEL_CHDRM_DelLicenseReqData+280 | 1 字节缓冲区溢出params[1] |
0x5134 | NOVEL_CHDRM_SetDRMDataLicenseResData+1ae0 | 1 字节缓冲区溢出params[1] |
0x5ff8 | NOVEL_CHDRM_GetDRMCertData+234 | n 字节缓冲区溢出params[1] |
0x6110 | NOVEL_CHDRM_GetDRMCertData+34C | n 字节缓冲区溢出params[1] |
0x6220 | NOVEL_CHDRM_GetDRMCertData+45摄氏度 | n 字节缓冲区溢出params[1] |
0x6348 | NOVEL_CHDRM_GetDRMCertData+584 | n 字节缓冲区溢出params[1] |
0x644c | NOVEL_CHDRM_GetDRMCertData+688 | n 字节缓冲区溢出params[1] |
0x6554 | NOVEL_CHDRM_GetDRMCertData+790 | n 字节缓冲区溢出params[1] |
0x6e30 | NOVEL_CHDRM_GetRegisterReqData+13c | 1 字节缓冲区溢出params[1] |
0x6ebc | NOVEL_CHDRM_GetRegisterReqData+1C8 | n 字节缓冲区溢出params[1] |
0x7028 | NOVEL_CHDRM_GetRegisterReqData+334 | 2 字节缓冲区溢出params[1] |
0x70f8 | NOVEL_CHDRM_GetRegisterReqData+404 | n 字节缓冲区溢出params[1] |
0x7154 | NOVEL_CHDRM_GetRegisterReqData+460 | 2 字节缓冲区溢出params[1] |
0x724c | NOVEL_CHDRM_GetRegisterReqData+558 | n 字节缓冲区溢出params[1] |
0x7274 | NOVEL_CHDRM_GetRegisterReqData+580 | 20 字节缓冲区溢出params[1] |
0x72d4 | NOVEL_CHDRM_GetRegisterReqData+5e0 | n 字节缓冲区溢出params[1] |
0x7db4 | NOVEL_CHDRM_GetRegisterStatus+124 | n 字节缓冲区溢出params[1] |
0x7df8 | NOVEL_CHDRM_GetRegisterStatus+168 | 1 字节缓冲区溢出params[1] |
0x7f0c | NOVEL_CHDRM_GetRegisterStatus+27c | 1 字节缓冲区溢出params[1] |
0x7fa8 | NOVEL_CHDRM_GetRegisterStatus+318 | 1 字节缓冲区溢出params[1] |
DRM_Secure_Store_Read
¶DRM_Secure_Store_Read
使用或 从安全存储中读取数据,具体取决于正在读取的文件。Secure_Store_PlainRead
Secure_Store_EncryptRead
unsigned int DRM_Secure_Store_Read(void* data, uint32_t *data_len, uint32_t store_type)
{
if (store_type - 0x10 <= 0x4F) {
// drmCipherData
return Secure_Store_EncryptRead("64726D43697068657244617461.cli",
data, data_len, store_type, &version);
} if (store_type - 0x60 <= 0x9F) {
// drmPlainData
return Secure_Store_PlainRead("64726D506C61696E44617461.cli",
data, data_len, store_type, &version);
}
if (store_type <= 0xF) {
// drmCipherData
ret1 = Secure_Store_EncryptRead("64726D43697068657244617461.cli",
data, &outsize, store_type, &version);
*data_len = outsize;
// drmPlainData
ret2 = Secure_Store_PlainRead("64726D506C61696E44617461.cli",
data + outsize, &outsize, store_type, &version);
*data_len += outsize;
return ret1 | ret2;
}
// [...]
}
这里将:Secure_Store_EncryptRead
读取文件filename
;
解密其中的数据;
根据值检索 TLV 对象store_type
;
将结果复制到输出缓冲区中。data
unsigned int Secure_Store_EncryptRead(uint8_t *filename, void *data,
uint32_t *outsize, uint8_t store_type, uint32_t *version) {
/* [...] */
// Reads the file from the file
HiTEE_FlashRead(filename, &rpmb_data, 0x2000, &rpmb_data_size);
rpmb_data_size = _byteswap_ulong(rpmb_data.size);
/* [...] */
// In-place RPMB data decryption.
Secure_Store_DataDecrypt(rpmb_data.data, &rpmb_data_size);
/* [...] */
// Extracts data from the file according to the `store_type` argument.
unpack_tlv_data(store_type, rpmb_data.data, &rpmb_data_size,
&unpacked_tlv_buf_p, &unpacked_tlv_len);
/* [...] */
// Copies the result into the `data` output buffer provided to the function.
NOVEL_CHDRMw_Memcpy(data, unpacked_tlv_buf_p, unpacked_tlv_len);
/* [...] */
}
注意:除了解密过程外,执行相同的操作。Secure_Store_PlainRead
输出缓冲区首先作为参数传递给 ,然后传播到 和/或 。但是,从不检查其大小,这可能会导致在将数据复制到其中时缓冲区溢出。data
DRM_Secure_Store_Read
Secure_Store_PlainRead
Secure_Store_EncryptRead
例如,我们将查看对 in 的易受攻击的调用,这是命令 ID #0x17 的处理程序。DRM_Secure_Store_Read
NOVEL_CHDRM_GetSerialNumber
TEE_Result TA_InvokeCommandEntryPoint(
void *sessionContext,
uint32_t commandID,
uint32_t paramTypes,
TEE_Param params[4])
{
/* [...] */
if (commandID == 0x17) {
DRM_CheckParamType(paramTypes, 5, 6, 0, 0);
/* [...] */
NOVEL_CHDRM_GetSerialNumber(params[1].memref.buffer,
¶ms[1].memref.size);
}
/* [...] */
}
NOVEL_CHDRM_GetSerialNumber
从安全存储中读取类型为 0x60 的文件。读取的数据将写入大小为 2048 的堆栈分配缓冲区。DRM_Secure_Store_Read
int NOVEL_CHDRM_GetSerialNumber(uint8_t *obuf1_addr, uint32_t obuf1_size) {
/* [...] */
uint8_t cert[2048];
memset(cert, 0, sizeof(cert));
/* [...] */
DRM_Secure_Store_Read(cert, &cert_size, 0x60);
/* [...] */
}
但是,用户可以调用以将与类型 0x60 对应的值写入安全存储。文件数据和大小来自对输入缓冲区(由用户控制)进行操作的调用。因此,应该可以写入超过 2048 个字节,从而在使用 读取此数据时导致缓冲区溢出。NOVEL_CHDRM_SetDRMCertData
DRM_Secure_Store_Write
unpack_tlv_data
TEE_Param
DRM_Secure_Store_Read
int NOVEL_CHDRM_SetDRMCertData(uint8_t *ibuf0_addr, uint32_t ibuf0_size) {
/* [...] */
if (!unpack_tlv_data(0x16, ibuf0_addr, &ibuf0_size, &cert, &cert_size)) {
DRM_Secure_Store_Write(cert, cert_size, 0x60);
/* [...] */
}
/* [...] */
}
我们确定了 25 个易受攻击的调用,所有这些调用都可能导致缓冲区溢出:DRM_Secure_Store_Read
地址 | 访客 | 冲击 |
---|---|---|
0x149c | NOVEL_CHDRM_GetSerialNumber+68 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x16c8 | NOVEL_CHDRM_GetSecurityReqData+14c | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x16e4 | NOVEL_CHDRM_GetSecurityReqData+168 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x17b4 | NOVEL_CHDRM_GetSecurityReqData+238 | 基于堆栈的缓冲区溢出(如果大小为 4>) |
0x19e8 | NOVEL_CHDRM_GetSecurityReqData+46c | 基于堆栈的缓冲区溢出(如果大小为 8,则>) |
0x1bb0 | NOVEL_CHDRM_GetSignature+交流 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x2344 | NOVEL_CHDRM_VerifySignature+2b8 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x2fe0 | NOVEL_CHDRM_GetLicenseReqData+6b8 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x303c | NOVEL_CHDRM_GetLicenseReqData+714 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x3974 | NOVEL_CHDRM_SetDRMDataLicenseResData+320 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x53c4 | NOVEL_CHDRM_SetDRMCertData+1直流 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x546c | NOVEL_CHDRM_SetDRMCertData+284 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x5f9c | NOVEL_CHDRM_GetDRMCertData+1天8 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x60b0 | NOVEL_CHDRM_GetDRMCertData+2ec | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x61c0 | NOVEL_CHDRM_GetDRMCertData+3FC | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x62d4 | NOVEL_CHDRM_GetDRMCertData+510 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x63f4 | NOVEL_CHDRM_GetDRMCertData+630 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x64f8 | NOVEL_CHDRM_GetDRMCertData+734 | 基于堆的缓冲区溢出(任何大小) |
0x6d98 | NOVEL_CHDRM_GetRegisterReqData+A4 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x6e64 | NOVEL_CHDRM_GetRegisterReqData+170 | 基于堆的缓冲区溢出(如果大小为 256,则>) |
0x7cf4 | NOVEL_CHDRM_GetRegisterStatus+64 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x7d64 | NOVEL_CHDRM_GetRegisterStatus+D4 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x7e28 | NOVEL_CHDRM_GetRegisterStatus+198 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x7e90 | NOVEL_CHDRM_GetRegisterStatus+200 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x7f3c | NOVEL_CHDRM_GetRegisterStatus+2交流 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
getvaluewithtypeandindex
¶getvaluewithtypeandindex
分析输入缓冲区以提取具有给定类型和键类型的值。它首先在输入缓冲区内定位值,计算其偏移量和长度。然后,使用 将该值复制到输出缓冲区中。值长度受输入缓冲区大小的限制。从不检查输出缓冲区长度,从而导致潜在的缓冲区溢出。inbuf
NOVEL_CHDRMw_Memcpy
insize
uint32_t getvaluewithtypeandindex(
uint32_t type,
uint32_t key_type,
void *inbuf,
uint32_t insize,
void *outbuf,
uint32_t *outsize_p)
{
/* [...] */
/*
* Parses the input buffer `inbuf` to compute `value_size` and `value_offset`.
* A value is then extracted from `inbuf` and written into `outbuf`.
*/
if (insize >= value_size + value_offset) {
NOVEL_CHDRMw_Memcpy(outbuf, inbuf + value_offset, value_size);
*outsize_p = value_size;
return 0;
}
/* [...] */
}
例如,我们将查看对 in 的易受攻击的调用,这是命令 ID #0xE 的处理程序。getvaluewithtypeandindex
NOVEL_CHDRM_SetDRMDataLicenseResData
在 中,首先从 中提取缓冲区(大小不受限制)并将其复制到 中。然后,此缓冲区用作对 的调用的输入。此调用的输出是大小为 4 的堆栈变量。如上所述,可以将其超过 4 个字节复制到其输出中,从而导致缓冲区溢出。NOVEL_CHDRM_SetDRMDataLicenseResData
ibuf0_addr
data1_p
getvaluewithtypeandindex
OutputProtection
getvaluewithtypeandindex
unsigned int NOVEL_CHDRM_SetDRMDataLicenseResData(
uint8_t *ibuf0_addr,
uint32_t ibuf0_size,
uint8_t *obuf1_addr,
uint32_t *obuf1_size)
{
/* [...] */
unpack_tlv_data(0xD, ibuf0_addr, &ibuf0_size, &data1_p, &data1_size);
/* [...] */
OutputProtection = 0;
OutputProtection_size = 0;
getvaluewithtypeandindex(4, 6, data1_p, data1_size,
&OutputProtection, &OutputProtection_size);
/* [...] */
我们确定了 13 个易受攻击的调用,所有这些调用都可能导致堆栈缓冲区溢出:getvaluewithtypeandindex
地址 | 访客 | 冲击 |
---|---|---|
0x3aa4 | NOVEL_CHDRM_SetDRMDataLicenseResData+450 | 基于堆栈的缓冲区溢出(如果大小为 512,则>) |
0x3b14 | NOVEL_CHDRM_SetDRMDataLicenseResData+4c0 | 基于堆栈的缓冲区溢出(如果大小为 2048,则> |
0x3b84 | NOVEL_CHDRM_SetDRMDataLicenseResData+530 | 基于堆栈的缓冲区溢出(如果大小为 128,则>) |
0x3c3c | NOVEL_CHDRM_SetDRMDataLicenseResData+5e8 | 基于堆栈的缓冲区溢出(如果大小为 128,则>) |
0x3f74 | NOVEL_CHDRM_SetDRMDataLicenseResData+920 | 基于堆栈的缓冲区溢出(如果大小为 > 256) |
0x4188 | NOVEL_CHDRM_SetDRMDataLicenseResData+B34 | 基于堆栈的缓冲区溢出(如果大小为 32,则>) |
0x42c8 | NOVEL_CHDRM_SetDRMDataLicenseResData+C74 | 基于堆栈的缓冲区溢出(如果大小为 32,则>) |
0x443c | NOVEL_CHDRM_SetDRMDataLicenseResData+DE8 | 基于堆栈的缓冲区溢出(如果大小为 32,则>) |
0x4570 | NOVEL_CHDRM_SetDRMDataLicenseResData+F1C | 基于堆栈的缓冲区溢出(如果大小为 32,则>) |
0x48e0 | NOVEL_CHDRM_SetDRMDataLicenseResData+128C | 基于堆栈的缓冲区溢出(如果大小为 32,则>) |
0x4a1c | NOVEL_CHDRM_SetDRMDataLicenseResData+13C8 | 基于堆栈的缓冲区溢出(如果大小为 4>) |
0x4ad0 | NOVEL_CHDRM_SetDRMDataLicenseResData+147C | 基于堆栈的缓冲区溢出(如果大小为 > 256) |
0x4be4 | NOVEL_CHDRM_SetDRMDataLicenseResData+1590 | 基于堆栈的缓冲区溢出(如果大小为 16,则>) |
GetOCSPResponse
¶NOVEL_CHDRM_SetDRMCertData
是命令 ID #0xF 的处理程序,该处理程序将输入缓冲区及其大小作为参数。它首先调用从输入缓冲区中提取一个值,该值由用户控制,然后再将其传递给函数。TEE_Param
unpack_tlv_data
GetOCSPResponse
int NOVEL_CHDRM_SetDRMCertData(uint8_t *ibuf0_addr, uint32_t ibuf0_size) {
/* [...] */
ibuf0_size_cpy = ibuf0_size;
rsp_status_t rsp_status;
/* [...] */
if (!unpack_tlv_data(0x1C, ibuf0_addr, &ibuf0_size_cpy, &data_p, &data_size)) {
GetOCSPResponse(data_p, data_size, &rsp_status);
/* [...] */
}
/* [...] */
}
GetOCSPResponse
解析位于输入缓冲区中的 ASN.1 数据。在此函数中,有许多以下模式的实例:data_p
一个调用,它递增数据指针并检索当前标记的长度(无界)asn1_get_tag
调用 that 将标记数据从输入缓冲区复制到输出缓冲区NOVEL_CHDRMw_Memcpy
rsp_status_p
int GetOCSPResponse(uint8_t *data_p, uint32_t data_size, rsp_status_t *rsp_status) {
/* [...] */
asn1_get_tag(&data_p, seq0_end, &length, OID);
/* [...] */
NOVEL_CHDRMw_Memcpy(&rsp_status->field_14, data_p, length);
data_p += length;
/* [...] */
}
由于标记的长度是在没有任何检查的情况下给出的,这将导致缓冲区溢出(这是堆栈分配的缓冲区)。我们确定了 14 个易受攻击的模式,所有这些模式都会导致堆栈缓冲区溢出:NOVEL_CHDRMw_Memcpy
rsp_status_p
GetOCSPResponse
rsp_status_p
地址 | 访客 | 冲击 |
---|---|---|
0x3a7d0 | GetOCSP响应+1e0 | 基于堆栈的缓冲区溢出 |
0x3a8ec | GetOCSP响应+2fc | 基于堆栈的缓冲区溢出 |
0x3a994 | GetOCSP响应+3a4 | 基于堆栈的缓冲区溢出 |
0x3abc4 | GetOCSP响应+5d4 | 基于堆栈的缓冲区溢出 |
0x3ac84 | GetOCSP响应+694 | 基于堆栈的缓冲区溢出 |
0x3acec | GetOCSP响应+6fc | 基于堆栈的缓冲区溢出 |
0x3ad54 | GetOCSP响应+764 | 基于堆栈的缓冲区溢出 |
0x3ae18 | GetOCSP响应+828 | 基于堆栈的缓冲区溢出 |
0x3aee0 | GetOCSP响应+8f0 | 基于堆栈的缓冲区溢出 |
0x3b084 | GetOCSP响应+a94 | 基于堆栈的缓冲区溢出 |
0x3b138 | GetOCSP响应+b48 | 基于堆栈的缓冲区溢出 |
0x3b1f8 | GetOCSPResponse+c08 | 基于堆栈的缓冲区溢出 |
0x3b2bc | GetOCSP响应+ccc | 基于堆栈的缓冲区溢出 |
0x3b338 | GetOCSP响应+d48 | 基于堆栈的缓冲区溢出 |
Secure_Store_EncryptWrite
Secure_Store_PlainWrite
¶Secure_Store_EncryptWrite
,可以使用用户控制的 和 参数 via 调用,首先作为 TLV 对象打包到大小为 + 5 的堆分配缓冲区中。然后,它将文件的 0x2000 字节读入堆栈分配的结构中。然后,此函数多次表现出相同的易受攻击模式,即调用:DRM_Secure_Store_Write
buffer
buffer_size
buffer
buffer_tlv
buffer_size
rpmb_data
NOVEL_CHDRMw_Memcpy
rpmb_data.data
作为目的地;
buffer_tlv
作为来源;
buffer_tlv_size
作为长度。
TEE_Result Secure_Store_EncryptWrite(
char *filename,
void *buffer,
uint32_t buffer_size,
uint32_t store_type,
uint32_t a5)
{
/* [...] */
rpmb_data_t rpmb_data;
/* [...] */
buffer_tlv = NOVEL_CHDRMw_Malloc(buffer_size + 5);
pack_tlv_data(store_type, buffer, buffer_size, buffer_tlv, &buffer_tlv_size);
ret = HiTEE_FlashRead(filename, &rpmb_data, 0x2000, &rpmb_data_size);
if (ret == 0xFFFF7106) {
/* [...] */
NOVEL_CHDRMw_Memcpy(&rpmb_data.data[secure_store_len], buffer_tlv, buffer_tlv_size);
secure_store_len += buffer_tlv_size;
}
/* [...] */
}
由于大小为 0x2000,并且由用户控制,因此会发生堆栈缓冲区溢出。rpmb_data
buffer_tlv_size
注意:包含与 相同的易受攻击的模式。这两个函数的调用方式与DRM_Secure_Store_Read
中的缺失长度检查部分中所述相同。Secure_Store_PlainWrite
Secure_Store_EncryptWrite
总而言之,我们确定了 12 个易受攻击的模式实例,这些实例会导致堆栈缓冲区溢出:
地址 | 访客 | 冲击 |
---|---|---|
0x37e60 | Secure_Store_EncryptWrite+1cc | 基于堆栈的缓冲区溢出 |
0x38058 | Secure_Store_EncryptWrite+3C4 | 基于堆栈的缓冲区溢出 |
0x380a0 | Secure_Store_EncryptWrite+40摄氏度 | 基于堆栈的缓冲区溢出 |
0x380d8 | Secure_Store_EncryptWrite+444 | 基于堆栈的缓冲区溢出 |
0x38120 | Secure_Store_EncryptWrite+48C | 基于堆栈的缓冲区溢出 |
0x38190 | Secure_Store_EncryptWrite+4FC | 基于堆栈的缓冲区溢出 |
地址 | 访客 | 冲击 |
---|---|---|
0x385c4 | Secure_Store_PlainWrite+1C4 | 基于堆栈的缓冲区溢出 |
0x38764 | Secure_Store_PlainWrite+364 | 基于堆栈的缓冲区溢出 |
0x387ac | Secure_Store_PlainWrite+3交流 | 基于堆栈的缓冲区溢出 |
0x387e4 | Secure_Store_PlainWrite+3e4 | 基于堆栈的缓冲区溢出 |
0x3882c | Secure_Store_PlainWrite+42摄氏度 | 基于堆栈的缓冲区溢出 |
0x38878 | Secure_Store_PlainWrite+478 | 基于堆栈的缓冲区溢出 |
二进制漏洞(更新中)
其它课程
windows网络安全防火墙与虚拟网卡(更新完成)
windows文件过滤(更新完成)
USB过滤(更新完成)
游戏安全(更新中)
ios逆向
windbg
恶意软件开发(更新中)
还有很多免费教程(限学员)
更多详细内容添加作者微信