• 沒有找到結果。

國立陽明交通大學 資電亥客與安全碩士學位學程 碩士論文

N/A
N/A
Protected

Academic year: 2022

Share "國立陽明交通大學 資電亥客與安全碩士學位學程 碩士論文"

Copied!
35
0
0

加載中.... (立即查看全文)

全文

(1)

國立陽明交通大學

資電亥客與安全碩士學位學程 碩士論文

Graduate Degree Program of Cyber Security National Yang Ming Chiao Tung University

Master Thesis

程序運行期間之原位符號執行及其應用

In-Situ Symbolic Execution for Running Processes and Its Application

h 研 究 生:呂翰漳 (Lyu, Han-Zhang) 指導教授:林一平 教授(Dr. Lin, Yi-Bing)

1

吳育松 教授(Dr. Wu, Yu-Sung)

中華民國一一○年九月

September 2021

(2)

程序運行期間之原位符號執行及其應用

In-Situ Symbolic Execution for Running Processes and Its Application

h研 究 生:呂翰漳 sStudent: Han-Zhang Lyu

指導教授:林一平, 吳育松 Advisor: Yi-Bing Lin, Yu-Sung Wu

國立陽明交通大學

資電亥客與安全碩士學位學程 碩士論文

A Thesis

Submitted to Graduate Degree Program of Cyber Security College of Computer Science

National Yang Ming Chiao Tung University in partial Fulfillment of the Requirements

for the Degree of Master of Science

in

Computer Science

September 2021 Taiwan, Republic of China

中華民國一一○年九月

(3)

i

程序運行期間之原位符號執行及其應用

研究生:呂翰漳 t指導教授:林一平, 吳育松 國立陽明交通大學資電亥客與安全碩士學位學程

摘要

近年來資安漏洞層出不窮,為了找到能夠觸發這些漏洞的條件,我們必須提高程式 碼覆蓋率(code coverage),符號執行即為一種。不過符號執行仍然存在許多的限制,使 得多數大型系統無法充分利用其功效。如果大量的使用第三方函數庫或與系統呼叫則容 易使符號執行引擎產生不穩定的因素,產生錯誤的執行狀態。且不穩定的狀態容易使分 析系統的複雜度增加,往往需要耗費大量的分析時間。而許多程序有漏洞疑慮的範圍通 常不大,基於以上原因,在本研究中我們提出一種新的技術,稱為原位符號執行 (In-situ Symbolic Execution),不須將完整的程序作用於符號執行引擎,僅在特定區段使用符號 執行,再將執行結果同步回原程序中。使目標程序可以有效的跳過其中複雜的部份,並 讓其在具體環境中得以繼續執行。我們將選擇不會進入第三方函數庫的程式區段作分析,

最終證實不僅可以使得程序在具體環境與符號環境交互執行,且相較於傳統符號執行有 更好的執行效能。

關鍵詞:資安漏洞、符號執行、系統分析、原位系統、環境交互作用

(4)

ii

In-Situ Symbolic Execution for Running Processes and Its Application

Student: Han-Zhang Lyu Advisor: Yi-Bing Lin, Yu-Sung Wu Graduate Degree Program of Cyber Security

National Yang Ming Chiao Tung University

Abstract

In recent years, information security vulnerabilities have emerged endlessly. To find the conditions that can trigger these vulnerabilities, we must increase code coverage. Symbolic execution is one of them. However, symbolic execution still has many limitations, making most large systems unable to be used usually. If many third-party function libraries are used or called with the system, it is easy to cause unstable factors in the symbolic execution engine, resulting in an incorrect execution state. Moreover, the dangerous state quickly increases the complexity of the analysis system, which often requires a lot of analysis time. However, many programs have a small range of suspicion about vulnerabilities. Based on the above reasons, in this research, we propose a new technology called In-situ Symbolic Execution, which does not require the complete program to act on symbols. The execution engine only uses symbolic execution in a specific section. It then synchronizes the execution result to the original program so that the target program can effectively skip the complicated part and let it continue to execute in the concrete environment. We will choose the program sections that will not enter the third-party library for analysis. Finally, we prove that the program can be executed interactively in the concrete environment and symbolic environments and have better execution performance than the traditional symbolic execution.

Keywords: computer security vulnerabilities, symbolic execution, system analysis, In-situ system, environment interaction

(5)

iii

目錄

摘要... i

Abstract ... ii

目錄... iii

圖目錄... v

表目錄... vi

1. 背景 ... 1

符號執行 ... 1

符號執行的侷限性 ... 2

2. 原位符號執行 ... 4

挑戰與難處 ... 5

作用環境 ... 5

3. 系統設計 ... 6

運行時期程序狀態的提取 ... 7

程式碼擷取 ... 7

記憶體內容擷取 ... 8

符號引擎的執行 ... 9

同步至符號執行引擎 ... 9

符號化執行 ... 10

狀態還原 ... 12

4. 實作細節 ... 13

資料集 ... 13

同步作業 ... 13

擷取模式 ... 14

5. 實驗與結果 ... 15

資料輸入長度與執行效能評估 ... 15

真實程式原位符號化執行分析 ... 17

應用實例 ... 19

符號執行結果影響之多路徑汙染源追蹤比較 ... 19

(6)

iv

反制動作生成 ... 21

6. 相關研究 ... 23

7. 結論 ... 25

8. 參考文獻 ... 26

(7)

v

圖目錄

圖 1. 符號執行範例... 2

圖 2. 環境交互作用範例... 3

圖 3. 原位符號執行示意圖... 4

圖 4. 原位符號執行系統架構圖... 7

圖 5. 資料轉換流程圖... 10

圖 6. 符號化執行流程圖... 11

圖 7. 複雜運算範例... 15

圖 8. 執行結果示意圖... 16

