陳藝夫
(張家界航空工業(yè)職業(yè)技術(shù)學(xué)院,湖南 張家界 427000)
隨著web3.0[1]概念的提出,web2.0 的“主力軍”之一的PHP 并沒有退居幕后,依然以“微服務(wù)”、“api 服務(wù)”占據(jù)著web3.0 的主力地位。其便捷易學(xué)的特性使得加入PHP 開發(fā)的人員多而雜,進而導(dǎo)致PHP 開發(fā)的項目容易產(chǎn)生安全漏洞;而市場占有率高,則容易吸引別人尋找漏洞。造成了審計PHP 開發(fā)的開源CMS 成為了攻擊web 服務(wù)的最有效的手段之一。具體web 應(yīng)用漏洞占比如圖1 所示。
圖1 CNVD 2020 年4 月通用漏洞統(tǒng)計
漏洞發(fā)掘方式主要包含了代碼審計和滲透測試[2]。相對于滲透測試,代碼審計只關(guān)心某個系統(tǒng)的代碼漏洞,不關(guān)心提供代碼支持環(huán)境或者其他支持環(huán)境的漏洞;其受測面更窄,卻更具深度。但是代碼審計主要針對的是owasp top 10 漏洞,對于邏輯漏洞的發(fā)掘能力相對較弱。
代碼安全審計是一種漏洞挖掘方式,主要包含了白盒審計、黑盒審計、灰盒審計。三種不同的測試方式有不同的優(yōu)缺點。根據(jù)要求使用不同的審計方法。這里我們主要討論以何種思路來利用上面三種審計方式完成漏洞挖掘任務(wù)。
PHP 語言開發(fā)的產(chǎn)品產(chǎn)生漏洞的客觀原因有:①PHP 發(fā)展過熱,導(dǎo)致進入行業(yè)的初學(xué)者較多??傮w而言,代碼的質(zhì)量不高。②早期安全事件不受重視,安全開發(fā)意識的培訓(xùn)不到位。③PHP 項目以小公司為主,形成了“短平快”的開發(fā)方式,追求的是“敏捷開發(fā)[3]”。因為需要提高開發(fā)效率、維護客戶關(guān)系等原因,有意無意的忽略安全管理[4]。
PHP 語言開發(fā)的產(chǎn)品產(chǎn)生漏洞的具體原因有:①代碼編寫者在編寫代碼時對傳入的參數(shù)沒有過濾或過濾不嚴(yán)。②PHP 語言本身提供的方法出現(xiàn)了漏洞。③使用了不安全的函數(shù)。④代碼運行邏輯不嚴(yán)謹(jǐn)[5]。
條件一:用戶可以控制的輸入。條件二:用戶可以獲得輸出。條件三:用戶可以利用輸入在服務(wù)器或者客戶端執(zhí)行權(quán)限外的操作。
值得注意的是,以上的第一個條件中,用戶“可以控制的輸入”既指可以完全隨意輸入,也包含具有限制性的輸入。反應(yīng)在漏洞上就是漏洞的利用難度高低以及影響范圍的大小。
第二個條件不單指直接通訪問獲得及時反饋或結(jié)果,也包含利用dnsLog、反彈shell、延時判斷、非正常返回判斷等獲得反饋或結(jié)果。
第三個條件為主觀條件。在某一個權(quán)限范疇內(nèi)出現(xiàn)BUG,盡管是設(shè)計者因未考慮周全產(chǎn)生的問題,但是獲取的信息或者操作的權(quán)限任在管理者允許的權(quán)限內(nèi),就不能視作安全漏洞。這種漏洞的判斷條件彈性較大,也是眾多白帽子和廠商關(guān)于漏洞定級存在的主要矛盾點。
一般的代碼審計需求分為兩類,第一類是針對開源系統(tǒng)進行的。大多數(shù)屬于公益類審計。另一類是針對授權(quán)獲取到源碼后的審計。大部分屬于商業(yè)行為。但是本文所述審計方法都適用以上兩種情況。
思路:在php 種常見的任意文件讀取、任意文件刪除、任意變量覆蓋、任意文件包含等漏洞中都會有一些固定而且危險的函數(shù)或者方法。主要涉及的函數(shù)包含以下但不限于以下函數(shù):read()、unlink()、extract()、include()。所以審計的時候可以針對性的去查找相關(guān)方法、函數(shù)、關(guān)鍵字等。這里使用YCCMS 開源系統(tǒng)進行測試(注:所有本文展示的漏洞均已上報國家信息安全漏洞共享平臺,勿做違法用途)。
方法:使用開源的編輯器或者審計工具協(xié)助追蹤函數(shù),如:vscode 中的搜索、seay 源碼審計系統(tǒng)中的全文搜索以及自動審計。
如圖2 所示,在使用了seay 源碼審計系統(tǒng)之后,系統(tǒng)會自動追蹤相關(guān)危險函數(shù)。也可以在規(guī)則中自己添加自定義的規(guī)則。但由于追蹤的目標(biāo)是危險函數(shù)的特征字符,且未對相關(guān)的代碼邏輯進行進一步的分析,導(dǎo)致這種方法檢索出來的漏洞存在大量的誤報情況。除圖2 中所圈出來的信息存在漏洞可能,其余皆為誤報。
圖2 seay 源碼系統(tǒng)自動審計所查疑似漏洞
點擊圖2 中圈出的鏈接可以直接訪問到使用該危險方法unlink()的文件。由于誤報問題,我們需要進入該文件進行一次邏輯分析。人工判定是否存漏洞。所追蹤到的函數(shù)內(nèi)容如圖3 所示。
圖3 追蹤危險函數(shù)unlink
通過閱讀該文件,我們發(fā)現(xiàn)途中是一個使用該方法的類,該類在觸發(fā)使用clean 方法的時候會調(diào)用危險函數(shù)unlink()。根據(jù)該類的clean 方法的說明我們可以知道,該方法是用來清理系統(tǒng)生成的靜態(tài)文件的方法。是一個正常的刪除功能的寫法。而unlink()函數(shù)使用的參數(shù)來自于變量$_fileDir 與$_dirName 的拼接。根據(jù)clean 方法的內(nèi)容我們可以知道。如果變量$_GET[‘navname‘]可控,即可利用../等字符進行跨目錄操作。形成任意文件刪除漏洞。具體邏輯如圖4 所示。
圖4 危險方法clean 的實現(xiàn)邏輯
然后我們可以繼續(xù)追蹤$_GET 有沒有被過濾。但是首先應(yīng)該要確定該類NavAction 是否被引用,引用來自于哪里。這里可以使用vscode 編輯器的全文關(guān)鍵字搜索功能,如圖5 所示。
圖5 通過vscode 全文追蹤發(fā)現(xiàn)關(guān)鍵字
發(fā)現(xiàn)該文件并未被引用。那么該類的功能需要觸發(fā)必然是以參數(shù)調(diào)用的方式進行引用。一般情況下為自動加載、URL 請求加載兩種方式。我這里的思路為直接訪問入口文件,讀懂邏輯獲得關(guān)鍵邏輯信息,用于尋找該文件的出發(fā)點,以達到尋找到$_get 的值的來源。
首先需要理解框架結(jié)構(gòu)。大致的目錄如下:
且admin 目錄下存在index.php 則極可能是后臺入口文件。
訪問該文件,內(nèi)容如下:
發(fā)現(xiàn)該文件只有非常簡單的一行。這種格式是一個標(biāo)準(zhǔn)的入口文件。
根據(jù)require 的請求邏輯繼續(xù)去追蹤../config/run.inc.php 文件。內(nèi)容如圖6 所示。
圖6 入口文件run.inc.php 文件
在圖6 文件中第19 行可以發(fā)現(xiàn)_autoload()類。該函數(shù)用于自加載類文件。
觸發(fā)條件為“訪問類”的時候,既當(dāng)代碼運行到29 行:Factory::setAction 的時候。根據(jù)其代碼意思可以知曉。在訪問該文件的時候會根據(jù)$_classname 變量的值引入controller 目錄或者model目錄或者class 目錄下的“.class.php”文件作為類文件的引入。
而$_classname 則必然來自于Factory::setAction()-run()的觸發(fā)。這里使用vscode 軟件的類追蹤按下Ctrl+左鍵可以直接定位到該文件或者方法。Factory類內(nèi)容如圖7 所示。
圖7 Factory 工廠類
由以上代碼我們可以得知,訪問類文件依靠getA()方法,表現(xiàn)在url 請求中就是a=“xxx”。這里的XXX 可以是array 中存在任意類文件名。
以上內(nèi)容可以確定選擇類的方式為http://localhost/admin/index.php?a=Nav。而確定Factory::setAction()->run();中的setAction 之后需要繼續(xù)使用vscode 的快速鏈接功能追蹤到方法run()。具體內(nèi)容如圖8 所示。
圖8 工廠類的run 方法實現(xiàn)
由圖8 代碼第29 和30 行可以知道。想要觸發(fā)一個類的某種方法需要傳參m 即可。那么最后我們獲取到觸發(fā)漏洞的方法應(yīng)該是訪問url:
http://localhost/admin/index.php?a=Nav&m=clean。其中Nav 是類的縮寫。m 是需要執(zhí)行的方法。邏輯如圖9 所示。
圖9 系統(tǒng)運行邏輯
根據(jù)以上分析總結(jié)發(fā)現(xiàn),在該文件運行的時候不存在對$_get[‘navname’]變量的過濾。所以可以直接傳入導(dǎo)致漏洞。最后的exploit 如下:
http://localhost/admin/index.php?a=nav&m=clean&navname=../../etc/passwd
這里的index.php 因為路徑重寫可以省略。這里的../../etc/passwd 則是需要任意刪除的文件。
該方法主要的優(yōu)勢有:①快速找到切入點。②能快速尋找到可能出現(xiàn)漏洞的代碼。
主要缺點:①無法系統(tǒng)而且完整的對文件進行分析,需要在發(fā)現(xiàn)漏洞后花費大量精力尋找觸發(fā)點。②誤報率高,危險函數(shù)量大,審查較為麻煩。③很難發(fā)現(xiàn)邏輯漏洞。
不同于危險函數(shù)追蹤法,邏輯分析法在漏洞分析之前需要閱讀項目核心代碼或者通讀代碼。需要在正式開始審計之前熟悉項目中的各種功能。邏輯分析法主要使用的審計方法是灰盒審計和黑盒審計。
思路:采用最有可能出現(xiàn)問題的輸入測試現(xiàn)有所有功能(黑盒測試)。如:在留言框中填寫“ ”’</script><Script> alert (‘xss’)</script>”、在 登 陸注冊使用“ admin and ‘“`--/* ”等進行測試[6]。通過查看頁面反應(yīng)、數(shù)據(jù)反應(yīng)、后臺反應(yīng)等方法確定是否存在不同的輸出?;蛘咚伎几鱾€功能之間的邏輯聯(lián)系,畫出權(quán)限關(guān)系、功能關(guān)系、角色關(guān)系等的思維導(dǎo)圖,從而尋找交叉點、分離點、沖突點等方法。
如圖10 所示,通過在后臺登陸頁面嘗試使用“返回“的方式測試,測試是否存在驗證碼不過期的問題。
圖10 ZZZCMS 后臺登陸頁面
經(jīng)過嘗試發(fā)現(xiàn)返回之后驗證碼不更新,基本確認(rèn)這里存在驗證碼繞過漏洞(注:低危漏洞,一般用于爆破)。這種測試方式屬于黑盒測試。
驗證思路:采用burpsuit 抓取請求包再利用intruder 模塊大量重放該報文,并且設(shè)置password為payload 如圖11 所示。
圖11 利用爆破測試驗證碼更新
其中第一行為訪問的序號,第二行為報文中作為變量的payload 值,其中第20 個payload 為我設(shè)置的密碼。第三行為返回報文的狀態(tài)值。最后一行為返回的報文的長度。
根據(jù)只有一個返回的長度為954 和返回的狀態(tài)碼302 可以確認(rèn)登錄成功,既驗證碼可以重復(fù)使用。
漏洞驗證:
第一步:獲取后臺登陸模塊的基本功能相關(guān)的黑盒測試信息。內(nèi)容如圖12 所示。
第二步:確定基本邏輯無誤的情況下檢查相關(guān)源碼。需要注意的是,這里如何檢查就需要依據(jù)通讀源碼或者理解核心源碼進行確定。(因篇幅有限,無法展示通讀源碼成果,特此說明。)
追蹤訪問后臺登陸文件。/admin/login.php,其登陸模塊的主要功能實現(xiàn)如圖13 所示。
圖12 獲取登陸頁面請求數(shù)據(jù)
圖13 Login.php 文件主要內(nèi)容
這里可以發(fā)現(xiàn)如下代碼:
get_cookie(‘a(chǎn)dminname’)==’’? $code=getfor m(‘code’,’post’,’code’)
該代碼中與驗證碼唯一相關(guān)的函數(shù)為getform函數(shù)。那么追蹤getform()函數(shù)。在/inc/zzz_main.php第656 行找到getform 方法。Getform 函數(shù)實現(xiàn)如圖14 所示。
圖14 getform 方法的實現(xiàn)
根據(jù)以上login.php 中的函數(shù)的參數(shù)可以得知,$code 的內(nèi)容最終會通過692 行進入checkstr 函數(shù)中去。這里繼續(xù)追蹤該函數(shù)。該方法依然在/inc/zzz_main.php 文件中。主要內(nèi)容如圖15 所示。
圖15 驗證碼驗證邏輯
發(fā)現(xiàn)checkstr 的代碼邏輯是如果滿足傳輸過來的類型為“code”的時候使用_SESSION 進行驗證碼驗證。繼續(xù)追蹤該函數(shù)。內(nèi)容如圖16 所示。
圖16 _SESSION 方法的實現(xiàn)
_session 函數(shù)在確定驗證碼的正確性之后未及時的銷毀session 導(dǎo)致session 可以復(fù)用,造成驗證碼繞過漏洞。完整運行邏輯如圖17 所示。
圖17 完整驗證碼的驗證邏輯
該漏洞更大的危害是在密碼找回功能處,可能出現(xiàn)任意密碼重置問題(漏洞成因:在手機接收的驗證碼長度小于6 的時候,利用數(shù)據(jù)包重放,且頁面驗證碼可以重復(fù)利用的情況下爆破手機驗證碼)。
邏輯分析法主要的優(yōu)點有:①可以發(fā)掘非危險函數(shù)產(chǎn)生的漏洞。②漏洞發(fā)現(xiàn)的準(zhǔn)確率高,并且具有較強的針對性。③結(jié)合黑盒、白盒、灰盒的測試方式能夠覆蓋到幾乎全部類型漏洞。
邏輯分析法的主要缺點:①審計前期需要完整讀懂項目代碼,審計準(zhǔn)備實踐過長。②功能測試內(nèi)容繁多,容易漏測或者測試不完全,導(dǎo)致漏洞被忽略。
本文針對php 代碼審計技術(shù)做了綜合性的介紹。從白盒審計和黑灰盒審計兩個方面演示了審計流程,挖掘到了具體的漏洞。也通過代碼邏輯說明了產(chǎn)生漏洞的具體原因。這種漏洞挖掘模式既能有效的挖掘出危害信息系統(tǒng)的漏洞,也能有效的指導(dǎo)信息系統(tǒng)的開發(fā)人員寫出安全的代碼。