二进制漏洞分析-20.TrustZone Task_Phone_Novelchd漏洞(上)

admin 2023年12月10日19:39:23评论40 views字数 13563阅读45分12秒阅读模式

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

  • 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_EncryptWriteSecure_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_dataNOVEL_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, &params[1].memref.size);
    }
    /* [...] */
}

NOVEL_CHDRM_GetDeviceID传递输出缓冲区及其大小,而无需事先验证。无论其实际大小如何,这都会写入 0x20 个字节。例如,如果我们提供大小为 0x8 字节的输出缓冲区,则会导致 0x18 字节的缓冲区溢出。TEE_Paramobuf1_addrobuf1_sizepack_tlv_dataobuf1_addrTEE_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_dataTEE_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_PlainReadSecure_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

输出缓冲区首先作为参数传递给 ,然后传播到 和/或 。但是,从不检查其大小,这可能会导致在将数据复制到其中时缓冲区溢出。dataDRM_Secure_Store_ReadSecure_Store_PlainReadSecure_Store_EncryptRead

例如,我们将查看对 in 的易受攻击的调用,这是命令 ID #0x17 的处理程序。DRM_Secure_Store_ReadNOVEL_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,
            &params[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_SetDRMCertDataDRM_Secure_Store_Writeunpack_tlv_dataTEE_ParamDRM_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分析输入缓冲区以提取具有给定类型和键类型的值。它首先在输入缓冲区内定位值,计算其偏移量和长度。然后,使用 将该值复制到输出缓冲区中。值长度受输入缓冲区大小的限制。从不检查输出缓冲区长度,从而导致潜在的缓冲区溢出。inbufNOVEL_CHDRMw_Memcpyinsize


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 的处理程序。getvaluewithtypeandindexNOVEL_CHDRM_SetDRMDataLicenseResData

在 中,首先从 中提取缓冲区(大小不受限制)并将其复制到 中。然后,此缓冲区用作对 的调用的输入。此调用的输出是大小为 4 的堆栈变量。如上所述,可以将其超过 4 个字节复制到其输出中,从而导致缓冲区溢出。NOVEL_CHDRM_SetDRMDataLicenseResDataibuf0_addrdata1_pgetvaluewithtypeandindexOutputProtectiongetvaluewithtypeandindex


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_Paramunpack_tlv_dataGetOCSPResponse


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_Memcpyrsp_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_Memcpyrsp_status_pGetOCSPResponsersp_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_EncryptWriteSecure_Store_PlainWrite

Secure_Store_EncryptWrite,可以使用用户控制的 和 参数 via 调用,首先作为 TLV 对象打包到大小为 + 5 的堆分配缓冲区中。然后,它将文件的 0x2000 字节读入堆栈分配的结构中。然后,此函数多次表现出相同的易受攻击模式,即调用:DRM_Secure_Store_Writebufferbuffer_sizebufferbuffer_tlvbuffer_sizerpmb_dataNOVEL_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_databuffer_tlv_size

注意:包含与 相同的易受攻击的模式。这两个函数的调用方式与DRM_Secure_Store_Read中的缺失长度检查部分中所述相同。Secure_Store_PlainWriteSecure_Store_EncryptWrite

总而言之,我们确定了 12 个易受攻击的模式实例,这些实例会导致堆栈缓冲区溢出:

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年12月10日19:39:23
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   二进制漏洞分析-20.TrustZone Task_Phone_Novelchd漏洞(上)http://cn-sec.com/archives/2284567.html

发表评论

匿名网友 填写信息