圖 9. 符號執行間的效能比較... 17

圖 10. 汙染追蹤範例... 20

圖 11. 反制動作示意圖 ... 21

圖 12. 漏洞範例... 22

(8)

vi

表目錄

表 1. 符號執行間的效能比較... 16

表 2. bash5.0 中目標函數的符號化分析 ... 18

表 3. gzip1.10 中目標函數的符號化分析 ... 18

表 4. 多路徑汙染的符號化分析... 20

(9)

1

1. 背景

在本章中,我們將簡單介紹符號執行 (symbolic execution),並探討其侷限性。

符號執行

符號執行是一種程序分析的技術,用來找出適當的輸入使程序到達指定的部份。其 假設的輸入值並非實際值而是符號值,先根據分析程序中的特徵得到表達式,再利用分 支所可能導致的結果得到約束值 (constraint),最後利用求解器 (solver) 得到可以觸發 這些分支的可能輸入。其主要目標為盡可能尋找夠多的程序路徑 (program path),對於 每條路徑需要得到一組具體輸入的集合,以及檢查是否產生記憶體損壞等錯誤,而得到 越多的路徑就有越高的機率獲得通往目標位置 (target point) 的路徑。

符號執行最初的概念是在1976 年由 J. C. King [1] 所提出的,其論文中提及「解析 程序的路徑後,用符號模擬通過路徑並獲得輸出」;簡而言之,符號執行的結果會得到 特定區域的符號值。達到目標點後,分析器會得到相應的約束路經,再利用求解器得到 可以觸發目標點的具體值。由於當時的研究為了追求完整性,加上大型程序大多路徑較 為複雜難以完全遍歷,因而乏人聞問。這一問題到了2009 年,Vitaly Chipounov [2] 提 出了一種嶄新的想法「選擇性符號執行 (selective symbolic execution)」,是利用符號執 行錯覺的技術,可以僅象徵性地執行完整系統的任一部份,改善了路徑爆炸 (path explosion) [3] 的問題,使符號執行能有效的應用於大型程序上。

我們以一個簡單的符號執行為例,如圖 1 所示,變數 input 會讀入一個值,當值為 30 時會觸發目標位置,反之則會進入 fail()。在符號執行時,會將讀入的值設為符號值 λ,並將 λ / 2 設給 z;當執行至第 5 行的 if 條件判斷句時,由於符號引擎內部無法判斷 λ / 2 == 15 是否成立,故會將兩種分支結果分別執行。在執行時,引擎會將路徑約束與 分支起始位置的執行狀態複製一份,並分別用於兩條分支;在本例中,分支 printf()約 束路徑的判斷條件是λ / 2 == 15,而分支 fail()約束路徑的判斷條件則為 λ / 2 != 15。在 分析結束時,求解器會計算並得出一個具體的輸入值,即能夠達到該目標分支的解值,

解值可以讓使用者於具體執行中應用進而達到目標位置,在本例中解值為30。

(10)

2

1 2 3 4 5 6 7 8 9

void fun(){

input = read();

z = input / 2;

if(z == 15)

printf("target!!");

else

fail();

}

圖 1. 符號執行範例

符號執行的侷限性

傳統的符號執行技術往往需要從程式的進入點開始運行,這樣的方法會導致許多大 型程式在使用符號執行時難以遍歷程式,經常發生系統執行到一半時產生崩潰的現象,

其原因通常可以歸咎於過多的分支導致路徑以指數的形式擴大,從而造成路徑爆炸的問 題。

雖然現今大多數的符號執行引擎皆擁有可以透過選擇有效路徑的方式來提高符號 執行的可行性,但在面對如伺服器等級的大型程式時仍會面臨相同的問題,因為伺服器 是不會終止的,亦表示路徑以及符號執行引擎中的約束是會無止境的成長,直至無法求 解。因此於大型程式中使用完全符號執行是沒有意義的,在無法預知程式會運行到什麼 階段為止之前,符號執行也無法適時的用來求出結果。

在上例中我們演示了符號執行實際的內部操作,可以發現符號執行存在一些缺點。

隨著程序規模的擴大,其中分支數量的複雜度也會以指數級的成長,因此在中大型程式 中若想要完美利用符號執行至每條路徑,可能會產生路徑爆炸的問題。如果有些程序存 在無窮迴圈或是遞迴,會大大的增加具有意義的路徑,使符號執行的難度更加提高。為 了解決此問題,現代的符號執行大多採用執行獨立路徑或合併相似分支的方法,不過這 些都僅能緩解而不能解決在大型程式中會產生的路徑爆炸問題。

(11)

3

由於記憶體中對於已符號化的變數可能存在別名,對於這些別名,除非有特別標記,

否則符號執行引擎無法加以區分,導致執行後的結果產生偏差;或是符號變數是一連串 的記憶體位址的集合,符號執行引擎區要將這些集合視為一個單獨完整的變量去做處理,

其中這一種類型的變數也十分難處理。

最後是環境交互作用,如果一個程序與環境有交互作用時,符號執行將難以運行,

如圖 2 所示。符號執行會在第 6 行中的 if 條件判斷句產生兩個分支,並於第 13 行獲取 fp 對應內容的值;然而檔案操作是使用系統呼叫 (syscall) 實現的,符號執行無法進入 內核進行控制。

1 2 3 4 5 6 7 8 9 10 11 12 13 14

int main(){

FILE *fp = fopen("text");

...

if(state)

fprintf(fp, "something");

else

fprintf(fp, "the other thing");

...

data = fgets(..., fp);

}

圖 2. 環境交互作用範例

