谷俊 鮮明 杜瑞祥 陳恬
[摘要]代碼重用漏洞利用技術是突破DEP和W⊕X的主流技術,其靈巧的攻擊思想是現(xiàn)行漏洞利用技術的重要方向。因此研究基于代碼重用漏洞利用技術及其防御方法,對提升程序安全和系統(tǒng)安全有著重要意義。論文將闡述基于代碼重用的攻擊原理和主要方法以及各種方法的優(yōu)缺點和約束條件,總結當前主流防御技術的優(yōu)缺點,并對下一步研究工作提出展望。
[關鍵詞]代碼重用;W⊕X;數(shù)據(jù)執(zhí)行保護;ROP Android
[中圖分類號]TN926-34;TP311 [文獻標識碼]A
1 引言
一直以來緩沖溢出漏洞對計算機網絡安全造成巨大的威脅,每年都有數(shù)目眾多的緩沖溢出漏洞被發(fā)現(xiàn)。攻擊者不停地嘗試利用系統(tǒng)的這些漏洞對程序進行攻擊。早期的緩沖溢出漏洞利用都是向堆棧中注入惡意代碼,劫持正常的程序控制流程,將程序跳轉到自己預設的Shellcode,進而執(zhí)行惡意代碼,完成攻擊。
后來,針對緩沖溢出漏洞利用方法的特點,出現(xiàn)了相應的防護技術。包括Solar Designers Stack Patch,通過棧不可執(zhí)行。防止代碼注入攻擊:另外類似的還有DEP技術和W⊕X技術;通過硬件或軟件的支持,防止注入數(shù)據(jù)被執(zhí)行,保證內存區(qū)域不能既可執(zhí)行又可寫入。Linux PAX項目中,已經實現(xiàn)了W⊕X技術,通過將不需要執(zhí)行的頁設為不可執(zhí)行,限制可寫頁和可執(zhí)行頁的轉換,防止程序動態(tài)生成和執(zhí)行代碼:另外對需要動態(tài)生成代碼的程序,PAX提供了解除限制的方法;同時Pax技術使得堆棧上的數(shù)據(jù)不可執(zhí)行,并且對elf文件中的段進行限制,只允許實際的代碼段執(zhí)行,有效地防御了改寫GOT表等攻擊。在Windows XP sp2以上的系統(tǒng)中都應用了類似的DEP技術。
2 基于代碼重用的漏洞利用
新的防御技術有效地限制了代碼注入攻擊,傳統(tǒng)的代碼注入攻擊幾乎不能成功。攻擊者們進而研究新的方法?;诖a重用的漏洞利用不需要執(zhí)行注入的數(shù)據(jù),而是利用程序中已有的合法函數(shù)或者指令片段進行組合,實現(xiàn)特定功能?;诖a重用的漏洞利用被認為是能有效突破DEP和W⊕X的技術,它所需要的條件是:(1)存在能夠控制棧區(qū)的緩沖溢出漏洞;(2)程序已有代碼和指令的位置可以被找到。
比較流行的基于代碼重用的漏洞利用方法主要五種。
2.1 Return-to-libc
Retum-to-libc通過棧溢出,把棧幀中的返回地址覆蓋為一些關鍵函數(shù)的地址,并在棧中寫入系統(tǒng)關鍵函數(shù)的參數(shù)。這樣,不需要在棧上寫Shellcode,就實現(xiàn)了溢出攻擊。因為該攻擊方法主要利用的是libc庫的一些關鍵函數(shù),故被稱作Return-to-libc。Libc庫為攻擊者提供了相當多重要功能的函數(shù),如system()、exec()等函數(shù)可以直接執(zhí)行某個程序或者指令,使構造攻擊更加簡單。AttackLab中,介紹了Retum-to-libc的簡單實驗,在Nergal的文章中作者介紹了在應用了Pax技術的系統(tǒng)中實現(xiàn)Retum-to-libc的方法。該攻擊方法一開始被認為不是圖靈完全的。2011年由Minh Trall實現(xiàn)一種Return-into-libc攻擊,并證明該攻擊時圖靈完全的。
然而,Rentum-to-libc仍然具有一些缺陷:(1)Retum-to-libc的功能依賴于系統(tǒng)中存在的庫函數(shù),如果將這些特定的函數(shù)進行修改或移除,Retum-to-libc可以構造攻擊的能力受到嚴重限制;(2)Retum-to-libc只能順序調用庫函數(shù),將函數(shù)的功能進行串聯(lián),它不能實現(xiàn)如分支操作、循環(huán)操作等諸多功能。
2.2 Return-Oriented Programming(ROP)
針對Retum-to-libc攻擊的不足,ROP不調用系統(tǒng)庫中已有的函數(shù),而是把程序中已有的以Ret結尾的短指令片段(一般不超過5條指令)進行再組合,這些被利用的指令片段被稱為Gadget。ROP攻擊通過溢出,將Gadget的地址預先注入到棧中,然后劫持控制流,將程序執(zhí)行流轉向第一個ROP Gadget,當?shù)谝粋€ROP Gadget執(zhí)行完畢后,利用Ret指令的特性,跳轉到棧頂所指向的下一個Gadget。這樣依次重復,可以將多個Gadget串聯(lián)執(zhí)行,以實現(xiàn)特定的功能。Shacham在X86架構的系統(tǒng)中成功實現(xiàn)了ROP攻擊,隨即該技術被擴展到其他多種架構。如SPARC、Atmel AVR、PowerPC、Z80、ARM架構和Harvard架構平臺,如Sequoia的AVCAdvantage投票機器和蘋果公司的iPhone系列移動操作系統(tǒng),而Harvard平臺是被認為對傳統(tǒng)的代碼注入攻擊免疫的平臺。在早期的攻擊構造中,攻擊者大多數(shù)使用手工的方法來組織Gadget構造攻擊。后來,研究人員將這種攻擊的構造的各個階段進行自動化操作,將這種攻擊變得更加實用。研究人員同時證明了ROP可以被應用于Rootkit攻擊,通過復用內核中的代碼,攻擊者可以成功的隱藏進程。Bittau等實現(xiàn)了一種ROP變種攻擊(BROP),利用ROP控制棧參數(shù),執(zhí)行系統(tǒng)調用。Schuster實現(xiàn)了另一種ROP變種攻擊(COOP),能夠很好地利用C++編寫的面向對象代碼進行攻擊。
由于ROP攻擊是利用Ret指令在Gadget之間跳轉,有很明顯的特征,很容易被檢測到,同時這些Ret指令沒有對應的Call指令,也可以通過檢測Call-ret指令組合發(fā)現(xiàn)這類攻擊。
2.3 Pop-jmp
Pop-jmp對ROP進行改進,為了消除ROP攻擊的特征,Checkoway提出Pop-jmp攻擊方法,它利用Pop給寄存器賦值,然后通過Jmp跳轉到寄存器所指向的位置,它與Rop攻擊區(qū)別不大。Ret指令語義上就等于Pop Eip和Jmp Eip兩條指令連續(xù)調用。在文提出一種利用類Ret指令作為“指令蹦床”,使每個Gadget的Jmp指令先跳轉到“指令蹦床”,然后通過“指令蹦床”跳轉到下一Gadget。其原理如圖1所示。
其具體步聚:(1)通過棧溢出將返回地址EIP覆蓋為“指令蹦床”的地址;(2)通過“ebx賦值gadget”的popebx給ebx賦值為“指令蹦床”的地址;(3)通過“jmp ebx”跳轉到“指令蹦床”;(4)用“指令蹦床”跳轉到相應的Gadget;(5)Gadget執(zhí)行完跳轉至“指令蹦床”。
第4、5步循環(huán)跳轉,完成攻擊。從其攻擊原理可以看出,Pop-jmp雖然消除了Ret指令特征,但產生了新的Pop_jnlp指令特征;而“指令蹦床”限制了可用的寄存器和Gadget,而且每次跳轉到“指令蹦床”,容易被檢測。
2.4 Jump-Oriented-Programming(JOP)和Branch Instruction-Oriented Programming(BIOP)
為了克服ROP和Pop-jmp的一些缺陷,TylerBletsch在文章提出JOP攻擊。Pop-jmp攻擊相比,它不限于用Esp引用Gadget地址,也不依靠Ret指令以及Pop-jmp指令進行Gadget串聯(lián)。其攻擊如圖2所示,用Gadget分配表(Dispateh Table)存放數(shù)據(jù)和地址,每次Gadget執(zhí)行完跳轉到分配器。分配器通過對棧地址的加減,間接尋址下一個Gadget,這樣棧地址相當于一個程序計數(shù)器。其優(yōu)點是對棧的引用更加靈活,經過精心設計,可以利用棧中任意內存。
但是該方法存在兩個缺點:與JOP攻擊一樣,Gadget分配器存在寄存器依賴性,使JOP功能受限;二是,難以找到gadget分配器。
文章提出的BIOP,對JOP改進并實現(xiàn)自動化攻擊構造。它繼承了JOP不依賴棧的控制流跳轉,而且尋找一類同時含有Call,Ret聯(lián)合Gadget,聯(lián)合Gadget通過Call結尾的Gadget調用一個以Ret結尾的Gadget,使Gadget中的Call指令有對應的Ret指令。這種攻擊不依賴棧的控制,而是依賴寄存器,每次跳轉之前要給寄存器賦上正確的值,Gadget之間存在約束關系。
2.5 Sigreturn Oriented Programming(SROP)
Erik Bosman和Herbert Bos提出了SROP攻擊方法,SROP攻擊利用Sigreturn系統(tǒng)調用進行構造,該系統(tǒng)調用在Unix和Linux系統(tǒng)發(fā)送Signal的時候會被間接地調用。當內核向某個進程發(fā)起一個Signal,該進程會被暫時掛起(suspend),進入內核,然后內核為該進程保存相應的上下文,并跳轉到之前注冊好的SignalHandler中處理相應Signal,當Signal Handler返回之后,內核為該進程恢復之前保存的上下文,最后恢復進程的執(zhí)行。上下文數(shù)據(jù)就保存在被掛起進程的棧上,這些數(shù)據(jù)幀被稱為Signal Frame,Signal Frame被保存在用戶進程的地址空間中的,是用戶進程可讀寫的:從Sigreturn調用返回時,系統(tǒng)不對Signal Frame進行檢查。攻擊者可以偽造Signal Frame幀,發(fā)起Sigretum調用。將幀的關鍵數(shù)據(jù)精心設計,當調用返回時,就可以得到程序的控制流。通過連續(xù)的構造Signal Frame,可以發(fā)起多個系統(tǒng)調用,實現(xiàn)特定功能。這種方法簡化了攻擊流程,需要的先決條件也較少,沒有Gadget的副作用,暫時沒有出現(xiàn)專門的防御工具。
3 基于代碼重用的漏洞利用的防御技術
隨著基于基于代碼重用的漏洞利用技術發(fā)展,其防御方法也隨之產生。
3.1 基于控制流的防御方法
通過抑制非正常控制流以達到防止基于代碼重用的漏洞利用?;诖a重用的漏洞利用本質是劫持控制流,只要保證控制流的正確和完整,就可以有效抑制基于代碼重用的漏洞利用。Abadi、Zhang M實現(xiàn)了根據(jù)Control How Graph(CFG)檢查控制流的方法,Davi設計了一種基于硬件的控制流檢查方法,對Call、Ret、Jmp指令。CFG的生成能夠確保程序按照正確的流程執(zhí)行,但是動態(tài)生成CFG圖很復雜而耗時,且難以防御COOPt=]攻擊?;诳刂屏鞯姆烙捎贑GF的不完善性還難以實用。
Cowan引入金絲雀方法(canary)檢查控制流,該方法在返回地址附近預制一個Canary值,每次返回前檢查Canary值是否被更改。它一定程度上能夠保護棧的完整性,防止程序棧遭受攻擊,進而保護程序控制流。但是Canary方法也不能完全保證控制流的完整和正確。Scut中,作者通過格式化字符串漏洞突破了Canary保護,BROO同樣可以突破Canary。
由于性能、靈活度、算法復雜度、實現(xiàn)難度等各方面的考量,控制流的完整性檢查還很不完善。
3.2 地址空間布局隨機化(ASLR)
要完成基于代碼重用的漏洞利用,必須先獲取Gadget或者關鍵函數(shù)的地址。因此,Gadget和關鍵函數(shù)的實際首地址將決定程序的控制流,如果我們能夠每次都隨機加載程序庫,程序庫每次加載的起始地址隨機化,讓Gadget和關鍵函數(shù)的控制流程和地址失效。因此,ASLR將增加代碼重用的難度。Shacham描述了針對ASLR機制的基于代碼重用的漏洞利用方法和實際效果,并介紹了在32位機器上應對ASLR問題的方法。Bryant、Seacord等,通過空雪橇操作在應用了ASLR的系統(tǒng)中定位地址,Bittau通過每次猜測一個字節(jié),縮短暴力破解ASLR的周期。在32位機器上,目前地址隨機化的位數(shù)較少,地址可以很快通過很多方法定位,不能完全阻止基于代碼重用的漏洞利用。但會增加攻擊者的難度;在64位機器上的地址隨機化將使Gadget的定位變得十分困難,基于代碼重用的漏洞利用會受到很大影響。因此向64位機器的遷移將大幅提高漏洞利用的難度,同時32位機器上的精細的隨機化,將提高漏洞利用的難度,但需要同其他方法相結合才能保證程序的相對的安全性。
在當前的粗粒度的隨機化的實施方案中,對代碼段整體的起始地址進行了隨機化。而這樣的隨機化有兩個問題,首先,隨機化的地址空間范圍有限,在32位的機器中,有效的隨機化空間只有216,因而其隨機地址范圍很小;其次,由于是整塊的隨機化,因而只要獲取代碼中的一個有效地址,就能計算推測出所有的指令序列的地址。另一方面,基于代碼重用的漏洞利用更關注Gadget的地址,即Ret或Jmp序列之前一定長度之前的指令序列,而其它部分的指令序列,由于指令副作用等原因并不關注。因而,對構建有效的Gadget段序列的隨機化更為重要,對于段序列的隨機化更能提高程序的安全性,抑制基于代碼重用的漏洞利用。
3.3 基于編譯階段的防護
基于編譯階段的防護通過修改編譯器,在編譯階段消除能夠被攻擊者惡意使用的指令序列和函數(shù),如減少ret,jmp等指令,在庫中消除類似system、execv等關鍵函數(shù)。目前其關注于修改編譯器生成指令的偏好,盡量消除非必要的控制流指令,增加對必須的控制流指令的監(jiān)護。Jinku Li提出分析ret指令來源,針對每一種情形分別處理,消除被曲解的ret指令,對于正常的ret指令,其使用間接返回(Return Indirection)的策略,即將可能被篡改的返回地址抽取出來,放在一個單獨的表中,而在棧中原來的位置存放該地址在表中的索引,每次返回時,通過該索引去獲取實際的返回地址,再將有效地保護返回地址,防止程序流程被篡改。
但是,該方法需要重寫編譯器,需要重新編譯原有代碼,對于龐大的遺留代碼很難有效,同時會帶來巨大的負載開銷。
3.4 基于動態(tài)插樁的防護
基于動態(tài)插樁工具(Dynamic BinaryIndtrumentation,DBI)的方法,通過動態(tài)插樁工具提供的程序執(zhí)行時狀態(tài)信息,基于函數(shù)回調機制,引入動態(tài)的監(jiān)控和判定條件,進而判定程序的合法狀態(tài)。防止對目標代碼段的斷章取義,進而阻止非法重用二進制代碼。Davi基于DBI實現(xiàn)了代碼重用防護,通過DBI提供的動態(tài)信息,使Shadow Stack保護函數(shù)的返回值不會被篡改,因而能有效防止傳統(tǒng)基于代碼重用的漏洞利用。黃志軍等引入黃志軍等引入DBI技術。檢查函數(shù)返回地址,防止惡意使用庫代碼。但DBI工具性能不足,以及DBI工具的平臺局限性,難以推廣。
在DBI方法的基礎上,出現(xiàn)了統(tǒng)計學的分析法,通過剖析被重用的Gadget。統(tǒng)計不同的指令的頻率。在Chen中,通過ret指令序列的長度及其連續(xù)出現(xiàn)的頻率來識別ROP攻擊。能夠一定程度上識別傳統(tǒng)ROP攻擊。但是對于不依賴Ret及類Ret指令的攻擊不適用。而且對于部分特別的攻擊序列,這樣的統(tǒng)計規(guī)律不一定成立。與此同時,在缺乏大量攻擊樣本的前提下,很難得出—個準確的統(tǒng)計學規(guī)律。
4 發(fā)展與展望
隨著防御技術的提高,基于代碼重用的漏洞利用難度也在增加,但是其仍有很大的利用空間。各個操作系統(tǒng)中仍有很多庫和代碼沒有應用ASLR機制,我們可以在這些庫和代碼中尋找Gadget,我們構造利用代碼時不必局限于某一個庫,提高攻擊的靈活性。如果把自動構造應用其中,自動探測尋找未應用ASLR的代碼和庫,將提高漏洞利用的成功率和實用性。
而在防護方面,基于上面四種防護技術,進行軟硬件結合的控制流完整性和正確性保護,以及細粒度的ASLR技術研究是很有必要的,但是要注意均衡防護技術與被保護程序運行效率的關系,減少對效率的損耗。
5 結束語
本文描述了現(xiàn)有流行的基于代碼重用的漏洞利用方法以及防御方法,總結了各自優(yōu)缺點。隨著各種代碼重用防御技術的發(fā)展,基于代碼重用的漏洞利用的難度也越來越大。但是在圖靈模型下不能從根本消滅基于代碼重用的漏洞利用。最新出現(xiàn)的SROP,還沒有出現(xiàn)有效的防御方法,下一步我們將設計并實現(xiàn)一種SROP防御方法。