自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

深入分析TIMA任意內(nèi)核模塊認(rèn)證繞過漏洞

安全 漏洞
為了確保Android設(shè)備中Linux內(nèi)核的完整性,三星推出了一個名為“l(fā)kmauth”的功能。每當(dāng)內(nèi)核嘗試載入內(nèi)核模塊時,系統(tǒng)就會用到“l(fā)kmauth”功能。

[[181702]]

前言

為了確保Android設(shè)備中Linux內(nèi)核的完整性,三星推出了一個名為“lkmauth”的功能。該功能的最初目的是,確保只有三星核準(zhǔn)的那些內(nèi)核模塊才可以加載到Linux內(nèi)核中。

TIMA任意內(nèi)核模塊認(rèn)證繞過漏洞分析

每當(dāng)內(nèi)核嘗試載入內(nèi)核模塊時,系統(tǒng)就會用到“lkmauth”功能。在加載內(nèi)核模塊之前,內(nèi)核首先會加載“lkmauth”的trustlet,并發(fā)送一個請求,來驗(yàn)證模塊的完整性。

由于三星設(shè)備使用了兩個不同的TEE,所以對于每個TEE都單獨(dú)實(shí)現(xiàn)了相應(yīng)的“lkmauth”功能。

在使用QSEE TEE(它使用了內(nèi)核配置TIMA_ON_QSEE)的設(shè)備上,使用“tima_lkmauth”的trustlet來驗(yàn)證待加載的內(nèi)核模塊的完整性。當(dāng)然,這個trustlet本身是相當(dāng)簡單的——它提供了一個硬編碼的列表,來保存所有“可允許”的內(nèi)核模塊的SHA1哈希值。如果當(dāng)前待加載的內(nèi)核模塊的SHA1沒有出現(xiàn)在硬編碼的列表中,那么它就會被拒絕。

對于使用MobiCore TEE(使用內(nèi)核配置TIMA_ON_MC20)的設(shè)備而言,它們會通過“ffffffff00000000000000000000000b.tlbin”trustlet來驗(yàn)證待加載內(nèi)核模塊的完整性。然而,在這種情況下,其流程會稍微有點(diǎn)復(fù)雜,下面簡單介紹加載模塊的具體步驟:

  1. [如果trustlet尚未加載]:加載trustlet。
  2. [如果已批準(zhǔn)的哈希值列表尚未加載]:向trustlet發(fā)送請求,以便加載已批準(zhǔn)的SHA1哈希簽名列表。
  3. 將存放內(nèi)核模塊的緩沖區(qū)傳遞給trustlet進(jìn)行驗(yàn)證。如果該內(nèi)核模塊的SHA1哈希值不在先前加載的已批準(zhǔn)哈希值列表中,則會被拒絕。

已經(jīng)批準(zhǔn)的模塊的哈希值組成的列表,將作為設(shè)備固件的一部分,存儲在文件“/system/lkm_sec_info”中。該文件的結(jié)構(gòu)如下所示:

  1. <LIST_OF_APPROVED_SHA1_HASHES> || <RSA-SHA1(LIST_OF_APPROVED_HASHES)> 

RSA簽名本身會使用PKCS#1 v1.5進(jìn)行填充,其中BT = 1,PS是0xFF字節(jié)的常量字符串。

用于驗(yàn)證簽名的公鑰,我們可以通過靜態(tài)分析方法從trustlet中找到。在trustlet的自身代碼中,2048位的模數(shù)(N)是以反向字節(jié)順序硬編碼的形式存在的。經(jīng)驗(yàn)證,在許多不同的設(shè)備和版本(如GT-I9300、SM-P600、SM-G925V等)中,都使用了相同的常量模量。這個模數(shù)本身是

  1. 23115949866714941391353337177289175219285878274139282906616665210063884406381659531323213685988661310147714551519208211866717752764819593136041821730036424774768373518089158559738346399417711215445691103520271683108620470478217421253901045241463596145712323679479119182170178158376677146612087823704797563128645982031650495998390419939015769566125776929249878666421780560391442439477189264423758971325406632562977618217815844688082799802924540355522191958147326121713251815752299744182840538928330568160188518794896256711464745438125835732128172016078553039694575936536720388879378619731459541542508235684590815108447 