解決此一挑戰主要有三種方法:第一種是直接在符號執行期間執行系統呼叫,此一 做法的優點是實作方式簡單明瞭,缺點是並不是使用符號執行,所以得到的值是程序具 體執行的值。第二種是直接對運行的環境建模,這樣做的優點是可以取得正確的符號執 行結果,缺點是必須對每個模型去實現;在現今主流的符號執行系統如KLEE [4]、angr [5]、Driller [6]、Firmalice [7] 都支援此一做法。最後一種是創建整個程序中所有分支的 執行狀態,此一做法的空間複雜度非常高,而且對記憶體的使用量也很大;在S2E [8] 中 即會對每個符號執行的狀態進行一次個別的快照。

(12)

4

2. 原位符號執行

在本研究中,我們提出一種新的方法能夠使程式結合具體執行和符號執行,讓程式 可以使用兩種方式同時運行,還能使原程式無止盡的運行下去,我們將其定義為原位符 號執行 (In-situ Symbolic Execution)。我們的目標是在不影響原先程式運行的前提下,

引入符號執行的方法,使符號執行更輕量化。具體而言,在程式運行前加入中斷點 (break point),等到程式運行至此處時使用符號執行代入,符號執行結束後將其結果代回原先 程式的中斷點,使其繼續運行;僅利用執行符號執行感興趣的程式片段,也就是在具體 執行的原本位置上使用符號執行引擎,與一般符號執行的差異在於除了可以讓程序在具 體執行中呈現結果外亦可以使符號執行僅執行部分程式碼內容且可降低符號執行的副 作用。

原位符號執行指的是程序正常執行期間在原指令執行位址使用符號化執行,等待符 號執行完後再返回程序正常執行,如圖 3 所示。

圖 3. 原位符號執行示意圖

(13)

5

具體執行環境可於程序隨意位置直行至欲符號化的位置開始使用符號化引擎,開始 使用符號執行直到運行至目標位置,將符號狀態求解成具體狀態後導回具體執行環境的 欲符號化的位置,如此即可使用具體執行環境直行至目標位置。使用原位符號執行的做 法能達成以下三點:第一點是可以在任意程序中任意位置使用符號化執行;第二點是不 須理會原指令位置前複雜的符號狀態,因為指令前的狀態皆為程序執行期間的具體狀態;

第三點是可以使用正常具體執行的方式,而不必運行在符號執行的引擎上,意味著程序 可以使用一般方式運作,在需要符號執行時再轉換即可。

在本章中,我們將後續探討原位符號執行的挑戰與難處,及其作用環境。

挑戰與難處

要將具體執行轉為符號執行會面臨很多挑戰,其中又以指令的擷取最為困難,因為 並非使用符號執行引擎來執行整份程序,僅需擷取部分指令,而如何得到片段指令的資 訊,必須知道程序的起始、終點、以及目標位址,其中起點與終點必須包含所有可能會 執行到的位址。除此之外,還有可能會呼叫第三方函數,這些函數大多為程序執行時動 態連結上去的,程序本身的內容可以經由追蹤執行檔得到,但是大多數的動態連結函式 庫若是需要追蹤則會耗費大量的時間且難以自動化完成。此外程序的狀態如何導入符號 執行引擎也是一門挑戰,執行狀態大致可分為暫存器的值、heap 與 stack 的內容,基本 上若能做到這些狀態的同步就可以完成符號引擎的執行。

作用環境

大多數的符號執行引擎僅需程序的執行檔,而不須在獲得原始碼的前提下作業,不 過 為 了 追 蹤 執 行 檔 的 追 蹤 便 利 性 , 在 編 譯 期 間 會 關 閉 PIE (Position-Independent-Executable);PIE 的作用為使得共享庫 (shared library) 中的程式可 以被加載到不同的位址空間中,而程序則會跑在隨機的位址上,是一種保護機制。而關 閉PIE 則會使得程序每次都在固定位址上執行,增加我們逆向追蹤的可行性。本系統與

(14)

6

大多數的符號執行引擎相同,皆在不須獲得原始碼但需要在關閉 PIE 的條件下得以執 行。

3. 系統設計

在本章中,我們將介紹原位符號執行的系統設計,分為三個部份:第一部份為運行 時期程序狀態提取,其中最初包括在程式中加入中斷點,還有程式運行時的程式碼、記 憶體、暫存器以及欲符號化的變數的擷取,以上等資訊皆須提取出來引入符號引擎中;

第二部份為符號引擎的執行,基於程序狀態提取的資料引入符號引擎中,利用符號執行 找到目標位置後,再紀錄符號引擎狀態的改變與符號變數的求解值;第三部份為狀態還 原,本系統會還原狀態與符號變數之值於原先執行的程式中,再觀察其是否能夠執行至 所預期的目標位置,以及後續程式的運行是否異常。

本系統主要分為兩大部份:第一部份為原位系統 (In-situ System),此處的行為模式 為具體執行,主要目的為暫停與繼續執行目標程序,以及將所需的程式碼和記憶體資訊 切割下來交給符號執行引擎使用;第二部份為符號執行引擎,此處為進行符號執行的區 域,將變數或是記憶體內容符號化使其能夠運行至目標位置,再求得符號化內容,最後 將結果同步回目標系統,讓系統可以順利運行。整體的系統架構如圖 4 所示。

(15)

7

圖 4. 原位符號執行系統架構圖

原位系統主要功能為暫停目標程序及擷取所求的片段程式碼,再記錄系統當下的狀 態,使用這些數據建構出可將片段程式符號化的效果,等符號執行完畢後才同步回具體 執行之中。在目標系統運行以前,我們會先利用逆向分析的方式找出此系統需要被符號 執行的區塊以及欲執行到的目標位置,而這些區塊須由一個至數個基本塊所組成。當系 統執行到此一區塊時會將此程序暫停,交由符號執行引擎去運作至所設定的目標位置,

