文/Yue CHEN
會找漏洞的時光機:Pinpointing Vulnerabilities
文/Yue CHEN
當我們的系統(tǒng)遭受攻擊時,即便我們已經(jīng)檢測到攻擊,如何知道被利用的漏洞在哪里呢?
先讓我們來看一個簡單的例子(圖1):假如用戶輸入的argv[ ]是個很長的字符串,由于strcpy不限制拷貝的字符數(shù),buf會被溢出,那么在第6行函數(shù)return時候,很可能會控制流異常。假如使用攻擊檢測,很可能檢測到第6行的return 0,但是真正的漏洞在第4行。癥狀(Symptom)和根本原因(Root Cause)在不同的地方。對于復雜的大程序,想要定位到Root Cause還是非常困難的。
圖1
目前基于memory instrumentation的漏洞檢測,由于要instrument所有的內(nèi)存訪問,其開銷特別大,因此不適合用于程序運行時使用。所以這篇論文提出個系統(tǒng)叫Ravel (Root-cause Analysis of Vulnerabilities from Exploitation Log), 它包含一個online模塊和一個offline模塊. Online的模塊把運行的不確定事件都記錄(Record)下來,并且提供攻擊檢測功能;Offline的模塊可以重放(Replay)程序的運行,并且可以instrument memory并且定位漏洞。
這樣做有以下優(yōu)勢:
1. 可以把真實世界里的攻擊,在實驗室環(huán)境進行重放(Replay)并分析。
2. 運行時候性能開銷很小,開銷大的漏洞定位階段被放在了Offline的實驗室里。
3. 可擴展??梢宰杂商砑有碌墓魴z測和漏洞定位方法。
對于攻擊檢測,Ravel用了現(xiàn)有的方法,比如程序崩潰,異常系統(tǒng)調(diào)用,CFI等。 對于Record amp; Replay, Ravel主要記錄了不確定事件,比如系統(tǒng)調(diào)用(syscall)結(jié)果,內(nèi)核到用戶空間的數(shù)據(jù)拷貝,同步原語等。
對于Replay階段的Memory Instrumentation,Ravel集成了二進制翻譯引擎(Binary Translation Engine,簡稱BT)。其中很重要的功能 (也是一項挑戰(zhàn)) , 是可以把BT發(fā)出的syscall和目標程序本身的syscall區(qū)分開來,以確保replay和record的一致性。
對于漏洞定位,Ravel設(shè)計了一系列功能。首先是數(shù)據(jù)流分析(Data-flow Analysis)。寫入一塊內(nèi)存叫做define(簡稱def),把從這塊內(nèi)存里讀出數(shù)據(jù)叫use。假如指令A寫入這塊內(nèi)存,指令B接著讀了出來,它們就構(gòu)成了一組def-use關(guān)系。一堆這種關(guān)系可以構(gòu)成一張圖,叫DFG (Data-flow Graph)。
我們可以預先把這些關(guān)系找出來,做一張DFG。假如運行時候有之前沒見過的def-use關(guān)系出現(xiàn),可以視為發(fā)現(xiàn) 違規(guī)(violation),意味著很可能有漏洞。那么如何知道出問題的地方是在def,還是在use呢?
圖2
圖3
Ravel用了一些啟發(fā)式搜索(heuristics)。這里用buffer overflow舉個例子。
比如我們本來有三個use (也就是read from memory),如圖2所示。然后有一個大的def (write to memory) 把這三個use都覆蓋了,如圖3所示。假如發(fā)現(xiàn)這些def-use關(guān)系是violation,那么很有可能,漏洞在def的指令及其周圍。并且很有可能是buffer overflow, memory overwriting之類的。Violation關(guān)系如圖4所示。別的漏洞,如information leakage,也可以用類似的方法來定位。
圖4
對于整數(shù)錯誤(Integer Errors), Ravel關(guān)注的是一些用整數(shù)計數(shù)(比如放在RCX/ECX寄存器里)的指令,比如MOVS, STOS 等; 和有整數(shù)參數(shù)的函數(shù),比如memcpy, recvfrom 等。從這些參數(shù)開始,Ravel進行backwards search來定位漏洞。
可以定位的整數(shù)錯誤漏洞包括:
Assignment Truncation (比 如0x12345678 → 0x5678)
檢測方法:從longer type賦值到shorter type
Integer Overflow/underflow (比如0xFFFFFFFF + 1)
檢測方法:檢測RFLAGS/EFLAGS寄存器
Signedness Error (比如 unsigned_int_var = signed_int_var)
檢測方法:收集Hint。比如一些指令或者函數(shù)會指定特定的signed或者unsigned參數(shù)。詳情參見slides或者paper.
那么有些整數(shù)錯誤是程序員/編譯器故意設(shè)置的,如何區(qū)分呢?
由于這些錯誤已經(jīng)和reported的漏洞相關(guān),所以非常大可能是漏洞,而不是正常的整數(shù)操作。
假如Race Condition存在,replay的execution trace會和record下來的不一樣,所以可以用該方法來檢測。
一旦檢測到,Ravel繼續(xù)用happens-before relation來進一步嘗試定位漏洞。
圖5
Ravel還能檢測以下一系列漏洞,此處不再贅述:
Use-after-free and Double-free
Buffer Overflow
Integer Errors
Information Leakage
Format String Vulnerabilities
Ravel的Record amp; Replay功能基于FreeBSD 10.2實現(xiàn),漏洞定位基于Valgrind實現(xiàn)。
圖5用Nginx的CVE-2013-2028 漏洞舉了一個Ravel如何從攻擊定位到漏洞的例子, 具體描述參見論文(論文鏈接: http://ww2.cs.fsu.edu/~ychen/paper/ravel.pdf)。
更多的Evaluation實驗, 比如Heartbleed,以及別的漏洞類型比如Null Pointer Dereference,Heap Overflow,Out-of-bounds Read,Untrusted Pointer Dereference,也可以在論文里找到。
圖6
圖6 是Online Performance Overhead的Evaluation, 實驗是在流行的Web服務(wù)器和SPEC CPU 2006上做的,可以看出性能開銷非常小。
(責編:楊潔)
(作者單位為佛羅里達州立大學)