曹凱,何晶,范文慶,黃瑋
(中國傳媒大學(xué) 理工學(xué)部,北京 100024)
PHP語言在網(wǎng)站服務(wù)端使用廣泛,但由于固有的脆弱性,在編程過程中易產(chǎn)生各種漏洞。其中較為常見的有SQL注入漏洞和跨站腳本漏洞。根據(jù)OWASP(Open Web Appliation Security)[1]2017年最新公布的數(shù)據(jù)顯示,在排名前十的Web應(yīng)用安全漏洞中,注入類攻擊排名第一位,跨站腳本攻擊排名第三位。這兩種漏洞的成因主要是對用戶輸入數(shù)據(jù)的有效性未能進(jìn)行合理驗(yàn)證,因此這種類型的漏洞又被稱為污染數(shù)據(jù)傳播漏洞,也可稱為污點(diǎn)型漏洞。本文對PHP漏洞檢測主要也是針對于SQL注入漏洞和跨站腳本漏洞。
對于Web漏洞的分析,開發(fā)人員通常會采用兩種分析方法。即動態(tài)分析和靜態(tài)分析。動態(tài)分析使用較為容易,用于發(fā)現(xiàn)程序運(yùn)行時出現(xiàn)的錯誤。而靜態(tài)分析的檢測,則不需要代碼的運(yùn)行。隨著技術(shù)的不斷進(jìn)步,更高效的算法被研究出來,靜態(tài)分析方法也變得越來越成熟。
目前業(yè)界PHP靜態(tài)分析工具有:Pixy,RIPS,PHP-Sat,WAP及Foritfy SCA等。Pixy[2]是使用Java語言開發(fā)的一款開源的PHP靜態(tài)檢測工具。其通過數(shù)據(jù)流分析的方法檢測漏洞,其機(jī)制非常有效,但Pixy只支持PHP4的語法,對于PHP5以后的語法特性并不支持,而且主要針對的漏洞為跨站腳本漏洞,對于其他漏洞檢測效果并不理想。RIPS[3]是用PHP語言開發(fā)的一款檢測PHP的工具,是基于token流的靜態(tài)分析工具。它通過PHP的內(nèi)置函數(shù)token_get_all()來對PHP代碼進(jìn)行詞法分析從而獲得token,然后進(jìn)一步將代碼轉(zhuǎn)換為便于分析的中間格式,進(jìn)而采用污點(diǎn)分析方法檢測漏洞。WAP[4],全稱Web Application Protection,是一款采用Java語言編寫的PHP漏洞檢測工具,該工具采用污點(diǎn)分析的方法分析源碼,優(yōu)點(diǎn)是可以自動化修補(bǔ)被確認(rèn)的漏洞。Balzarotti[5]等人結(jié)合字符串分析方法,基于Pixy工具實(shí)現(xiàn)了一種動靜結(jié)合的PHP代碼分析方法。Rimsa[6]等人使用e-SSA作為中間表示形式,以此對PHP進(jìn)行污點(diǎn)分析。Y.Zheng和X.Zhang[7]提出了路徑和上下文相關(guān)的過程間分析方法來檢測漏洞。但以上工具仍存在一些問題,比如中間表示形式不夠完備,導(dǎo)致丟失了很多重要信息;對文件包含處理不夠完善;對新版本的PHP語法特性不能完全兼容;漏報和誤報相對較高。
本文在總結(jié)前人的經(jīng)驗(yàn)的基礎(chǔ)上,采用PHP-Parser對PHP代碼進(jìn)行語法和詞法分析,可以兼容最新的和應(yīng)用更為廣泛的PHP5和PHP7的新特性,產(chǎn)生信息非常完整的抽象語法樹,然后構(gòu)建控制流圖,再在生成的控制流圖上進(jìn)行污點(diǎn)傳播分析,進(jìn)而檢測出可能存在的漏洞。通過測試,采用本文方法確實(shí)可以檢測出相應(yīng)漏洞。
為了進(jìn)行污點(diǎn)分析,PHP源碼必須被轉(zhuǎn)換為一種利于分析的中間表示形式,本文采用控制流圖(Control Flow Graph,CFG)作為中間表示形式,但CFG的生成依賴于抽象語法樹(Abstract Syntax Tree,AST),抽象語法樹反映了程序的結(jié)構(gòu),因此需要先對PHP源碼進(jìn)行詞法和語法分析來生成抽象語法樹。
對于生成抽象語法樹的方式有多種。有的采用HHVM[8],一種用來執(zhí)行PHP語言的PHP虛擬機(jī)來生成抽象語法樹;有的基于ANTLR[9],一款根據(jù)輸入自動生成語法樹的語法解析器。本文對PHP的詞法和語法分析采用PHP語法處理器PHP-Parser[10],PHP-Parser是一個由PHP編寫的支持PHP5.2到PHP7.1的語法解析器。主要用來產(chǎn)生抽象語法樹,對于PHP代碼的靜態(tài)分析具有很大的幫助。例如,將以下代碼傳遞給解析器:
echo 'Hi','World';
?>
將會產(chǎn)生一個數(shù)組格式的抽象語法樹:
array(
0:Stmt_Echo(
exprs:array(
0:Scalar_String(
value:Hi
)
1:Scalar_String(
value:World
)
)
)
以上輸出的抽象語法樹包含一個輸出語句節(jié)點(diǎn),節(jié)點(diǎn)內(nèi)包含一個數(shù)組,數(shù)組內(nèi)容為兩個常量字符串。 PHP的語法繁多,大概包含140種不同的節(jié)點(diǎn),為了便于解析將其分為以下幾類:
(1)PHPParserNodeStmt,即語句節(jié)點(diǎn)。沒有任何返回值的結(jié)構(gòu),如賦值語句,函數(shù)定義等。
(2)PHPParserNodeExpr,即表達(dá)式節(jié)點(diǎn)。有返回值的結(jié)構(gòu),如單個變量,函數(shù)調(diào)用等。
(3)PHPParserNodeScalar,即常量節(jié)點(diǎn)。用來表示任何常量,如字符串,整型,常量表達(dá)式等。
(4)還包括一些不屬于以上三種類型的節(jié)點(diǎn),如參數(shù)節(jié)點(diǎn)等。
當(dāng)獲得PHP源代碼后,首先使用PHP-Parser將源碼轉(zhuǎn)換為一個數(shù)組形式抽象語法樹,若直接進(jìn)行數(shù)據(jù)流分析,由于編程語言中會有分支、循環(huán)、跳轉(zhuǎn)以及條件表達(dá)式等結(jié)構(gòu),當(dāng)中隱含了不連續(xù)的控制流,所以抽象語法樹與數(shù)據(jù)流分析并不能完全兼容。因此本文將抽象語法樹轉(zhuǎn)換為控制流圖,然后再進(jìn)行污點(diǎn)分析。
成果表包括界樁登記表、三交點(diǎn)界樁登記表、界樁成果表、界址點(diǎn)成果表、三交點(diǎn)成果表和界線協(xié)議書附圖備考表。參考1998年陜西省各鄉(xiāng)鎮(zhèn)聯(lián)合勘界相關(guān)成果,對邊界線上的界線名稱、邊界點(diǎn)名稱、編號、坐標(biāo)及行政歸屬等內(nèi)容形成不同制式表格模板,方便信息錄入、管理與查詢。
本文通過遞歸的方法來構(gòu)造CFG。首先遍歷AST中的所有節(jié)點(diǎn),將節(jié)點(diǎn)集合作為輸入,遍歷過程中對集合中的節(jié)點(diǎn)進(jìn)行判斷處理,比如是否為跳轉(zhuǎn),分支,結(jié)束等語句,要按照節(jié)點(diǎn)的類型來構(gòu)造CFG。此處如果遇到循環(huán)語句和分支語句的跳轉(zhuǎn)條件,則將其存儲在CFG的邊上,以便后續(xù)的數(shù)據(jù)流處理。本文中對于CFG邊的處理要包含以下信息:邊的來源,邊的目的,邊上攜帶的條件,邊上攜帶的凈化信息和編碼信息。此外對于部分節(jié)點(diǎn)還要生成基本塊摘要,以便在后續(xù)污點(diǎn)分析中使用?;緣K摘要中包含一些關(guān)鍵信息(主要包含常量,全局變量,返回值,全局變量的注冊以及數(shù)據(jù)流信息等)。
具體的CFG生成算法如下:
1.首先創(chuàng)建一個輸入基本塊,并為其構(gòu)造一個輸出邊,連接到當(dāng)前基本塊,并作為當(dāng)前基本塊的輸入邊。
2.獲取AST中的節(jié)點(diǎn),若是只有一個節(jié)點(diǎn),則將其加入基本塊,生成相應(yīng)的基本塊摘要。如果包含多個節(jié)點(diǎn),則對其進(jìn)行遍歷處理。
3.如果遇到函數(shù)定義類型節(jié)點(diǎn)類型則不對其進(jìn)行分析。
4.如果節(jié)點(diǎn)是跳轉(zhuǎn)類型的語句,則生成當(dāng)前基本塊摘要,并對每個分支建立其對應(yīng)的基本塊。首先創(chuàng)建一個新的基本塊,然后獲取分支節(jié)點(diǎn)進(jìn)行遍歷處理,通過遞歸處理構(gòu)造分支節(jié)點(diǎn)的CFG。并以新基本塊作為當(dāng)前基本塊。
5.如果節(jié)點(diǎn)類型是循環(huán)語句,則加入循環(huán)體構(gòu)建基本塊摘要。首先將循環(huán)條件加入到基本塊中,接下來處理循環(huán)體,創(chuàng)建新的基本塊,然后遞歸處理構(gòu)造CFG。并以新基本塊作為當(dāng)前基本塊。
6.如果節(jié)點(diǎn)是return語句,則將節(jié)點(diǎn)加入當(dāng)前基本塊,并構(gòu)造基本塊摘要,返回當(dāng)前基本塊。
7.如果節(jié)點(diǎn)是結(jié)束語句,則跳出循環(huán),構(gòu)造基本塊摘要。
8.如果節(jié)點(diǎn)是其他類型的語句,則統(tǒng)一處理,將節(jié)點(diǎn)加入當(dāng)前基本塊。
9.如果當(dāng)前基本塊不是結(jié)束語句,則為當(dāng)前基本塊構(gòu)造一條輸出邊,作為下一基本塊的輸入邊,直至遍歷完所有節(jié)點(diǎn)后,構(gòu)造一個輸出基本塊。
運(yùn)用該算法生成CFG控制流圖,將AST生成便于數(shù)據(jù)流分析的中間表示,用于后續(xù)的污點(diǎn)分析。
污點(diǎn)分析是數(shù)據(jù)流分析技術(shù)的一種實(shí)踐方法,在過去的幾十年中數(shù)據(jù)流分析技術(shù)一直是信息安全領(lǐng)域的重要研究方向,其中有大量的工作研究制定數(shù)據(jù)流策略。
本文的污點(diǎn)分析是始于生成CFG的過程中。如果在生成CFG時發(fā)現(xiàn)了敏感函數(shù)的調(diào)用,則獲取其中包含的危險參數(shù),通過變量回溯的方法進(jìn)行向上追蹤,判斷該參數(shù)是否來源于污點(diǎn)源中,并追蹤其是否經(jīng)過了凈化處理來判斷是否會產(chǎn)生漏洞。
污點(diǎn)源source,代表系統(tǒng)直接引入不可信的數(shù)據(jù),多數(shù)時候是由用戶輸入獲得的,用戶的直接輸入可以由超全局變量獲取,超全局變量包括$_GET、$_POST、$_COOKIE等。當(dāng)程序的敏感函數(shù)獲取了用戶輸入的不可信的數(shù)據(jù),就可能會導(dǎo)致污點(diǎn)型漏洞的出現(xiàn)。
污點(diǎn)匯聚點(diǎn)表示產(chǎn)生安全敏感操作或者泄露隱私數(shù)據(jù)到外界,也就是漏洞最終被利用的結(jié)果。如XSS漏洞泄漏了COOKIE,SQL注入漏洞泄露了數(shù)據(jù)庫信息等。這些信息泄漏往往都是由于一些敏感函數(shù)的操作引起的,因此要對PHP敏感函數(shù)進(jìn)行建模,敏感函數(shù)是導(dǎo)致漏洞的關(guān)鍵之處。本文針對PHP的漏洞檢測所設(shè)置的污點(diǎn)匯聚點(diǎn)即是一些可能導(dǎo)致漏洞的敏感函數(shù)。其中跨站腳本漏洞的敏感函數(shù)點(diǎn)有‘echo’,‘print’,‘print_r’,‘exit’,‘die’,‘printf’,‘vprintf’等。SQL語句執(zhí)行函數(shù)點(diǎn)包含‘dba_open’,‘odbc_do’,‘fbsql_query’,‘mysql_query’,‘pg_query’,‘sqlite_query’等,本文共統(tǒng)計并配置了五十余個函數(shù),在此不一一贅述。
此外,在PHP代碼審計過程中,若是發(fā)現(xiàn)了可控的危險參數(shù),我們會立即去查看開發(fā)者是否對該變量進(jìn)行了有效的處理,如過濾、轉(zhuǎn)義或者編碼等。如果沒有處理,我們認(rèn)為該處存在漏洞,如果經(jīng)過了有效處理,則認(rèn)為該處是安全的。在本文的靜態(tài)檢測方法中,也是遵循上述思路。為了降低系統(tǒng)的誤報率,在設(shè)計過程中除了污點(diǎn)源和污點(diǎn)匯聚點(diǎn)外,我們還統(tǒng)計并配置了PHP中的安全函數(shù)。本文對PHP內(nèi)置的安全函數(shù)進(jìn)行了歸類,如防止XSS的函數(shù)htmlspecialchars等,防止SQL注入的函數(shù)addslashes等。此外還有一些通用的防止漏洞的函數(shù)如intval等。如果危險參數(shù)在污點(diǎn)分析的過程中經(jīng)過了安全的函數(shù)處理,就被視為經(jīng)過了有效的凈化。
采用PHP語言編寫的各種應(yīng)用程序中,其源代碼會分成許多的源文件,程序運(yùn)行時,通過文件包含方法來組合這些源文件。PHP的文件包含方式主要通過以下四個函數(shù)實(shí)現(xiàn):include();require();include_once();require_once()。使用上述函數(shù)包含其他文件時,會獲取到指定文件中包含的文本,代碼和標(biāo)記等,并會復(fù)制到使用include或require的文件中,包含的文件會作為PHP代碼運(yùn)行。因此在進(jìn)行數(shù)據(jù)流分析的時候我們要考慮到文件包含的問題,進(jìn)行多文件間的處理。我們在進(jìn)行多文件間分析之前還要收集文件的信息生成文件摘要,文件摘要主要包含賦值語句的信息,以及相關(guān)的凈化和編碼信息等數(shù)據(jù)流信息。
本文對于文件包含處理的大致思路如下:
1.首先獲取當(dāng)前文件包含的所有文件名,獲取其路徑。
2.遍歷包含的這些文件的文件摘要,檢測是否有相關(guān)的數(shù)據(jù)流信息,如果有獲取其變量名。
3.判斷該變量是否是污點(diǎn)變量。
4.以此文件為當(dāng)前文件,繼續(xù)進(jìn)行文件包含的處理。
本文的污點(diǎn)分析流程如圖1所示,若在程序分析的過程中發(fā)現(xiàn)了敏感函數(shù)的調(diào)用,即通過回溯方法獲得危險參數(shù)節(jié)點(diǎn),由此進(jìn)行污點(diǎn)分析。簡單來說,就是判斷該危險參數(shù)是否會導(dǎo)致觸發(fā)漏洞。獲得危險參數(shù)后,分析整體步驟如下:
圖1 污點(diǎn)分析流程
1.首先檢查該危險參數(shù)在當(dāng)前基本塊中的賦值情況,查詢數(shù)據(jù)流信息中右節(jié)點(diǎn)是否有用戶的輸入的污點(diǎn)源,例如$_GET,$_POST等超全局變量。然后通過判斷不同類型漏洞的插件類確認(rèn)該節(jié)點(diǎn)是否安全。
2.若在當(dāng)前基本塊中未能檢測到用戶輸入源,則進(jìn)行多基本塊之間的分析。首先對當(dāng)前基本塊的前驅(qū)基本塊進(jìn)行查找,在獲取了前驅(qū)基本塊后開始危險變量的分析。同步驟1),判斷危險參數(shù)是否經(jīng)過了凈化處理,并判斷其是否來源于污點(diǎn)源,如果是則報告漏洞。若當(dāng)前基本塊沒有前驅(qū)基本塊,則結(jié)束算法。
3.若在上述基本塊間分析過程中未能發(fā)現(xiàn)漏洞,則進(jìn)入多文件間分析。獲取當(dāng)前基本塊之前的文件摘要的集合,然后對這些文件摘要進(jìn)行遍歷,并由此做出判斷。
4.在執(zhí)行以上過程中,若發(fā)現(xiàn)漏洞,則通過漏洞報告模塊報告漏洞。若沒有發(fā)現(xiàn)漏洞,則系統(tǒng)繼續(xù)往下分析代碼。
本文的測試集采用DVWA(Damm Vulnerable Web App)[11],DVWA是基于PHP和MySQL開發(fā)的Web應(yīng)用程序,是一個漏洞實(shí)驗(yàn)平臺,包含SQL注入,跨站腳本等,其漏洞數(shù)量是確定的,所以可以精準(zhǔn)的確定誤報和漏報。本文專對包含SQL注入和跨站腳本的12個程序進(jìn)行檢測,共分為三組,一組包含XSS漏洞,一組包含普通的SQL注入漏洞,一組包含SQL盲注類型的漏洞,每組四個程序,根據(jù)安全防護(hù)級別不同將其分為low、medium、high、impossible四個等級,其中l(wèi)ow防護(hù)級別最低,medium次之,high防護(hù)級別較高但仍包含漏洞,impossible防護(hù)級別最高,不包含漏洞。實(shí)際檢測效果如表1所示,其中Y代表檢出漏洞,N代表未檢出漏洞。
表1 實(shí)驗(yàn)結(jié)果
從上述結(jié)果可以看出,本文設(shè)計的工具對于SQL注入類型的漏洞檢測效果較好,在包含SQL注入的8個文件中檢測出6個確定的漏洞。但是對于XSS漏洞只檢測出一個,產(chǎn)生了兩個漏報。根據(jù)分析,對于Medium程序中使用了str_replace()函數(shù)直接將獲得的 达尔| 和政县| 历史| 海门市| 镇原县| 积石山| 嘉祥县| 镇雄县| 唐山市| 余江县| 安阳县| 长垣县| 仙桃市| 天长市| 东阳市| 准格尔旗| 绥芬河市| 望都县| 吉隆县| 清远市| 东港市| 呈贡县| 福清市| 巴楚县| 寻乌县| 博乐市| 德清县| 名山县| 天峻县| 阿拉善右旗| 曲松县| 富裕县| 吉水县| 锦屏县| 太仆寺旗| 广宁县| 延长县| 惠水县| 湖口县| 盐山县| 嘉峪关市|