最終將得到的結果返回至目標程序,使其可以順利執行到目標位置。

運行時期程序狀態的提取

在本研究中,我們使用ptrace 來完成運行時期程序狀態的提取,包含程式碼以及記 憶體內容的擷取。

程式碼擷取

系統開始運行前,我們會選取一個至數個中斷點作為欲進行符號執行的起始位置,

然後將中斷點設置於此。具體而言,我們會擷取出中斷點後一個位元組的資料,並將其

(16)

8

變更為0xCC 再放回去;0xCC 為一種軟體使用中斷點的方式 (softer breakpoint),又可 以稱為INT3。等到程式開始執行後,系統程序依序執行指令至 0xCC 時,CPU 會自動 判斷為中斷點位置,然後暫停程序。接著將原本的指令內容寫回記憶體,並且需要保留 執行當下的所有狀態,以利未來系統能夠繼續正常執行。暫停之後,將所有符號執行可 能會執行到的程式碼區段擷取下來,並記錄其儲存位址。最後需要標記出欲執行到的位 置,我們稱之為目標位置,而其起始位置與目標位置須事前經由追蹤程式的二進位檔案 獲取。

為了避免環境交互作用所會產生的副作用,我們希望起始位置與目標位置的範圍設 限於同一函數內,如程式的主函數中;並盡量避免觸碰到會呼叫系統的內核調用,還有 產生不必要的外力影響符號執行的正確性。一般的符號執行須引入程序中的所有物件,

難免會呼叫到內核調用的函數;但是原位符號執行僅需執行部分程式內容,所以可以選 擇避開這些複雜的系統呼叫內容,並將符號執行引擎高效利用於片段化的程式碼中。

記憶體內容擷取

得到所需片段程式碼後,為了將完整的系統建構起來,我們需要中斷點當下的執行 狀態,包括記憶體內容以及暫存器的資訊。記憶體的內容由於過於龐大我們難以一一拷 貝出來,而且大部份皆為沒有用的資料,對繼續執行有益的不外乎為stack 與 heap。stack 與 heap 通常存放著記憶體配置,包括各種變數還有返回值 (return address);而且兩者 的記憶體映射 (memory mapping) 方式相同,皆為找到起始位置後做映射,不過這些資 訊的起始位置會因為每次程式的重新執行而被放置於記憶體中不同位置,因此必須進入 系統層面查找;關於各個程序記憶體對映,我們以 ubuntu 18.0 為例,會記錄在 /proc/[PID]/maps 裡面,得到起始位置後可利用 ptrace 函數去做記憶體內容的提取。

stack 的內容也是極為龐大,但有用的資訊通常不超過數百個位元組,所以與其花 大量的時間去比對程式碼內容,得到實際會使用到的記憶體位置,我們採用的方法是直 接提取固定數量的位元組的stack 內容,而這大小可視實驗的系統的複雜度做修正。

(17)

9

接著需要得到的是暫存器的值,暫存器存放著當下執行指令、數據、位址,可視為 讀寫速度非常快的記憶體。其值利用ptrace 可簡單的求出,不過無法如記憶體內容般大 量的複製,需要對每個暫存器去做一一的輸出對映。

運行符號化執行引擎

在本研究中,我們採用的符號執行引擎為 angr,大部份的情況下使用 angr 都會引 入整個執行檔做分析,但我們採用的是片段程式碼追蹤與符號執行時的分析,angr 也提 供了可以載入部份程式的api:load_shellcode(),在這個 api 中僅須提供足夠的基本資訊 如程式碼內容、位移量與處理器的架構、arm、x86 等等即可。

雖然完成了符號執行運轉的基礎條件,但程序並非從頭開始跑,所以我們必須引入 暫存器的內容使符號執行引擎知曉須從哪個指令開始執行以及各大記憶體的存放位址;

除了暫存器外,程序狀態所擷取下的記憶體內容也需要在引擎內同步上去。

同步至符號執行引擎

我們將探討具體執行期間的狀態所提取的資料如何引入符號引擎。將接收到的資料 分成三部份:程式碼的內容、暫存器的值以及記憶體的資訊。程式碼的內容因為是從記 憶體中裁減出來的,所以資料會是以二進位的方式作為輸入,事實上在 angr 之中不論 是以二進位碼亦或是組譯語言皆會被轉為中間語言的形式 (Intermediate representation),

而其所用的中間語言為VEX,為 angr 用以優化符號執行引擎所使用的語言,目的是將 所有處理器架構的語言統一。VEX 的主要核心價值是表達每一條指令對程序產生的影 響、走過哪些路徑,如此對於在測試中幫助程序改變所走的路徑,以達到高覆蓋率。而 程式碼內容經過中間語言轉換後會導入至angr 的記憶體中按照給定的偏移量放置。

只要放置好程式內容,就可以使用符號引擎去執行各項操作,此時會給予程序一組 空白的起始狀態,為了使空白狀態的程序可以從擷取出的程式碼起始位置開始運作,我 們下個階段必須將程序的暫存器同步至符號執行引擎,否則缺少各項暫存器之值會導致 執行期間出錯,如rip 之值未正確設置會使得處理器無法正確導入下個指令,或 rbp 會 造成stack 的位置錯誤等等。

(18)

10

記憶體的內容同步方式與暫存器大同小異,需要重新打包載入,不同的是需打包成 大端序 (big-endian) 的形式,雖然記憶體內容是連續的,但打包時有長度限制,所以必 須利用迴圈的方式逐一完成。而資料在具體執行環境與符號執行引擎之間的轉換流程如 圖 5 所示。

圖 5. 資料轉換流程圖

符號化執行

在符號引擎同步化完成後,需要對剛剛已有狀態的程序創建一個模擬器,事實上 angr 可以同時對一個符號化位置的狀態進行多種模擬,並產生多個分支,不須從頭配置

