当前位置:首页 > 电脑常识 > 正文

深入分析TIMA任意内核模块认证绕过缝隙 8090安适门户

11-21 电脑常识

为了确保Android设备中Linux内核的完整性,三星推出了一个名为“lkmauth”的成果。该成果的最初目的是,确保只有三星核准的那些内核模块才可以加载到Linux内核中。
TIMA任意内核模块认证绕过缝隙分析
每当内核测验考试载入内核模块时,系统就会用到“lkmauth”成果。在加载内核模块之前,内核首先会加载“lkmauth”的trustlet,并发送一个请求,来验证模块的完整性。
由于三星设备使用了两个差此外TEE,所以对付每个TEE都单独实现了相应的“lkmauth”成果。
在使用QSEE TEE(它使用了内核配置TIMA_ON_QSEE)的设备上,使用“tima_lkmauth”的trustlet来验证待加载的内核模块的完整性。固然,这个trustlet自己是相当简单的——它供给了一个硬编码的列表,来生存所有“可允许”的内核模块的SHA1哈希值。如果当前待加载的内核模块的SHA1没有呈此刻硬编码的列表中,那么它就会被拒绝。
对付使用MobiCore TEE(使用内核配置TIMA_ON_MC20)的设备而言,它们会通过“ffffffff00000000000000000000000b.tlbin”trustlet来验证待加载内核模块的完整性。然而,在这种情况下,其流程会稍微有点庞大,下面简单介绍加载模块的具体法式:
1. [如果trustlet尚未加载]:加载trustlet。
2. [如果已批准的哈希值列表尚未加载]:向trustlet发送请求,以便加载已批准的SHA1哈希签名列表。
3. 将存放内核模块的缓冲区通报给trustlet进行验证。如果该内核模块的SHA1哈希值不在先前加载的已批准哈希值列表中,则会被拒绝。
已经批准的模块的哈希值构成的列表,将作为设备固件的一部分,存储在文件“/system/lkm_sec_info”中。该文件的布局如下所示:

2311594986671494139135333717728917521928587827413928290661666521006388440638165953132321368
5988661310147714551519208211866717752764819593136041821730036424774768373518089158559738346
3994177112154456911035202716831086204704782174212539010452414635961457123236794791191821701
7815837667714661208782370479756312864598203165049599839041993901576956612577692924987866642
1780560391442439477189264423758971325406632562977618217815844688082799802924540355522191958
1473261217132518157522997441828405389283305681601885187948962567114647454381258357321281720
16078553039694575936536720388879378619731459541542508235684590815108447
RSA签名自己会使用PKCS#1 v1.5进行填充,此中BT = 1,PS是0xFF字节的常量字符串。

用于验证签名的公钥,我们可以通过静态分析要领从trustlet中找到。在trustlet的自身代码中,2048位的模数(N)是以反向字节挨次硬编码的形式存在的。经验证,在许多差此外设备和版本(如GT-I9300、SM-P600、SM-G925V等)中,都使用了不异的常量模量。这个模数自己是


这里使用的公钥指数为3。

发送到trustlet的请求缓冲区具有以下布局:

/* Message types for the lkmauth command */ typedef struct lkmauth_hash_s { uint32_t cmd_id; uint32_t hash_buf_start;/* starting address of buf for ko hashes */ uint32_t hash_buf_len;/* length of hash buf, should be multiples of 20 bytes */ uint8_t ko_num;/* total number ko */ } __attribute__ ((packed)) lkmauth_hash_t; 通过对trustlet中措置惩罚惩罚这个命令的代码进行逆向工程,得到了措置惩罚惩罚函数高级逻辑代码,具体如下所示: int load_hash_list(char* hash_buf_start, uint32_t hash_buf_len, uint8_t ko_num) { //Checking the signature of the hash buffer, without the length of the //public modulus (256 bytes = 2048 bits) uint32_t hash_list_length = hash_buf_len - 256; char* rsa_signature_blob = hash_buf_start + hash_list_length; if (verify_rsa_signature(hash_buf_start, hash_list_length, rsa_signature_blob)) return SIGNATURE_VERIFICATION_FAILURE; //Copying in the verified hashes into the trustlet //SHA1 hashes are 20 bytes long (160 bits) each //The maximal number of copied hashes is 0x23 //g_hash_list is a list in the BSS section of the trustlet //g_num_hashes is also in the BSS section of the trustlet uint8_t i; for (i=0; i memcpy(g_hash_list + i*20, hash_buf_start + i*20, 20); } g_num_hashes = i; return SUCCESS; }

问题在于,上述代码包罗了一个逻辑缺陷:没有对“ko_num”字段进行相应的验证,以确保其匹配哈希值列表的实际长度。这意味着打击者能够欺骗trustlet来加载特别的“允许哈希值”,即使它们不是已经签名的blob的一部分。为此,可以在供给与哈希值列表的原始长度匹配的"hash_buf_len"的时候,通过供给一个大于实际哈希值数量的“ko_num”字段来到达这一目的。然后,打击者可以在缓冲器中的签名blob之后供给任意的SHA1哈希值,从而导致这些特别的哈希值也会被复制到已经批准的可信哈希值列表中。
下面给出此类打击的一个具编制子: 

hash_buf_start = || || || hash_buf_len = len() + len() ko_num = (/20) + ceil(256/20) + 1

温馨提示: 本文由杰米博客推荐,转载请保留链接: https://www.jmwww.net/file/pc/13211.html

博客主人杰米WWW
杰米博客,为大家提供seo以及it方面技巧喜欢的朋友收藏哦!
  • 11365文章总数
  • 1378074访问次数
  • 建站天数
  •