這里使用的公鑰指數(shù)為3。

發(fā)送到trustlet的請求緩沖區(qū)具有以下結(jié)構(gòu):

  1. /* Message types for the lkmauth command */ 
  2. typedef struct lkmauth_hash_s { 
  3. uint32_t cmd_id; 
  4. uint32_t hash_buf_start;/* starting address of buf for ko hashes */ 
  5. uint32_t hash_buf_len;/* length of hash buf, should be multiples of 20 bytes */ 
  6. uint8_t ko_num;/* total number ko */ 
  7. } __attribute__ ((packed)) lkmauth_hash_t; 

通過對trustlet中處理這個命令的代碼進(jìn)行逆向工程,得到了處理函數(shù)高級邏輯代碼,具體如下所示:

  1. int load_hash_list(char* hash_buf_start, uint32_t hash_buf_len, uint8_t ko_num) { 
  2.   //Checking the signature of the hash buffer, without the length of the 
  3.   //public modulus (256 bytes = 2048 bits) 
  4.   uint32_t hash_list_length = hash_buf_len - 256; 
  5.   char* rsa_signature_blob = hash_buf_start + hash_list_length; 
  6.   if (verify_rsa_signature(hash_buf_start, hash_list_length, rsa_signature_blob)) 
  7.     return SIGNATURE_VERIFICATION_FAILURE; 
  8.   //Copying in the verified hashes into the trustlet 
  9.   //SHA1 hashes are 20 bytes long (160 bits) each 
  10.   //The maximal number of copied hashes is 0x23 
  11.   //g_hash_list is a list in the BSS section of the trustlet 
  12.   //g_num_hashes is also in the BSS section of the trustlet 
  13.   uint8_t i; 
  14.   for (i=0; i<ko_num && i<0x23; i++) { 
  15.     memcpy(g_hash_list + i*20, hash_buf_start + i*20, 20); 
  16.   } 
  17.   g_num_hashes = i
  18.   return SUCCESS; 

問題在于,上述代碼包含了一個邏輯缺陷:沒有對“ko_num”字段進(jìn)行相應(yīng)的驗(yàn)證,以確保其匹配哈希值列表的實(shí)際長度。這意味著攻擊者能夠欺騙trustlet來加載額外的“允許哈希值”,即使它們不是已經(jīng)簽名的blob的一部分。為此,可以在提供與哈希值列表的原始長度匹配的"hash_buf_len"的時候,通過提供一個大于實(shí)際哈希值數(shù)量的“ko_num”字段來達(dá)到這一目的。然后,攻擊者可以在緩沖器中的簽名blob之后提供任意的SHA1哈希值,從而導(dǎo)致這些額外的哈希值也會被復(fù)制到已經(jīng)批準(zhǔn)的可信哈希值列表中。

下面給出此類攻擊的一個具體例子:

  1. hash_buf_start = <ORIGINAL_SIGNED_HASH_LIST> || 
  2.                    <RSA-SHA1(ORIGINAL_SIGNED_HASH_LIST)> || 
  3.                    <4 GARBAGE BYTES> || 
  4.                    <ATTACKER_CONTROLLED_SHA1_HASH> 
  5.   hash_buf_len = len(<ORIGINAL_SIGNED_HASH_LIST>) + 
  6.                  len(<RSA-SHA1(ORIGINAL_SIGNED_HASH_LIST)>
  7.   ko_num = (<ORIGINAL_SIGNED_HASH_LIST>/20) + ceil(256/20) + 1 

由于“/system/lkm_sec_info”中的原始哈希值列表長度總是很短(例如從來不超過8)的,因此表達(dá)式(( / 20)+ ceil(256/20)+1)的值永遠(yuǎn)不會大于22。但是它仍然小于0x23(35)個哈希值的硬編碼下限,這意味著上面的代碼能夠正常執(zhí)行所提供的命令。此后,已批準(zhǔn)的哈希值列表將會變成如下所示的結(jié)構(gòu):

  1. original_approved_hash_1 
  2. original_approved_hash_2 
  3. ... 
  4. original_approved_hash_n 
  5. bytes_00_to_20_of_rsa_signature 
  6. bytes_20_to_40_of_rsa_signature 
  7. ... 
  8. bytes_240_to_256_of_rsa_signature || 4_garbage_bytes 
  9. attacker_controlled_sha1_hash 

實(shí)際上,這就將攻擊者控制的SHA1哈希值插入到了已批準(zhǔn)的哈希值列表中,從而成功繞過了簽名驗(yàn)證。

該漏洞的一種利用方法是,控制一個可以加載內(nèi)核模塊的進(jìn)程,然后將感染的哈希值列表請求發(fā)送給trustlet。例如,“system_server”進(jìn)程就具有這種能力,同時還能夠加載trustlet,并與之進(jìn)行通信(我們已經(jīng)在SM-G925V的默認(rèn)SELinux策略中進(jìn)行了相應(yīng)的驗(yàn)證):

  1. allow system_server mobicore-user_device : chr_file { ioctl read write getattr lock append open } ;  
  2. allow system_server mobicoredaemon : unix_stream_socket connectto ;  
  3. allow system_server mobicore_device : chr_file { ioctl read write getattr lock append open } ; 

將受感染的哈希值列表加載到trustlet之后,攻擊者就可以嘗試加載與剛才插入到列表中的SHA1哈希值相匹配的內(nèi)核模塊了。需要注意的是,加載模塊的第一次嘗試將會失敗,因?yàn)閮?nèi)核將嘗試加載已批準(zhǔn)的哈希值列表本身,但是trustlet將檢測到此情況并返回錯誤代碼RET_TL_TIMA_LKMAUTH_HASH_LOADED。這樣的話,內(nèi)核會做一個標(biāo)記,指出列表已經(jīng)加載好了——也就是說,下一次加載模塊的時候,就不會重新加載這個列表了:

  1. ... 
  2. else if (krsp->ret == RET_TL_TIMA_LKMAUTH_HASH_LOADED) { 
  3.   pr_info("TIMA: lkmauth--lkm_sec_info already loaded\n"); 
  4.   ret = RET_LKMAUTH_FAIL
  5.   lkm_sec_info_loaded = 1
  6. ... 

之后,第二次嘗試加載已經(jīng)感染的模塊的時候,就會成功了,因?yàn)樗墓V狄呀?jīng)位于已批準(zhǔn)的哈希值列表中了。