(19)

11

狀態僅需創建多個模擬器即可,若同時有許多分支會運行至目標位置,為保證結果的正 確性,可以指定避免執行到的位址,而符號化執行的流程圖如圖 6 所示。

具體而言,創建出模擬器後對程序輸入目標位置,目標位置的查找是使用人工的方 式利用二進位檔逆向追蹤出來的,其目的為使 angr 可以確切的執行到目標位置。一開 始系統會先判斷每個分支的符號執行引擎最後是否會達到目標位置,若最後不會達到目 標位置則會刪除該狀態分支;反之則會繼續判斷是否會運行置避免被執行位址。若符號 執行引擎有經過避免執行到的位址則會刪除該狀態分支;反之最終可以走到目標位置則 代表有解,可經由求解器求解得出變數或記憶體內容的值,再代回原目標程序,亦可經 由判斷符號化位置是否被執行得出記憶體位址是否被程式觸發。

圖 6. 符號化執行流程圖

(20)

12

狀態還原

符號執行完成後會得到一系列的值,再代回原目標程序。許多簡單的解值可以使用 手動的方式輸入,但大多的結果可能包含不可視字元,若輸入錯誤的話會導致無法運行 至原先預期的目標位置。我們採用的方法為將符號化變數的記憶體位置與解值輸出成檔 案後經由具體執行的系統輸入。

具體執行的系統接收到輸入後便會從中斷點處繼續執行,直到到達目標位置,原則 上我們僅會還原符號變數的內容,並不會對暫存器或其餘的記憶體內容作更動,因此不 會產生額外崩潰的問題。到達目標位置後可以選擇重複進行原位符號執行,這種方法主 要是將大型的符號執行部分拆成多個小的符號執行運作,並降低複雜度。

(21)

13

4. 實作細節

在本章中,我們將介紹原位符號執行的實作細節,包含資料集、同步作業以及擷取 模式。

資料集

我們將具體執行時蒐集到的程式碼、記憶體、暫存器內容分別儲存至對應的二進位 檔中,因為符號執行引擎所需要輸入的資料格式不相同,所以在同步至符號執行引擎前 必須先做資料的前處理。

由於ptrace 是使用 C 語言,但我們使用的符號執行引擎 angr 是使用 python 所撰寫,

因此暫存器內容需要重新打包,而擷取下的暫存器內容與 angr 所求皆為小端序 (little-endian),所以我們僅需利用 python 中的 pack 重新將數據打包即可。值得注意的 是取出的暫存器順序與長度固定,因此可以一同取出,但同步至符號執行引擎時需要每 個值逐一打包。記憶體的內容因為單一次數輸入長度的限制,每次只能以一個位元組為 單位進行輸入,且必須轉化成大端序以迴圈的方式輸入;程式碼的內容則僅需利用 load_shellcode 做輸入即可。

同步作業

從符號執行引擎得到的具體變數值同步回具體執行時,若直接將變數使用ptrace 修 改記憶體的值,容易導致系統無法正常執行,因為ptrace 一次會強制修改 8 位元組的資 料,而常見的整數型態如int、short 等等,這些字串的長度大多不是剛好的長度。若字 串的長度過短,則須讀取前半段記憶體內容位移適當的長度後,再加上變數值整合成8 位元組長度的資料;若字串的長度過長,則須分成多次進行輸入。這些同步時所使用的 記憶體內容需視資料型態做調整。

(22)

14

擷取模式

本系統中為了因應不同的目標程序,提供了兩種程式碼擷取模式的方法。第一種程 式碼擷取模式是從使用者下中斷點處至自我定義的長度為擷取範圍,此一模式適用於符 號執行影響範圍較小的目標程序;該作法的優點是可以有效降低擷取及轉換至符號執行 引擎時所耗費的資源。第二種程式碼擷取模式是手動輸入程式碼擷取的開頭以及範圍,

通常適用於作用範圍較大如呼叫自定義的函數,因為會涉及較大範圍的rip 跳躍,可能 會使符號執行引擎作用至難以預測的位置,因此建議做大範圍的程式碼擷取提高路徑查 找的成功率。

(23)

15

5. 實驗與結果

本 研 究 採 用 的 開 發 環 境 為 Intel i3-550 3.2GHz 、 8GB Memory、 作 業 系 統 為 Ubuntu18.08 (64 位元)、gcc 版本為 7.5.0,並利用 angr8 作為符號執行引擎。我們的實驗 主要為探討本研究開發的原位符號執行引擎與傳統符號執行的效能差異,還有對於不同 大小的目標函數使用原位符號執行做符號化分析,以及原位符號執行系統所能應用的一 些場景實例。

資料輸入長度與執行效能評估

對於擷取到的程式碼,內容往往難以經由人為運算或是簡易的邏輯逆向推理得到結 果,也就是說,即使使用電腦也需要暴力破解所有的可能性,導致求解時運算的複雜度 增加;在這種情況下,符號執行就成為求解最好的方法。我們以一個複雜運算為例,如 圖 7 所示,我們希望程序執行至第 8 行的 if 條件判斷句,並在第 9 行返回正確值,不 過就算在已知變數 encrypted 的情況下,依舊難以利用簡易的推演得到使結果引向正確 的輸入變數 input,因此我們使用不同的符號執行進行求解,使得程序能夠到達目標位 置。

1 2 3 4 5 6 7 8 9 10

for i (0 to len)

num1 = ((input[i]^i) << ((i^9)&3)) % 0x100

num2 = ((input[i]^i) >> (8 - ((i^9)&3))) % 0x100 num = (num1 | num2) % 0x100

if(encrypted[i] != (num+8)) break;

if(i == (len-1)) return true;

end for

圖 7. 複雜運算範例

