周 航 方 勇 黃 誠 劉 亮 陳興剛
1(四川大學電子信息學院 成都 610065)
2(四川大學網(wǎng)絡空間安全學院 成都 610207)
3(成都市計量檢定測試院 成都 610056)
(helloworld@stu.scu.edu.cn)
隨著HTML5的快速發(fā)展,Web應用系統(tǒng)在各個行業(yè)中的應用越來越廣泛,采用PHP開發(fā)的網(wǎng)站更是不計其數(shù).據(jù)2014年相關報告統(tǒng)計,Github上PHP開源項目已經(jīng)接近14萬[1],而這一數(shù)據(jù)仍在不斷增長.PHP作為腳本語言,存在入門簡單、語法靈活、語法不嚴謹?shù)忍攸c.這些特點導致PHP語言開發(fā)的Web系統(tǒng)長期以來遭受網(wǎng)絡攻擊,針對PHP應用的安全研究刻不容緩.
目前針對程序源代碼漏洞檢測方法主要分為2類:動態(tài)檢測技術和靜態(tài)檢測技術.動態(tài)檢測技術可分為主動檢測和被動檢測2種方式:主動檢測利用沙箱環(huán)境,將PHP源代碼逐一在沙箱中運行,通過動態(tài)分析污點的匯聚點分析漏洞類型;被動檢測主要是對用戶行為進行監(jiān)控,例如PHP擴展Taint,當用戶輸入的污染數(shù)據(jù)傳入某些危險函數(shù)時擴展就會發(fā)出警告[2].靜態(tài)分析主要采用了基于數(shù)據(jù)流分析的污點分析技術,對一個變量而言,它本身只有2種狀態(tài):污染狀態(tài)和非污染狀態(tài)[3].污點分析可以抽象為一個三元組〈sources,sinks,sanitizers〉,它的整個過程就是分析程序中污點源引入的數(shù)據(jù)是否不經(jīng)過無害處理而直接進入污點匯聚點[4].相比于動態(tài)檢測,靜態(tài)檢測不需要在運行源代碼的情況下進行分析,有著執(zhí)行速度快、效率高、代碼覆蓋面廣等優(yōu)點[5].
針對Web二階漏洞檢測技術,國內(nèi)外的專家學者作了如下研究:Yan等人[6]采用識別準則的方式對二階SQL注入漏洞進行檢測,該方法對準則庫依賴極強并且準則庫需要人為添加維護,在實際環(huán)境中不可取;田玉杰等人[7]提出了一種基于改進參數(shù)化的二階SQL注入攻擊防御模型,但是該模型的建立是以正常用戶輸入中不允許包含SQL代碼為前提的,誤報率較高且通用性差.Backes等人[8]提出了一種基于語法相似性的方法進行漏洞檢測,該方法針對大規(guī)模漏洞檢測非常有效,但是它對模板代碼有著很高的要求,對特定系統(tǒng)的漏洞檢測十分局限.上述文獻中提到的二階漏洞檢測方法普遍存在依賴規(guī)則、通用性較差的缺點.針對這些問題,本文主要進行了如下研究及工作:
1)研究了二階漏洞的產(chǎn)生原理以及當前針對此類問題的檢測方法,分析了這些方法在進行二階漏洞檢測時的不足.
2)提出了二階漏洞的靜態(tài)檢測方法.在抽象語法樹的基礎上提出了控制流圖的構建方法,利用控制流圖以及語法分析技術重建數(shù)據(jù)庫讀寫操作模型,結合數(shù)據(jù)流分析檢測源碼中可能存在的二階漏洞.
3)基于上述方法實現(xiàn)原型系統(tǒng)CodeAn,并選取Github上PHP開源項目進行漏洞檢測.實驗結果表明:該系統(tǒng)誤報率為9%,低于同類漏洞檢測工具.
在常見的一階漏洞中,污點源通常定義為用戶的輸入[9].污點分析的過程就是分析用戶的輸入在到達敏感函數(shù)之前是否經(jīng)過了適當?shù)膬艋幚?但是如果污點源引入的數(shù)據(jù)不直接進入污點匯聚點而是先存入數(shù)據(jù)庫,當污染的數(shù)據(jù)再次從數(shù)據(jù)庫中取出來并且沒有經(jīng)過適當?shù)膬艋幚砭瓦M入污點匯聚點,此過程就可能會導致新的Web應用漏洞,這類漏洞通常被定義為二階漏洞.針對此類漏洞的污點分析就可以抽象為一個四元組〈sources,database,sinks,santizers〉.
圖1展示了二階漏洞的模型:攻擊者向服務端發(fā)起惡意請求;服務端接收惡意數(shù)據(jù)后存入數(shù)據(jù)庫之中;在程序的運行過程中,數(shù)據(jù)庫中的污染數(shù)據(jù)被取出來并且沒有進行適當?shù)剡^濾就直接進入危險函數(shù),導致Web二階漏洞產(chǎn)生.
圖1 二階漏洞模型
本文以存儲型XSS為例(存儲型XSS可以看作是二階XSS漏洞),介紹二階漏洞的產(chǎn)生原理.圖2為1段存儲用戶輸入數(shù)據(jù)、讀取用戶輸入數(shù)據(jù)并輸出的代碼.在程序的第2行,服務端獲取用戶的數(shù)據(jù)并對數(shù)據(jù)進行SQL注入過濾;第3行將過濾后的數(shù)據(jù)存入數(shù)據(jù)庫中;第5行讀取數(shù)據(jù)庫內(nèi)容,并且不經(jīng)過任何過濾直接將內(nèi)容輸出到頁面.
圖2 二階漏洞代碼示例
在程序執(zhí)行過程中,系統(tǒng)對數(shù)據(jù)進行了addslashes過濾防止SQL注入.在系統(tǒng)取出數(shù)據(jù)之后并沒有進行第2次針對性地過濾,導致XSS跨站腳本漏洞的產(chǎn)生.
用戶需要發(fā)送2次請求就可以造成XSS攻擊,如圖3所示:
圖3 用戶攻擊請求
在分析數(shù)據(jù)庫讀寫操作時,若SELECT語句使用星號查詢所有字段,數(shù)據(jù)流分析時會無法準確定位數(shù)據(jù)庫操作的具體列;其次列本身的數(shù)據(jù)類型和長度可能對數(shù)據(jù)存在隱式凈化.為了提高數(shù)據(jù)流分析的準確率和減少不必要的工作量,提出如下方法進行處理.
遍歷源碼中.sql后綴以及.php后綴的文件,利用正則表達式匹配文件中所有CREATE TABLE的SQL語句.使用語法解析器解析并重建數(shù)據(jù)庫的表結構:包括所有表名、列名、列類型和長度.在MySQL中,字符串之外的數(shù)據(jù)類型都存在隱式凈化,例如:整數(shù)類型Int、時間類型Time等等.針對字符串之外的數(shù)據(jù)類型,不對該列進行數(shù)據(jù)庫讀寫分析;而針對字符串類型,設置長度閾值為10.通常長度小于10的列缺乏構造有效攻擊載荷的條件,也不對其進行數(shù)據(jù)庫讀寫分析.通過處理,得到表1所示的數(shù)據(jù)庫結構信息:
表1 數(shù)據(jù)庫結構信息
二階漏洞模型如圖1所示,由圖1可知漏洞產(chǎn)生的根本原因是數(shù)據(jù)庫中的污染數(shù)據(jù)傳入了敏感函數(shù).本文將PHP中的100多個敏感函數(shù)根據(jù)漏洞類型分為8類,部分信息如表2所示:
表2 敏感函數(shù)及分類
為了分析數(shù)據(jù)在databases→sinks之間的傳播,本文進行了如下研究:
在控制流圖中,函數(shù)調用的語句可以抽象為Expr-FuncCall〈name,args,result〉,其中name表示函數(shù)名,args表示參數(shù),result表示函數(shù)返回值;數(shù)組元素的訪問可以抽象為Expr-ArrayDim-Fetch〈var,dim,result〉,其中var表示數(shù)組名,dim表示數(shù)組鍵名,result表示返回值.
PHP中使用內(nèi)置的query系列函數(shù)獲取數(shù)據(jù)庫資源標識符,為了構建數(shù)據(jù)庫的讀操作模型,利用控制流圖獲取query函數(shù)的參數(shù)args,此參數(shù)為待執(zhí)行的SQL語句.通過語法解析器分析數(shù)據(jù)庫讀操作查詢的相關表名以及字段名.如果存在UNION或者JOIN操作,則可能存在多個表;如果存在別名操作,則需要通過數(shù)據(jù)庫結構信息進行別名映射.PHP中使用內(nèi)置的fetch系列函數(shù)將數(shù)據(jù)庫資源標識符轉換為關聯(lián)數(shù)組或索引數(shù)組.在對數(shù)據(jù)庫查詢結果數(shù)組進行訪問時,若Expr-ArrayDimFetch中的屬性dim為字符串類型,則其值與數(shù)據(jù)庫中的列名一致;若屬性dim為數(shù)字類型,則通過數(shù)據(jù)庫結構信息查找相應的列名.
遍歷控制流圖中的基本塊,獲取基本塊中所有函數(shù)調用語句Expr-FuncCall及其屬性name和args.根據(jù)表2提供的列表,提取敏感函數(shù)調用的相關信息.以敏感函數(shù)所在的控制流圖基本塊為起點進行后向數(shù)據(jù)流分析,對敏感函數(shù)的參數(shù)args構建數(shù)據(jù)依賴關系,標記敏感參數(shù)args到數(shù)據(jù)庫資源標識符的所有有效路徑.
從二階漏洞模型可知,漏洞產(chǎn)生的另外一個原因是用戶輸入的污染數(shù)據(jù)sources存儲進數(shù)據(jù)庫之中.sources點規(guī)則定義如表3所示:
表3 sources列表
為了分析數(shù)據(jù)在sources→databases之間的傳播,本文進行了如下研究:
MySQL中存在3種數(shù)據(jù)庫寫操作語句:INSERT,REPLACE,UPDATE.INSERT和REPLACE用于向數(shù)據(jù)庫中插入數(shù)據(jù),UPDATE用于向數(shù)據(jù)庫中更新數(shù)據(jù).此處對UPDATE語句進行分析,其語法結構如下所示:
在構建數(shù)據(jù)庫寫操作模型時,主要針對表、列以及列輸入變量進行分析.UPDATE語法中的assignment的結構為col-name=value,通常列輸入變量為value.而語法結構中的WHERE子句用于界定數(shù)據(jù)更新的條件,LIMIT用于界定可更新的行數(shù).本文只關注外部數(shù)據(jù)到數(shù)據(jù)庫之間的傳遞,對限定語句不進行研究.
遍歷控制流圖中的基本塊,獲取數(shù)據(jù)庫語句執(zhí)行函數(shù)query的參數(shù)args,此參數(shù)為待執(zhí)行的SQL語句.通過語法解析器進行解析[10]提取數(shù)據(jù)庫寫操作的表、列以及輸入變量,結合數(shù)據(jù)庫結構得到表4所示的數(shù)據(jù)庫寫操作模型.而針對存在隱式凈化的列字段,不對其相應變量進行下一步的數(shù)據(jù)依賴關系分析.
表4 數(shù)據(jù)庫寫操作模型
以列的輸入變量所在控制流圖基本塊為起點進行后向數(shù)據(jù)流分析,對輸入變量構建數(shù)據(jù)依賴關系.在依賴關系中,依賴變量來自表3中的sources列表,則標記一條有效路徑并結束當前變量的分析,直到所有變量的路徑標記完畢.
控制流圖[11](control flow graph,CFG)也稱控制流程圖,由圖形符號表示程序在執(zhí)行期間可能通過的所有執(zhí)行路徑.控制流圖可通過遍歷AST節(jié)點,利用控制節(jié)點分割基本塊得到.PHP中控制節(jié)點及其分類如圖4所示,構建方法如過程1所示.
圖4 用戶攻擊請求
過程1.CFG生成過程.
1)遍歷AST節(jié)點;
2)如果節(jié)點屬于STMT-Jump,即為每個分支建立新的基本塊,并且將新的基本塊用有向邊連接到前一個基本塊,跳轉條件被添加到有向邊上;
3)如果節(jié)點屬于STMT-Loop,即建立一個新的基本塊,在數(shù)據(jù)流分析期間對循環(huán)條件進行分析;
4)如果節(jié)點屬于STMT-Stop或STMT-Return,則停止解析;
5)一旦創(chuàng)建新的基本塊,即對基本塊進行數(shù)據(jù)流模擬并創(chuàng)建塊摘要;
6)所有AST節(jié)點遍歷結束之后停止本過程.
數(shù)據(jù)流分析以控制流圖中的基本塊為最小單位,在控制流圖的構建過程中模擬每個基本塊的數(shù)據(jù)流.
最常見的數(shù)據(jù)依賴[12]情況就是賦值運算.如果變量$x的取值決定于$y,那么就可以認為$x依賴于$y.在分析的過程中,對每個基本塊的變量進行搜集,構建數(shù)據(jù)依賴關系.
但是PHP中允許使用多個變量指向同一個內(nèi)容[13],這種關系稱為引用.如果存在引用關系,則可能導致分析存在缺陷.因此在基本塊的數(shù)據(jù)流模擬時,將所有引用關系指向保存的一個引用結構中.
數(shù)據(jù)流分析的關鍵就在于為每個數(shù)據(jù)匯聚點構建數(shù)據(jù)依賴圖,由于當前塊中數(shù)據(jù)只依賴于之前基本塊中的數(shù)據(jù)[14],在控制流圖的基礎上使用后向的數(shù)據(jù)流分析方法:循環(huán)遍歷當前基本塊的所有入口邊緣,并在每個數(shù)據(jù)塊摘要的屬性中查找污點變量的名稱.如果找到匹配項,則通過依賴分析以及引用分析將變量替換為對應的依賴變量,并復制所有污點標記以及凈化標記.最后通過鏈接到基本塊的所有入口邊緣繼續(xù)跟蹤,直到標記出所有的路徑.數(shù)據(jù)依賴圖示例如圖5所示:
圖5 數(shù)據(jù)依賴圖
在數(shù)據(jù)流分析的過程中,內(nèi)置函數(shù)對數(shù)據(jù)的處理會改變其原有的污點屬性[15].本文把內(nèi)置的凈化函數(shù)分為4類:編解碼類、安全類、散列類、強制轉換類.
編解碼類:例如base64-decode,base64-encode等,在進行污點分析的過程中,數(shù)據(jù)經(jīng)過編碼函數(shù)處理之后則去除污點標記,經(jīng)過解碼函數(shù)處理之后恢復原有污點標記.
安全類:例如addslashes,stripslashes等,在數(shù)據(jù)流的分析過程中,數(shù)據(jù)經(jīng)過前者處理之后去除對應的污點標記,經(jīng)過后者處理之后恢復對應的污點標記.
散列類:例如md5等,數(shù)據(jù)經(jīng)過此類函數(shù)處理之后,污染源的所有污點屬性被清除.
強制轉換類:例如intval等,與散列類函數(shù)一樣,去除所有污點屬性.
本文提出了一種針對PHP源代碼Web二階漏洞的檢測模型,系統(tǒng)整體框架如圖6所示.系統(tǒng)第1部分使用語法解析器對PHP源碼進行預處理,讀取源碼并轉換為token序列,然后通過語法規(guī)則將token序列轉換為AST.第2部分遍歷抽象語法樹節(jié)點,并利用上文提到的方法構建程序控制流圖:利用控制節(jié)點將源碼分割成單獨的基本塊,并在基本塊中進行數(shù)據(jù)流模擬,并提取基本塊的塊摘要.第3部分以數(shù)據(jù)庫為中心,對其讀寫操作進行建模:利用正則表達式提取PHP應用中創(chuàng)建表的SQL語句,通過語法分析構建數(shù)據(jù)庫結構信息.在抽象語法樹和控制流圖的基礎上重構SQL執(zhí)行語句,對數(shù)據(jù)庫讀寫操作模型進行重建.對于數(shù)據(jù)庫的讀寫分析分為2部分:databases→sinks以及sources→databases之間的數(shù)據(jù)流傳播.本文利用后向數(shù)據(jù)流分析技術對敏感變量構建數(shù)據(jù)依賴圖,標記所有的有效路徑.在敏感函數(shù)和內(nèi)置凈化函數(shù)的基礎上分析可能存在的二階漏洞.
為了驗證理論的可行性及有效性,本文實現(xiàn)了原型系統(tǒng)CodeAn.選擇了Github上10個PHP開源項目進行性能分析.實驗環(huán)境如表5所示,測試采用了誤報率以及總耗時2個關鍵要素進行評估.實驗步驟如下:
圖6 系統(tǒng)框架圖
1)選取Github上10個PHP開源項目,分別選取某一版本作為檢測對象并統(tǒng)計其公開的二階漏洞.
2)搭建原型系統(tǒng)CodeAn,分別使用常見漏洞檢測工具Fortify,RIPS,CodeAn對PHP開源項目進行漏洞檢測.
3)從檢測漏洞數(shù)、總耗時、誤報率3個方面對檢測結果進行統(tǒng)計,得到實驗結果.
實驗結果如表5所示,RIPS檢測漏洞數(shù)23,誤報率為17%,總耗時3 733 s;Fortify檢測漏洞數(shù)31,誤報率為23%,總耗時4 033 s;CodeAn檢測漏洞數(shù)28,誤報率為9%,總耗時2550s.通過分析發(fā)現(xiàn),Fortify和RIPS產(chǎn)生的誤報事件都集中在2個方面:一方面是未考慮數(shù)據(jù)庫中字段類型以及長度對數(shù)據(jù)產(chǎn)生的隱式凈化;另一方面是在數(shù)據(jù)流分析的過程中,沒有考慮解碼函數(shù)以及散列函數(shù)對數(shù)據(jù)產(chǎn)生的影響,而前者會恢復數(shù)據(jù)的污點標記,后者會去除數(shù)據(jù)的污點標記.
相比Fortify和RIPS而言,本系統(tǒng)有著更低誤報率和更快的響應時間.
表5 實驗結果
本文闡述了二階漏洞的產(chǎn)生原理并提出了針對此類漏洞的檢測方法:利用控制流圖和語法分析技術對數(shù)據(jù)庫讀寫操作進行建模,以數(shù)據(jù)庫為中心進行數(shù)據(jù)流分析.實驗結果表明,文中提到的二階漏洞檢測方法和常見工具相比,誤報率更低,耗時更短.
本文主要針對面向過程的PHP應用程序,針對面向對象的PHP應用程序檢測效果不佳.下階段將針對此方向進行更深入的研究.
[1]Zapponi C.Programming languages and Git Hub[J/OL].[2017-11-10].http://githut.info/
[2]Nguyen-Tuong A,Guarnieri S,Greene D,et al.Automatically hardening Web applications using precise tainting[C]//Porc of Int Federation for Information Processing.Berlin:Springer,2005:295-307
[3]霍志鵬.基于靜態(tài)分析的PHP代碼缺陷檢測[D].北京:北京郵電大學,2015
[4]王蕾,李豐,李煉,等.污點分析技術的原理和實踐應用[J].軟件學報,2017,28(4):860-882
[5]王耀輝,王丹,付利華.面向PHP程序的SQL漏洞檢測系統(tǒng)[J].計算機工程,2016,42(4):112-118
[6]Yan L,Li X,Feng R,et al.Detection method of the second-order SQL injection in Web applications[G]//LNCS 8332:Proc of Int Workshop on Structured Object-Oriented Formal Language and Method.Berlin:Springer,2013:154-165
[7]田玉杰,趙澤茂,張海川,等.二階SQL注入攻擊防御模型[J].信息網(wǎng)絡安全,2014(11):70-73
[8]Backes M,Rieck K,Skoruppa M,et al.Efficient and flexible discovery of PHP application vulnerabilities[C]//Proc of IEEE European Symp on Security and Privacy.Piscataway,NJ:IEEE,2017:334-349
[9]Papagiannis I,Migliavacca M,Pietzuch P.PHP aspis:Using partial taint tracking to protect against injection attacks[C]//Proc of USENIX Conf on Web Application Development.Berkeley:USENIX Association,2011:2- 2
[10]Cao D,Bai D.Design and implementation for SQL parser based on ANTLR[C]//Proc of Int Conf on Computer Engineering and Technology.Piscataway,NJ:IEEE,2010:V4-276-V4-279
[11]夏玉輝,張威,萬琳,等.一種基于控制流圖的靜態(tài)測試方法[C]//全國軟件測試會議與移動計算、柵格、智能化高級論壇會議錄.武漢:中國計算機學會容錯計算專業(yè)委員會,2009
[12]聶世超.PHP程序靜態(tài)分析系統(tǒng)的設計與實現(xiàn)[D].長春:吉林大學,2011
[13]The PHP Group.References explained[EB/OL].[2017-11-10].http://php.net/manual/zh/language.references.php
[14]Xie Y,Aiken A.Static detection of security vulnerabilities in scripting languages[C]//Proc of USENIX Security Symp.Berkeley:USENIX Association,2006:179-192
[15]Ouni A,Kessentini M,Inoue K,et al.Search-based Web service antipatterns detection[J].IEEE Trans on Services Computing,2015,10(4):603-617