由于博客實(shí)在沒(méi)甚么可以更新的了,我就把目前做的事情總結(jié)1下,當(dāng)作1篇博客,主要是談1談項(xiàng)目中所應(yīng)用的1些技術(shù)。目前市面上有很多PHP的自動(dòng)化審計(jì)工具,開(kāi)源的有RIPS、Pixy,商業(yè)版本的有Fortify。RIPS現(xiàn)在只有初版,由于不支持PHP面向?qū)ο蠓治觯袁F(xiàn)在來(lái)看效果不是太理想。Pixy是基于數(shù)據(jù)流分析的工具,但是只支持PHP4。而Fortify是商業(yè)版本,由于這個(gè)限制,對(duì)它的研究也就無(wú)從談起。國(guó)內(nèi)對(duì)PHP自動(dòng)審計(jì)的研究1般都是公司在做,目前有些工具大多數(shù)使用簡(jiǎn)單的token流分析或直接粗魯1些,使用正則表達(dá)式來(lái)匹配,效果會(huì)很1般。
今天所要談的技術(shù)是基于靜態(tài)分析的1種PHP自動(dòng)化審計(jì)的實(shí)現(xiàn)思路,也是我的項(xiàng)目中的思路。為了進(jìn)行更加有效的變量根據(jù)和污點(diǎn)分析,和很好的應(yīng)對(duì)PHP腳本中的各種靈活的語(yǔ)法表示,正則表達(dá)式效果肯定是不理想的,我所介紹的思路是基于代碼靜態(tài)分析技術(shù)和數(shù)據(jù)流分析技術(shù)的審計(jì)。
首先,我認(rèn)為1個(gè)有效審計(jì)工具最少包括以下的模塊:
1、編譯前端模塊
編譯前端模塊主要應(yīng)用編譯技術(shù)中的抽象語(yǔ)法樹(shù)構(gòu)建、控制流圖構(gòu)建方法,將源碼文件轉(zhuǎn)為合適后端靜態(tài)分析的情勢(shì)。
2、全局信息搜集模塊
該模塊主要用于對(duì)分析的源碼文件進(jìn)行統(tǒng)1的信息搜集,比如搜集該審計(jì)工程中有多少類的定義,并對(duì)類中的方法名、參數(shù)、和方法定義代碼塊的起始和終止的行號(hào)進(jìn)行搜集,用于加快后續(xù)的靜態(tài)分析的速度。
3、數(shù)據(jù)流分析模塊
該模塊不同于編譯技術(shù)中的數(shù)據(jù)流分析算法,在項(xiàng)目中更重視對(duì)PHP語(yǔ)言本身特性的處理。當(dāng)系統(tǒng)的進(jìn)程間和進(jìn)程內(nèi)分析進(jìn)程中發(fā)現(xiàn)了敏感函數(shù)的調(diào)用,則對(duì)該函數(shù)中敏感的參數(shù)進(jìn)行數(shù)據(jù)流分析,即跟蹤該變量的具體變化,為后續(xù)污點(diǎn)分析做準(zhǔn)備。
4、漏洞代碼分析模塊
該模塊基于數(shù)據(jù)流分析模塊搜集的全局變量、賦值語(yǔ)句等信息,進(jìn)行污點(diǎn)數(shù)據(jù)分析。主要針對(duì)敏感sink中的危險(xiǎn)參數(shù),如mysql_query函數(shù)中的第1個(gè)參數(shù),經(jīng)過(guò)回溯獲得到相應(yīng)的數(shù)據(jù)流信息,如果在回溯進(jìn)程中發(fā)現(xiàn)該參數(shù)有用戶控制的跡象,就進(jìn)行記錄。如果該危險(xiǎn)參數(shù)有相應(yīng)的編碼、凈化操作也要進(jìn)行記錄。通過(guò)對(duì)危險(xiǎn)參數(shù)的數(shù)據(jù)進(jìn)行跟蹤和分析,完成污點(diǎn)分析。
有了模塊,那末如何進(jìn)行有效的流程來(lái)實(shí)行自動(dòng)化審計(jì),我使用了以下的流程:
分析系統(tǒng)經(jīng)過(guò)的大致流程以下:
1、框架初始化
首先進(jìn)行分析框架的初始化工作,主要是搜集待分析源碼工程中的所有用戶自定義類的信息,包括類名,類屬性,類方法名,類所在的文件路徑。
這些Record寄存在全局上下文類Context中,該類使用單例模式進(jìn)行設(shè)計(jì),并且常駐內(nèi)存,便于后續(xù)的分析使用。
2、判斷Main File
其次判斷每一個(gè)PHP文件是不是是Main file。在PHP語(yǔ)言中,沒(méi)有所謂的main函數(shù),大部份Web中的PHP文件分為調(diào)用和定義兩種類型,定義類型的PHP文件是用來(lái)定義1些業(yè)務(wù)類、工具類、工具函數(shù)等,不提供給用戶進(jìn)行訪問(wèn),而是提供給調(diào)用類型的PHP文件進(jìn)行調(diào)用。而真正處理用戶要求的則是調(diào)用類型的PHP文件,比如全局index.php文件。靜態(tài)分析主要是針對(duì)處理用戶要求的調(diào)用類型的PHP文件,即Main File。判斷根據(jù)為:
在AST解析完成的基礎(chǔ)上,判斷1個(gè)PHP文件中的類定義、方法定義的代碼行數(shù)占該文件所有代碼行數(shù)是不是超過(guò)1個(gè)范圍,如果是,則視為定義類型的PHP文件,否則為Main File,添加到待分析的文件名列表中。
3、AST抽象語(yǔ)法樹(shù)的構(gòu)建
本項(xiàng)目基于PHP語(yǔ)言本身進(jìn)行開(kāi)發(fā),對(duì)其AST的構(gòu)建,我們參考目前比較優(yōu)秀的PHP AST構(gòu)建的實(shí)現(xiàn)――――PHP Parser。
該開(kāi)源項(xiàng)目基于PHP語(yǔ)言本身進(jìn)行開(kāi)發(fā),可以對(duì)PHP的大多數(shù)結(jié)構(gòu)如if、while、switch、數(shù)組聲明、方法調(diào)用、全局變量等語(yǔ)法結(jié)構(gòu)進(jìn)行解析。可以很好的完本錢(qián)項(xiàng)目的編譯前端處理的1部份工作。
4、CFG流圖構(gòu)建
使用CFGGenerator類中的CFGBuilder方法。方法定義以下:
具體思路是采取遞歸構(gòu)建CFG。首先輸入遍歷AST獲得的nodes集合,遍歷中對(duì)集合中的元素(node)進(jìn)行類型判斷,如判斷是不是是分支、跳轉(zhuǎn)、結(jié)束等語(yǔ)句,并依照node的類型進(jìn)行CFG的構(gòu)建。
這里對(duì)分支語(yǔ)句、循環(huán)語(yǔ)句的跳轉(zhuǎn)條件(conditions)要存儲(chǔ)至CFG中的邊(Edge)上,方便數(shù)據(jù)流分析。
5、數(shù)據(jù)流信息的搜集
對(duì)1段代碼塊,最有效的并且值得搜集的信息是賦值語(yǔ)句、函數(shù)調(diào)用、常量(const define)、注冊(cè)的變量(extract parse_str)。
賦值語(yǔ)句的作用就是為了后續(xù)進(jìn)行變量跟蹤,在實(shí)現(xiàn)中,我使用了1種結(jié)構(gòu)來(lái)表示賦值的value和location。而其他的數(shù)據(jù)信息是基于AST來(lái)辨別和獲得的。比如函數(shù)調(diào)用中,判斷變量是不是遭到轉(zhuǎn)義、編碼等操作,或調(diào)用的函數(shù)是不是是sink(如mysql_query)。
6、變量?jī)艋⒕幋a信息處理
$clearsql = addslashes($sql) ;
賦值語(yǔ)句,當(dāng)右側(cè)是過(guò)濾函數(shù)時(shí)(用戶自定義過(guò)濾函數(shù)或內(nèi)置過(guò)濾函數(shù)),則調(diào)用函數(shù)的返回值被凈化,即$clearsql的凈化標(biāo)簽加上addslashes。
發(fā)現(xiàn)函數(shù)調(diào)用,判斷函數(shù)名是不是是配置文件中進(jìn)行配置的安全函數(shù)。
如果是,則將凈化標(biāo)簽添加至location的symbol中。
7、進(jìn)程間分析
如果在審計(jì)中,發(fā)現(xiàn)用戶函數(shù)的調(diào)用,這時(shí)候候必須要進(jìn)行進(jìn)程間的分析,在分析的工程中定位到具體方法的代碼塊,帶入變量進(jìn)行分析。
難點(diǎn)在于,如何進(jìn)行變量回溯、如何應(yīng)對(duì)不同文件中的相同名稱的方法、如何支持類方法的調(diào)用分析、如何保存用戶自定義的sink(比如在myexec中調(diào)用exec函數(shù),如果沒(méi)有經(jīng)過(guò)有效的凈化,那末myexec也要視為危險(xiǎn)函數(shù))、如何對(duì)用戶自定義的sink進(jìn)行分類(如SQLI XSS XPATH等)。
處理流程以下:
8、污點(diǎn)分析
有了上面的進(jìn)程,最后要進(jìn)行的就是污點(diǎn)分析,主要針對(duì)系統(tǒng)中內(nèi)置的1些風(fēng)險(xiǎn)函數(shù),比如可能致使xss的echo。并且要對(duì)危險(xiǎn)函數(shù)中的危險(xiǎn)參數(shù)做有效的分析,這些分析包括判斷是不是進(jìn)行了有效的凈化(比如轉(zhuǎn)義、正則匹配等),和制定算法來(lái)回溯前面該變量的賦值或其他變換。這無(wú)疑對(duì)安全研究人員工程能力的1個(gè)考驗(yàn),也是自動(dòng)化審計(jì)最重要的階段。
通過(guò)上面的介紹,你可以看到要實(shí)現(xiàn)1款自己的自動(dòng)化審計(jì)工具所要趟的坑是很多的。我的嘗試中也是遇到了N多的困難,并且靜態(tài)分析確切帶有1定的局限性,比如動(dòng)態(tài)分析中輕易可以取得的字符串變換的進(jìn)程,在靜態(tài)分析中就難以實(shí)現(xiàn),這不是技術(shù)上能夠突破的,而是靜態(tài)分析本身的局限性致使的,所以單純的靜態(tài)分析如果想要做到誤報(bào)和漏報(bào)很低,畢竟引入1些動(dòng)態(tài)的思想,比如對(duì)eval中的代碼進(jìn)行摹擬,對(duì)字符串變化函數(shù)和正則表達(dá)式進(jìn)行處理等。還有就是對(duì)1些基于MVC框架的,比如CI框架,代碼很分散,比如數(shù)據(jù)凈化的代碼放在input類的擴(kuò)大中,像這類PHP利用,我認(rèn)為很難做到1個(gè)通用的審計(jì)框架,應(yīng)當(dāng)要單獨(dú)對(duì)待。
以上只是粗略的把我當(dāng)前的嘗試(目前沒(méi)有完全實(shí)現(xiàn))拿來(lái)share,畢竟大學(xué)狗不是專業(yè)人員,希望可以拋磚引玉,使得愈來(lái)愈多的安全研究人員關(guān)注這1領(lǐng)域。