(24)

16

圖 8 由上至下分別呈現原位符號執行時遇到中斷點、符號執行求解成功以及成功 同步回具體執行時的結果。

圖 8. 執行結果示意圖

本實驗比較了不同符號執行分別在不同輸入長度的變數 encrypted 下的平均求解時 間,也就是本系統原位符號執行與傳統符號執行 (angr) 的執行效能,對於每種輸入長 度我們分別進行了100 次的實驗,並各別取得平均求解時間,代表程序使用符號執行花 了多少時間到達目標位置。兩者符號執行間的執行效能結果如表 1 所示,而更明瞭的 效能比較結果如圖 9 所示。

表 1. 符號執行間的效能比較 輸入長度

符號引擎

5 bytes

10 bytes

20 bytes

30 bytes

50 bytes

100 bytes

200 bytes 原位符號執行 2.12 s 2.99 s 4.84 s 6.70 s 10.90 s 24.49 s 61.88 s

angr 5.10 s 6.09 s 8.34 s 10.57 s 15.49 s 30.97 s 72.87 s 執行時間差值 2.98 s 3.1 s 3.5 s 3.87 s 4.59 s 6.48 s 10.99 s

(25)

17

圖 9. 符號執行間的效能比較

經由上述實驗,我們可以發現在相同的輸入長度下,原位符號執行所花費的求解時 間比angr 還要少,代表原位符號執行相比於 angr 有較高的執行效能,且隨著輸入長度 的增加,求解的時間差愈加明顯,其原因可能為越長的輸入長度可以突顯原位符號執行 中輕量化的優點,減少多餘的額外函數影響。而目標程序若有大量的第三方函數則會造 成擷取程式碼的不易,導致效能降低。

真實程式原位符號化執行分析

在本節中,我們將針對不同大小的目標函數使用原位符號執行做符號化分析,證實 在 實 體環 境應 用的 可行 性 。本 實驗 比較 了不 同 的函 數呼 叫, 包括 bash5.0 [9] 的 set_shell_name()和 array_shift(),以及 gzip1.10 中的 huft_build()和 built_tree(),我們將對 其中的輸入字串做符號化並觀測,如表 2 和表 3 所示。

0 10 20 30 40 50 60 70 80

5 10 20 30 50 100 200

(s)

輸入長度(bytes) 原位符號執行 angr

(26)

18

表 2. bash5.0 中目標函數的符號化分析 分析對象

bash5.0 函數

總時間 記憶體設置時間 符號執行時間 指令數量

set_shell_name() 1.98 s 0.36 s 0.45 s 76 array_shift() 3.31 s 0.30 s 1.41 s 207

表 3. gzip1.10 中目標函數的符號化分析 分析對象

gzip1.10 函數 總時間 記憶體設置時間 符號執行時間 指令數量 huft_build() 4.05 s 0.40 s 1.98 s 298

built_tree() 5.51 s 0.31 s 3.43 s 154

set_shell_name()是針對使用者使用的殼程式做名稱設置,若配置為外部的殼程式名 稱,可能會導致程程序發生錯誤;array_shift()會將輸入的陣列依照相對應的參數做位移,

若 flags 參數被設置異常內容,會導致程序直接移除此一元素;huft_build()會利用給定 的代碼長度製作一組表,用來解碼該組代碼,若輸入超過預設長度的代碼則會回傳錯誤 訊息;build_tree()為一創建霍夫曼樹的演算法,我們試著改變樹記述子 (tree descriptor) 的內容值,使霍夫曼樹的高度可以縮限在一定範圍內。經過實測後皆有利用原位符號執 行至相對應位置,並同步回具體執行之中。其中 built_tree()使用較長的符號執行時間,

我們推測是結構較大的符號執行路徑較為複雜所導致。

(27)

19

應用實例

傳統符號執行大多難以在現實世界中運用,而我們將測試原位符號執行於汙染追蹤 分析及反制動作生成的應用實例。本節實驗採用的開發環境則為Intel i7-4770 3.2GHz、

32GB Memory。

符號執行結果影響之多路徑汙染源追蹤比較

汙點追蹤 (taint checking) [10] [11] [12] 可以避免使用者的資料如帳號密碼外洩至 系統其他部份,只要能被外部修改的資料就潛在著此一資安危機。本實驗將探討原位符 號執行對於汙點追蹤的可行性,基本原理是將欲標記為汙點處的資料先符號化,再經歷 符號執行引擎查找是否有其餘敏感變數被符號化,表示此一變數與汙點資料有所接觸。

如果有多條路徑皆會到達目標點,則可以觀察使用者在到達目標點前在不同路徑之下各 自會汙染哪些變數;如果某一變數只於特定路徑被汙染到,則開發者可以觀察在這一路 徑是否有資料外洩的問題或記憶體區段錯誤的產生,可運用於程式除錯方面。

與傳統符號執行的差別在於本研究可以跳過複雜的前置流程,直接利用起始位置的 狀態進行分析。我們以一個汙染追蹤為例,如圖 10 所示,在第 9 行的 while 迴圈之中,

我們將對變數a 分析處理得到兩變數 count_odd 與 count_even;有多種可能可以使程序 到達第19 行的目標位址,但這其中卻不是每種可能都會進入第 17 行的判斷條件;在此 我們將測試不同目標條件下被汙染的變數總位元數,如表 4 所示。

(28)

20

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

int main(int argc, char *argv[]){

int a;

int count_odd = 0, count_even = 0;

int x;

...

a = read();

while(a){

if(a % 2)

count_odd++;

else

count_even++;

a /= 2;

}

if(count_odd > 5 && count_even < 7){

if(count_even == 10) x = a + 5;

target_point();

}

if(user.id == “admin” || x > 10){

...

}

return 0;

}

