《電子技術(shù)應(yīng)用》
您所在的位置:首頁(yè) > 通信與網(wǎng)絡(luò) > 業(yè)界動(dòng)態(tài) > 查找與整數(shù)處理相關(guān)的溢出,、截?cái)嗟嚷┒?/span>

查找與整數(shù)處理相關(guān)的溢出、截?cái)嗟嚷┒?

2021-11-26
來(lái)源:嘶吼專業(yè)版
關(guān)鍵詞: 漏洞

  許多漏洞發(fā)生的根本原因是對(duì)整數(shù)的漏洞處理。標(biāo)準(zhǔn) int 類(lèi)型可以從 0x7FFFFFFF 一直到 -0x80000000(注意負(fù)數(shù)),,并帶有整數(shù)溢出,?;蛘?,它可以被截?cái)嗖?shù)字從正數(shù)更改為負(fù)數(shù)。整數(shù)在C語(yǔ)言中可能是一個(gè)噩夢(mèng),,并且多年來(lái)造成了許多內(nèi)存攻擊漏洞,。

  整數(shù)溢出漏洞(integer overflow):在計(jì)算機(jī)中,整數(shù)分為無(wú)符號(hào)整數(shù)以及有符號(hào)整數(shù)兩種,。其中有符號(hào)整數(shù)會(huì)在最高位用0表示正數(shù),,用1表示負(fù)數(shù),而無(wú)符號(hào)整數(shù)則沒(méi)有這種限制,。另外,,我們常見(jiàn)的整數(shù)類(lèi)型有8位(單字節(jié)字符、布爾類(lèi)型),、16位(短整型),、32位(長(zhǎng)整型)等,。關(guān)于整數(shù)溢出,,其實(shí)它與其它類(lèi)型的溢出一樣,都是將數(shù)據(jù)放入了比它本身小的存儲(chǔ)空間中,,從而出現(xiàn)了溢出,。由此引發(fā)的一切程序漏洞都可以成為整數(shù)溢出漏洞。

  最近有一些發(fā)現(xiàn)引起了我的注意,,它們屬于整數(shù)漏洞處理引起的漏洞,。整數(shù)溢出也是一種常見(jiàn)的軟件漏洞,由此引發(fā)的漏洞可能比格式化字符串缺陷和緩沖區(qū)溢出缺陷更難于發(fā)現(xiàn),。溢出類(lèi)型及表現(xiàn):

  1,、溢出。只有符號(hào)的數(shù)才會(huì)發(fā)生溢出,對(duì)于signed整型的溢出,,C的規(guī)范定義是“undefined behavior”,,也就是說(shuō),編譯器愛(ài)怎么實(shí)現(xiàn)就怎么實(shí)現(xiàn),。對(duì)于大多數(shù)編譯器來(lái)說(shuō),,仍然是回繞。

  2,、回繞,。無(wú)符號(hào)數(shù)會(huì)回繞(常繞過(guò)一些判斷語(yǔ)句)。

  3,、截?cái)?。將一個(gè)較大寬度的數(shù)存入一個(gè)寬度小的操作數(shù)中,高位發(fā)生截?cái)唷?/p>

  簡(jiǎn)單了解整數(shù)溢出的危害:

  1,、整數(shù)回繞之后,,會(huì)導(dǎo)致索引越界,取到不確定的數(shù)據(jù),。

  2,、 或者判斷失效,形成死循環(huán),。

  3,、回繞之后,導(dǎo)致分配超大內(nèi)存,。

  需要指出的是 Qualys 發(fā)現(xiàn)的 Linux 內(nèi)核中的整數(shù)截?cái)嗦┒?、GHSL 的 BSD 管理程序中的符號(hào)轉(zhuǎn)換漏洞以及 Checkpoint 發(fā)現(xiàn)的 Kindle 中緩沖區(qū)分配大小的整數(shù)溢出。然后,,我的伙伴 seiraib 發(fā)現(xiàn)了一個(gè)整數(shù)溢出漏洞模糊測(cè)試,,但我們無(wú)法找到溢出實(shí)際發(fā)生的位置。我想知道,,這漏洞會(huì)在編譯時(shí)被發(fā)現(xiàn)嗎,?還是會(huì)在運(yùn)行時(shí)立即崩潰?“

  GCC 和 Clang 有編譯標(biāo)志,,可以在編譯時(shí)查找?guī)讉€(gè)漏洞類(lèi),。此外,還有一些運(yùn)行時(shí)保護(hù)可能會(huì)導(dǎo)致崩潰,,從而使 root 操作更容易,。本文是關(guān)于通過(guò)編譯器警告和動(dòng)態(tài)檢測(cè)發(fā)現(xiàn)漏洞的。所有帶有額外示例的源代碼片段都可以在 mdulin2/integer_compile_flags 中找到,。

  漏洞類(lèi)

  目標(biāo)是以一種程序預(yù)期不會(huì)導(dǎo)致內(nèi)存損壞的方式更改數(shù)字,。C 語(yǔ)言中將重點(diǎn)關(guān)注三個(gè)數(shù)量(但主要是整數(shù))漏洞類(lèi):

  溢出/下溢:如果超過(guò)c中該類(lèi)型的最大值或最小值,整數(shù)將簡(jiǎn)單地環(huán)繞。例如,,有符號(hào)整數(shù)的溢出將從0x7FFFFFFF一直到-0x80000000,。下溢以相反的方向進(jìn)行,是在減去數(shù)值時(shí)發(fā)生的,。

  截?cái)啵嚎s小數(shù)字的存儲(chǔ)容量,。例如,從 uint64_t 到 uint32_t 會(huì)將數(shù)字的存儲(chǔ)容量減少一半,。這有可能徹底改變數(shù)字的值和符號(hào),。

  有符號(hào)類(lèi)型(signedness)轉(zhuǎn)換:數(shù)字要么是有符號(hào)的,要么是無(wú)符號(hào)的(例如 unsigned int 和 int),。當(dāng)從負(fù)有符號(hào)數(shù)轉(zhuǎn)換為無(wú)符號(hào)數(shù)或從非常大的無(wú)符號(hào)數(shù)轉(zhuǎn)換為有符號(hào)數(shù)時(shí),,在這些之間進(jìn)行轉(zhuǎn)換可能會(huì)產(chǎn)生可怕的后果。例如,,將 0xFFFFFFFF 的無(wú)符號(hào)整數(shù)轉(zhuǎn)換為有符號(hào)整數(shù)將是 -1 而不是非常大的數(shù)字,。

  靜態(tài)分析

  其中兩個(gè)漏洞類(lèi)可以在編譯時(shí)通過(guò)特定的編譯標(biāo)志來(lái)確定,盡管可能會(huì)出現(xiàn)大量不可利用的漏洞,,但還是有一些很好的線索可以用來(lái)發(fā)現(xiàn)漏洞,。

  截?cái)?/p>

  截?cái)啻a

  有符號(hào)類(lèi)型轉(zhuǎn)換代碼

  在編譯期間使用Wconversion標(biāo)志將輸出警告”可能改變值的隱式轉(zhuǎn)換“。這直接引用了截?cái)嗪娃D(zhuǎn)換漏洞,!

  例如,,截?cái)嗲闆r的代碼可以在圖 1 中看到。該代碼有一種正在轉(zhuǎn)換為 int 的 long long 類(lèi)型,。由于這會(huì)將存儲(chǔ)容量從 64 位更改為 32 位,,因此可能會(huì)導(dǎo)致?lián)p壞。當(dāng)使用Wconversion標(biāo)志編譯此代碼時(shí),,將出現(xiàn)一條警告消息,,指出截?cái)鄦?wèn)題!這個(gè)警告可以在下圖中看到,。當(dāng)執(zhí)行從size_t (unsigned long long)到int的轉(zhuǎn)換時(shí),,可以使用這個(gè)確切的漏洞消息來(lái)查找上面提到的Linux Kernel內(nèi)核漏洞。

  截?cái)嗑嫦?/p>

  另一個(gè)需要考慮的有趣事項(xiàng)是float和double的情況,。因?yàn)閐ouble是float大小的2倍,,所以相同類(lèi)型的截?cái)嗫梢酝ㄟ^(guò)相同的編譯標(biāo)志檢測(cè)到,,此處顯示了代碼中的一個(gè)示例,。

  有符號(hào)類(lèi)型

  Wconversion標(biāo)志也可以用于檢測(cè)符號(hào)轉(zhuǎn)換漏洞。當(dāng)從有符號(hào)轉(zhuǎn)換為無(wú)符號(hào)或從無(wú)符號(hào)整數(shù)轉(zhuǎn)換為有符號(hào)整數(shù)時(shí),,就會(huì)發(fā)生這種情況,,這兩個(gè)問(wèn)題都顯示在上圖中。下圖顯示了編譯時(shí)漏洞消息的一個(gè)示例。

  有符號(hào)類(lèi)型轉(zhuǎn)換警告消息

  靜態(tài)分析總結(jié)

  這些標(biāo)志只檢查隱式轉(zhuǎn)換,。有時(shí),,需要將一個(gè)值從無(wú)符號(hào)整數(shù)轉(zhuǎn)換為有符號(hào)整數(shù),以便進(jìn)行一些數(shù)學(xué)計(jì)算,,這是有效的和預(yù)期的C語(yǔ)言,。當(dāng)一個(gè)數(shù)字被顯式轉(zhuǎn)換時(shí),這些漏洞消息將不會(huì)顯示,,因此,。為了找到顯式的強(qiáng)制類(lèi)型轉(zhuǎn)換,可以使用類(lèi)似于CodeQL的東西,、手動(dòng)檢查或動(dòng)態(tài)測(cè)試,。

  盡管到目前為止我們只使用 Wconversion 進(jìn)行靜態(tài)分析,但實(shí)際上構(gòu)成了這個(gè)單一標(biāo)志的標(biāo)志過(guò)多,。例如,,Wsign-conversion 標(biāo)志警告可能會(huì)更改整數(shù)值符號(hào)的隱式轉(zhuǎn)換。有關(guān)這些的更多信息,,請(qǐng)?jiān)L問(wèn) GCC 文檔,。

  動(dòng)態(tài)儀表

  靜態(tài)分析很可能會(huì)得到大量誤報(bào),不過(guò)其中還是有一些真正的漏洞,。然而,,如果可以觸發(fā)代碼路徑,動(dòng)態(tài)分析總是能找到真正的漏洞,。下面,,我們將展示在與整數(shù)相關(guān)的漏洞上崩潰/通知的檢測(cè)選項(xiàng)。我們將討論GCC和Clang中的一些特定標(biāo)志,,而不是討論漏洞類(lèi),。

  ftrapv

  此選項(xiàng)為加法、減法和乘法運(yùn)算的有符號(hào)溢出生成漏洞,。同樣,,由于這是動(dòng)態(tài)測(cè)試,因此每當(dāng)發(fā)生這種情況時(shí)都會(huì)導(dǎo)致程序崩潰,!可以在下面看到此代碼的示例:

  當(dāng)行a = a + 1時(shí),,上面的代碼將導(dǎo)致整數(shù)溢出;,,因?yàn)镃中整數(shù)的最大大小是0x7FFFFFFF,。會(huì)發(fā)生什么呢?程序被終止,,并且永遠(yuǎn)不會(huì)到達(dá)print語(yǔ)句,。通過(guò)在發(fā)生溢出時(shí)強(qiáng)制崩潰,,我們可以保證檢測(cè)到漏洞,并且更容易找到溢出的原因,。這在模糊測(cè)試和嘗試找到崩潰根本原因時(shí)非常有用,。

  還應(yīng)該注意的是,該標(biāo)志也可以檢測(cè)有符號(hào)整數(shù)下溢,。

  fsanitize=integer

  用于查找整數(shù)漏洞的 UBSAN(未初始化行為清理器)非常棒,!此標(biāo)志特定于 Clang,用于與整數(shù)相關(guān)的漏洞,。

  雖然ftrapv只捕獲有符號(hào)整數(shù)溢出,,但fsanitize=integer將在無(wú)符號(hào)整數(shù)和有符號(hào)整數(shù)溢出(有符號(hào)整數(shù)溢出和無(wú)符號(hào)整數(shù)溢出)時(shí)崩潰。這意味著所有整數(shù)溢出,,無(wú)論符號(hào)如何,,通過(guò)加法、減法或乘法都將在運(yùn)行時(shí)被捕獲,。

  除了發(fā)現(xiàn)程序中的溢出/下溢外,,我們還可以找到用這個(gè)標(biāo)志提到的另外兩個(gè)漏洞類(lèi):截?cái)啵[式有符號(hào)整數(shù)截?cái)嗪碗[式無(wú)符號(hào)整數(shù)截?cái)啵┖娃D(zhuǎn)換(隱式整數(shù)符號(hào)改變)。與上面的靜態(tài)方法不同,,必須發(fā)生一個(gè)糟糕的數(shù)學(xué)運(yùn)算才能觸發(fā)UBSAN使程序崩潰,。

  不過(guò),讓我們看看它的實(shí)際效果,!我們將使用原始的符號(hào)問(wèn)題,。當(dāng)運(yùn)行代碼時(shí),值為L(zhǎng)ONG_MAX (0x7FFFFFFFFFFFFFFF)的long long將由于轉(zhuǎn)換為整數(shù)而被分為兩半(被截?cái)啵?。因此,,這將是0xFFFFFFFF或-1作為有符號(hào)整數(shù)。由于添加了額外的檢測(cè),,程序在截?cái)喟l(fā)生時(shí)崩潰,。這樣,設(shè)備就不需要改變標(biāo)志,,它檢查long long中的值是否適合int,。這個(gè)崩潰可以在下圖中看到。

  截?cái)噢D(zhuǎn)換崩潰

  我們已經(jīng)提到了對(duì)整數(shù)溢出/下溢,、整數(shù)截?cái)嗪头?hào)轉(zhuǎn)換問(wèn)題的動(dòng)態(tài)和靜態(tài)檢查,。但是,動(dòng)態(tài)檢測(cè)缺少一件事:浮點(diǎn)數(shù)學(xué)運(yùn)算,。

  當(dāng)浮點(diǎn)數(shù)學(xué)運(yùn)算在 C 中溢出時(shí),,它會(huì)變?yōu)闊o(wú)窮大或 inf。奇怪的是,,由于浮點(diǎn)數(shù)學(xué)處理精度的方式,,浮點(diǎn)數(shù)從未真正發(fā)生環(huán)繞,;它只是趨近于無(wú)窮大,!可以在此處查看此溢出的示例,。

  另一個(gè)未捕獲的漏洞是浮動(dòng)截?cái)唷@?,在運(yùn)行時(shí)不會(huì)捕獲從 double 到 float 的轉(zhuǎn)換,。有一個(gè)誤導(dǎo)性的 UBSAN 標(biāo)志 (-fsanitize=float-cast-overflow),它只能發(fā)現(xiàn)漏洞的雙精度/浮點(diǎn)數(shù)到整數(shù)的轉(zhuǎn)換,,但不會(huì)發(fā)現(xiàn)浮點(diǎn)數(shù)之間的截?cái)嗦┒?。這方面的一個(gè)例子可以在這里看到。

  了解浮點(diǎn)數(shù)變?yōu)?inf 和 NaN 可能很有用,,例如 Unreal 游戲引擎中的 Jack Bakers NaN 傳播漏洞確實(shí)會(huì)發(fā)生,。但是,目前沒(méi)有檢測(cè)到 C 語(yǔ)言中浮點(diǎn)數(shù)在運(yùn)行時(shí)的溢出,、下溢,、截?cái)嗷?NaN/Inf 使用。

  總結(jié)

  在嘗試查找漏洞時(shí),,任何來(lái)自自動(dòng)化工具或儀器的幫助都非常有用,。除了上面提到的整數(shù)漏洞類(lèi)之外,還有許多其他有趣的標(biāo)志和工具,,例如眾所周知的 ASAN(地址清理器),,還有許多其他編譯標(biāo)志和檢測(cè)選項(xiàng)可以幫助查找特定的漏洞類(lèi),本文只關(guān)注查找與整數(shù)相關(guān)的漏洞類(lèi),。




電子技術(shù)圖片.png

本站內(nèi)容除特別聲明的原創(chuàng)文章之外,,轉(zhuǎn)載內(nèi)容只為傳遞更多信息,并不代表本網(wǎng)站贊同其觀點(diǎn),。轉(zhuǎn)載的所有的文章,、圖片、音/視頻文件等資料的版權(quán)歸版權(quán)所有權(quán)人所有,。本站采用的非本站原創(chuàng)文章及圖片等內(nèi)容無(wú)法一一聯(lián)系確認(rèn)版權(quán)者,。如涉及作品內(nèi)容、版權(quán)和其它問(wèn)題,,請(qǐng)及時(shí)通過(guò)電子郵件或電話通知我們,,以便迅速采取適當(dāng)措施,避免給雙方造成不必要的經(jīng)濟(jì)損失,。聯(lián)系電話:010-82306118,;郵箱:[email protected]