責(zé)任編輯:趙寧寧 來源: 安全客
相關(guān)推薦

2019-07-08 20:00:35

Linux內(nèi)核模塊

2010-01-22 11:01:04

linux內(nèi)核模塊

2009-12-11 09:42:54

Linux內(nèi)核源碼進(jìn)程調(diào)度

2009-12-11 09:47:23

Linux內(nèi)核源碼進(jìn)程調(diào)度

2009-12-17 15:28:32

內(nèi)核模塊編譯

2010-04-12 11:19:47

編譯內(nèi)核模塊

2017-09-28 10:12:51

2018-06-19 09:07:57

Linux內(nèi)核模塊

2023-05-08 08:05:42

內(nèi)核模塊Linux

2010-11-26 13:10:17

2010-09-07 14:21:22

PPPoE協(xié)議

2022-04-12 08:30:45

TomcatWeb 應(yīng)用Servlet

2011-03-23 11:01:55

LAMP 架構(gòu)

2021-09-03 08:44:51

內(nèi)核模塊Linux社區(qū)

2010-03-08 14:53:48

Linux分區(qū)

2011-09-01 13:51:52

JavaScript

2023-02-01 08:13:30

Redis內(nèi)存碎片

2010-09-29 14:21:22

2022-08-30 07:00:18

執(zhí)行引擎Hotspot虛擬機(jī)

2009-06-10 18:12:38

Equinox動態(tài)化OSGi動態(tài)化
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號