圖 10. 汙染追蹤範例

表 4. 多路徑汙染的符號化分析 分析對象

變數長度 分支數 可到目標位

置的分支數

汙染5 btyes 的分支數

汙染9 btyes 的分支數

符號執行 時間

1 byte 256 37 36 1 16.50 s

2 bytes 12148 847 792 55 511 s

(29)

21

在本例中,汙染5bytes 與 9bytes 的差別在於是否有額外汙染到變數 x。若變數長度 為1 byte,所有可造成的分支數共有 256 種,其中可到達目標位置的分支數有 37 種,

而污染5 bytes 與 9 bytes 的分支數各占 36 與 1 種。在變數長度為 2bytes 的實驗中,理 論上應該有 65536 種分支被找尋出來,不過因為所需記憶體過於龐大所以只查找出 12148 種分支;其中可到達目標位置的分支數有 847 種,而污染 5 bytes 與 9 bytes 的分 支數各占792 與 55 種。值得注意的是,雖然長度只成長一倍,但符號執行時間卻從 16 秒大幅提升至511 秒,大約為 30 倍,可見其複雜度大量提升。若要將原位符號執行系 統運用於汙染追蹤,現階段僅適用於較小的變數長度。

反制動作生成

本研究除了可以自動查找漏洞外,還可利用已知的漏洞產生反制行為。若已知目標 程序於執行至符號執行起始位置時會產生數條分支,假設運行其中的某特定分支會使得 程序崩潰,則此時我們可以使用符號執行使程序強迫該分支永遠不成立,以達到阻斷特 定功能的目的。如下圖 11 所示,若已知目標程序於執行至符號執行起始位置時會產生 數條分支,假設運行其中的某特定分支會使得程序崩潰,則此時我們可以使用符號執行 使程序強迫該分支永遠不成立,以達到阻斷特定功能的目的。

圖 11. 反制動作示意圖

(30)

22

我們以一個漏洞為例,如圖 12 所示,當程序於第 18 行讀入一目標字串 input,在 第20 行進入函數 parse()解析字串時,我們假定 input 值為 ls 則會觸發漏洞,此時我們 將利用原位符號執行使具體系統改變字串input 的內容,使其跳過漏洞函數。若需要降 低跳過函數帶來的副作用,可選擇於函數下方插入下一個中斷點,之後再將其復原,如 此即可利用此一函數達到繞過的效果。根據實驗結果表示可以達成目標,其中字串比較 函數strcmp()屬於第三方函數,所以需要使用 angr 內部實作的 hook()將其二元碼轉換為 python 執行,最終我們使用本研究的系統可以使本例於 1.113 秒執行完成並使原程序繼 續執行。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

char* parse(char *input){

...

if(strcmp(input, “ls”) == 0) vulnerability();

else ...

...

return output;

}

int main(){

char* input;

input = (char*) malloc(sizeof(char) * 256);

input = read();

execute(parse(input));

free(input);

return 0;

}

圖 12. 漏洞範例

(31)

23

6. 相關研究

concolic [13] 為具體 (concrete) 與符號化 (symbolic) 所複合而成的一個單字,

concolic 測試為一種同時使用具體執行 (concrete execution) 以及符號執行的混合技術。

符號執行階段利用約束求解器生成可以在具體執行中所使用的輸入值,在測試時可直接 代入具體執行,不必將目標程式全部符號化,目的為提高程式碼的覆蓋率,且可以有效 的解決路徑爆炸的問題,其原因在於僅需將特定有興趣的變數值符號化,可避免多數未 使用到此一變數的分支產生多餘路徑,現今許多符號執行引擎皆有支援concolic 測試,

如KLEE [4]、Driller [6]。concolic 測試適用於模型檢查中,可以利用具體狀態以及符號 狀態檢查軟體的各種屬性是否正常,能否到達一些正常不可到達的狀態;亦即concolic 測試是用於尋找程序中有無問題點,並描述其正確性,而非正常地執行程序。與傳統符 號執行不同的是concolic 測試適合用來查找程序錯誤的部分,而傳統符號執行則適合用 於完全的路徑探索,而原位符號執行則是對於傳統符號執行做改善,但兼具了concolic 測試的優點可與具體執行與符號化執行同步運行。

symbion [14] 為了解決符號執行期間會產生的狀態爆炸問題並提高程式碼覆蓋率,

加上為了消除符號執行期間與周圍環境 (函式庫、作業系統) 的交互建模關係,而提出 了使用符號執行與具體執行交錯的方法,僅在符號執行時探索程式碼中感興趣的部份。

主要是利用具體環境來運行輸入程序,再將與環境的交互結果與符號執行引擎進行同步,

因為與環境交互建模的部份都存在於具體執行中,所以可以緩解符號執行會產生的問題。

此外,由於複雜的部份都將委派於具體環境,因此也不會產生狀態爆炸的問題。與本研 究不同的是該方法可以同步的進行符號執行與具體執行,而我們需要等系統暫停後才可 以對程式碼做擷取。

S2E [8] 為一種可以自動搜尋路徑的系統,基於 QEMU [15]、KLEE [4]、LLVM [16]

而成,分別對應於虛擬機的目標程序執行、符號執行引擎、動態二進位檔的編譯。該系 統允許使用者定義程序的哪些部份需要被符號執行或具體執行,從而有效解決路徑爆炸 的問題,不過需要耗費大量的記憶體做快照;而本系統則不需要使用大量的記憶體空 間。

(32)

24

模糊測試 [17] 為一種利用隨機生成的輸入來觸發軟體漏洞的方法,利用高程式覆 蓋範圍找到隱藏在程式碼深度較高的部分,我們的系統是利用符號執行的方式找到較深 處的目標程式碼。

(33)

25

7. 結論

在本研究中我們提出一套使目標程序在具體執行期間使用符號化引擎執行,結束時 再同步回原目標程序的新系統,稱為原位符號執行。本系統不僅使符號執行得以更輕量 化的執行,還避免了環境交互作用所帶來的副作用;且得益於此系統交互執行的原理,

可以使目標程序完美的繼續執行。

我們於實驗章節驗證原位符號執行系統的可行性與相對於傳統符號執行所帶來的 高效能;並證實在bash5.0 與 gzip1.10 的部份函數中可以順利運作本系統且正確還原至 具體環境;最後在應用實例的部份將模擬出的可用場景一一實現,包括污染追蹤與反制 動作。

目前尚未處理動態連結函數庫的程式碼片段,因為地址空間過大造成擷取部分尚無 法完善。

(34)

26

8. 參考文獻

[1] J. C. King, "Symbolic execution and program testing," Communications of the ACM, vol.

19, no. 7, pp. 385-394, 1976.

[2] V. Chipounov, V. Georgescu, C. Zamfir, and G. Candea, "Selective symbolic execution," in Proceedings of the 5th Workshop on Hot Topics in System Dependability (HotDep), 2009, no. CONF.

[3] R. Baldoni, E. Coppa, D. C. D’elia, C. Demetrescu, and I. Finocchi, "A survey of symbolic execution techniques," ACM Computing Surveys (CSUR), vol. 51, no. 3, pp.

1-39, 2018.

[4] C. Cadar, D. Dunbar, and D. R. Engler, "Klee: unassisted and automatic generation of high-coverage tests for complex systems programs," in OSDI, 2008, vol. 8, pp. 209-224.

[5] Y. Shoshitaishvili et al., "Sok:(state of) the art of war: Offensive techniques in binary analysis," in 2016 IEEE Symposium on Security and Privacy (SP), 2016: IEEE, pp.

138-157.

[6] N. Stephens et al., "Driller: Augmenting fuzzing through selective symbolic execution," in NDSS, 2016, vol. 16, no. 2016, pp. 1-16.

[7] Y. Shoshitaishvili, R. Wang, C. Hauser, C. Kruegel, and G. Vigna,

"Firmalice-Automatic Detection of Authentication Bypass Vulnerabilities in Binary Firmware," in NDSS, 2015, vol. 1, pp. 1.1-8.1.

[8] V. Chipounov, V. Kuznetsov, and G. Candea, "S2E: A platform for in-vivo multi-path analysis of software systems," Acm Sigplan Notices, vol. 46, no. 3, pp. 265-278, 2011.

[9] C. Ramey. "The GNU Bourne-Again SHell."

http://tiswww.case.edu/php/chet/bash/bashtop.html (accessed August, 29, 2021).

[10] E. J. Schwartz, T. Avgerinos, and D. Brumley, "All you ever wanted to know about dynamic taint analysis and forward symbolic execution (but might have been afraid to ask)," in 2010 IEEE symposium on Security and privacy, 2010: IEEE, pp. 317-331.

[11] J. Newsome and D. X. Song, "Dynamic Taint Analysis for Automatic Detection, Analysis, and SignatureGeneration of Exploits on Commodity Software," in NDSS, 2005, vol. 5: Citeseer, pp. 3-4.

[12] R. Corin and F. A. Manzano, "Taint analysis of security code in the KLEE symbolic execution engine," in International Conference on Information and Communications Security, 2012: Springer, pp. 264-275.

[13] K. Sen, D. Marinov, and G. Agha, "CUTE: A concolic unit testing engine for C," ACM SIGSOFT Software Engineering Notes, vol. 30, no. 5, pp. 263-272, 2005.

(35)

27

[14] F. Gritti et al., "Symbion: Interleaving symbolic with concrete execution," in 2020 IEEE Conference on Communications and Network Security (CNS), 2020: IEEE, pp.

1-10.

[15] F. Bellard, "QEMU, a fast and portable dynamic translator," in USENIX annual technical conference, FREENIX Track, 2005, vol. 41: Califor-nia, USA, p. 46.

[16] C. Lattner and V. Adve, "LLVM: A compilation framework for lifelong program analysis & transformation," in International Symposium on Code Generation and Optimization, 2004. CGO 2004., 2004: IEEE, pp. 75-86.

[17] H. Peng, Y. Shoshitaishvili, and M. Payer, "T-Fuzz: fuzzing by program transformation," in 2018 IEEE Symposium on Security and Privacy (SP), 2018: IEEE, pp. 697-710.

參考文獻

相關文件

及清華大學電機系/光電所 博士/碩士班助教群 蔡瑋哲,蘇士祺,劉子齊,林彥州 碩士班. 張宸寧,葉明學,王思婷,廖泓宇

[17] Kuo-Sheng Chin , Liu-Yang Lin , and Jen-Tsai Kuo , “New Formulas for Synthesizing Microstrip Bandpass Filters With Relatively Wide Bandwidths,” IEEE Microwave

國立臺北教育大學教育經營與管理學系設有文教法律碩士班及原住民文

國立高雄師範大學數學教育研究所碩士論文。全國博碩士論文資訊網 全國博碩士論文資訊網 全國博碩士論文資訊網,

隨著科技的進步,展覽場的導覽系統已從過去導遊、磁帶機或 CD 播放 器講解的時代轉換成行動導覽的時代。目前行動導覽方式大都以 RFID 或 QR

The researcher of this study maintained that the junior high school curriculum emphasized too much on plane geometry and should incorporate existing high school curriculum

Stone and Anne Zissu, Using Life Extension-Duration and Life Extension-Convexity to Value Senior Life Settlement Contracts, The Journal of Alternative Investments , Vol.11,

港大學中文系哲學碩士、博士,現 任香港中文大學人間佛教研究中心