指令碼語言中安全漏洞的靜態檢測(半機翻有刪增)
我們提出了一種靜態分析演算法,用於檢測PHP中的安全漏洞,PHP是一種用於構建Web應用程式的流行伺服器端指令碼語言。我們的分析 採用了一種新穎的三層體系結構 , 以在內部塊,過程內和過程間級別以更低的粒度級別捕獲資訊。 這種架構使我們能夠處理指令碼語言的動態特性,這些特性尚未被先前技術充分解決。
我們在六個流行的開源PHP程式碼庫中證明了我們的方法的有效性,發現了105個以前未知的安全漏洞,其中大多數我們認為可以遠端利用。
介紹
近年來,基於Web的應用程式迅速擴散,並已成為提供從論壇到銀行和零售等安全敏感領域的線上服務的事實標準
因此,這些應用程式中的安全漏洞對這些服務的提供者和使用者都構成了越來越大的威脅。在2004年下半年,賽門鐵克編制了670個影響Web應用程式的漏洞,比2003年同期增加了81%。在可預見的未來,這種趨勢可能會持續下去。
<!- more –>
根據同一報告,這些漏洞 通常是由輸入驗證中的程式設計錯誤和提交的請求的不當處理引起的 。
由於漏洞通常深深嵌入程式邏輯中,因此傳統的網路級防禦(例如防火牆)無法提供足夠的保護來抵禦此類攻擊。測試也基本上無效,因為攻擊者通常使用最不期望的輸入來利用這些漏洞並危及系統。
一種自然的替代方法是使用靜態分析找出這些錯誤。這種方法已經在WebSSARI 和Minamide 中進行了探索。 WebSSARI已被用於在PHP指令碼中查詢許多安全漏洞,但由於其基於過程內型別的分析而具有大量誤報和否定。 Minamide的系統檢查PHP指令碼的HTML輸出的語法正確性,似乎不能有效地發現安全漏洞。
本文的主要資訊是,指令碼語言的分析不需要比傳統語言的分析困難得多。雖然指令碼語言強調靜態分析的不同方面,但是為解決指令碼語言的重要方面而設計的分析可以可靠地識別指令碼中的許多嚴重漏洞並具有高度自動化。鑑於指令碼在現實世界應用程式中的重要性,我們認為靜態分析有機會在這個新領域產生重大影響。
在本文中,我們應用靜態分析來發現PHP中的安全漏洞,PHP是一種伺服器端指令碼語言,已成為開發Web應用程式最廣泛採用的平臺之一.我們的目標是自動發現嚴重漏洞的錯誤檢測工具很有信心。然而,這項工作並不旨在驗證缺少錯誤。
本文做出以下貢獻:
(1) 我們提出了一個PHP的過程間靜態分析演算法 。像PHP一樣動態的語言為靜態分析提出了獨特的挑戰:語言結構(例如,include )允許動態包含程式程式碼,型別在執行期間發生變化的變數,具有依賴於運算元的執行時型別的語義的操作(例如, <),並且普遍使用散列表和正則表示式匹配只是必須很好地建模以產生有用結果的一些特徵。為了忠實地模擬這種語言中的程式行為, 我們使用三層分析來捕獲在塊內,過程內和過程間級別上降低粒度級別的資訊。 這種體系結構允許在最重要的地方分析如 在內部塊中,並且在較小程度上,在過程內層面,並且在函式呼叫的自然抽象邊界處使用激進抽象來實現可伸縮性。 我們使用 符號執行 來模擬基本塊內的動態特徵,並使用 塊概要 來隱藏程式內和程式間分析的複雜性。我們相信相同的技術可以很容易地應用於其他指令碼語言(例如,Perl)。
(2) 我們將展示如何使用我們的靜態分析演算法來查詢SQL注入漏洞 。配置完成後,分析將完全自動完成。雖然我們在這項工作中專注於SQL注入,但是可以應用相同的技術來檢測其他漏洞,例如跨站點指令碼(XSS)和Web應用程式中的程式碼注入。
(3) 我們通過實施分析演算法並在六個用PHP編寫的流行Web應用程式上執行它來實驗驗證我們的方法,找到105個以前未知的安全漏洞。 我們分析了兩個報告的PHP融合漏洞,這是一個成熟的,廣泛部署的內容管理系統,併為兩者構建漏洞,允許攻擊者控制或破壞系統。
背景
本節簡要介紹PHP語言,並顯示PHP中SQL注入漏洞的示例。PHP是十年前由Rasmus Lerdorf建立的,它是一組簡單的Perl指令碼,用於跟蹤對其線上簡歷的訪問。它已經發展成為用於構建Web應用程式的最流行的伺服器端指令碼語言之一。根據最近的安全調查顯示,PHP安裝在44.6%的Apache Web伺服器上,被數百萬開發人員採用,並由雅虎,IBM,甲骨文和SAP等人使用或支援。
儘管PHP語言在過去十年中經歷了兩次重大的重新設計,但它保留了類似Perl的語法和動態(解釋)特性,這有助於其最簡單和靈活的聲稱優勢。PHP有一套程式設計結構和特殊操作 ,可以簡化Web開發。我們舉三個例子:
1.與SQL自然整合:
PHP為資料庫操作提供了幾乎原生的支援。例如,在字串中使用內聯變數,大多數SQL查詢可以通過簡單的函式呼叫簡明地表達
$rows=mysql query("UPDATE users SET pass=‘$pass’ WHERE userid=‘$userid’");
將此程式碼與Java進行對比,其中通常通過預準備語句訪問資料庫:一個建立語句模板並使用繫結變數填充值(及其型別):
PreparedStatement s = con.prepareStatement("UPDATE users SET pass = ?WHERE userid = ?"); s.setString(1, pass); s.setInt(2, userid); int rows = s.executeUpdate();
2.動態型別和來自字串的隱式轉換:
PHP與其他指令碼語言一樣,廣泛支援字串操作以及字串和其他型別之間的自動轉換。這些功能對於Web應用程式很方便,因為字串充當瀏覽器,Web伺服器和資料庫後端之間的公共介質。例如,我們可以在沒有顯式強制轉換的情況下將數字轉換為字串:
if ($userid < 0) exit; $query = "SELECT * from users WHERE userid = ‘$userid’";
3.變數範圍和環境:
PHP有許多機制可以在從執行環境訪問值時最大限度地減少冗餘。例如,HTTP get和post請求會自動匯入到全域性名稱空間中作為雜湊表 $_GET
和 $_ POST
。要訪問提交表單的“name”欄位,可以直接在程式中使用 $_GET ['name']
。
如果這聽起來仍然太多,那麼PHP提供了一個提取操作,可以自動將雜湊表的所有鍵值對匯入當前範圍。在上面的示例中,可以使用extract(_GET,EXTR_OVERWRITE)來匯入使用HTTP get方法提交的資料。要訪問 $name
欄位,現在只需鍵入 $name
,某些人更喜歡 $_GET['name']
。
但是,這些便利性具有安全隱患:
1.SQL注入變得簡單:
Java中的繫結變數可以確保程式設計師傳遞給SQL查詢的任何資料都是資料。對於PHP示例,不能說同樣的情況,來自惡意攻擊者的格式錯誤的資料可能會改變SQL語句的含義並導致對資料庫的意外操作。這些通常稱為SQL注入攻擊。
在上面的示例中(情況1),假設 $userid
由攻擊者控制並具有值’ OR ‘1’ = ‘1 ,查詢字串變為
UPDATE users SET pass=’...’ WHERE userid=’’ OR ’1’=’1’
它具有更新資料庫中所有使用者的密碼的效果
2.隱式轉換:
請看一下
人們會期望,如果程式列印任何東西,它應該是“0”。不幸的是,PHP在將字串值與整數進行比較之前會隱式地將其轉換為數字。非數值(例如,“abc”)在沒有投訴的情況下轉換為0,因此上面的程式碼可以列印除非零數字之外的任何內容。如果隨後使用 $userid
,我們可以想象一個潛在的SQL注入漏洞
3.使用者控制下的未初始化變數:
在PHP中,未初始化的變數預設為null。有些程式依靠這個事實來做出正確的行為;考慮以下程式碼:
extract($_GET, EXTR_OVERWRITE); for ($i=0;$i<=7;$i++) $new pass .= chr(rand(97, 122)); // append one char mysql query("UPDATE . . . $new_pass . . .");
該程式生成隨機密碼並將其插入資料庫。但是,由於第1行的提取操作,惡意使用者可以通過在提交的HTTP表單資料中新增意外的新傳遞欄位來為$new_pass引入任意初始值。
CFG := build control flow graph(AST); foreach (basic block b in CFG) summaries[b] := simulate block(b); return make function summary(CFG, summaries);
分析
給定一個PHP原始檔,我們的工具按以下步驟執行靜態分析:
(1)我們將PHP源解析為 抽象語法樹(AST) 。我們的解析器基於PHP 5.0.5的標準開源實現。每個PHP原始檔都包含一個主要部分(以下稱為主要部分,雖然它不是任何函式定義的一部分)和零個或多個使用者定義的函式。我們將使用者定義的函式儲存在環境中, 並從main函式開始分析 。
(2)單個函式的分析總結在上面 CFG 的程式碼示例中。對於程式中的每個函式, 分析執行從函式體的抽象語法樹(AST)到控制流圖(CFG)的標準轉換。 CFG的節點是基本塊:最大單個條目,單個退出語句序列。CFG的邊緣是塊之間的跳轉關係。對於條件跳轉,相應的CFG邊緣用分支謂詞標記。
(3)使用 符號執行 來模擬每個基本塊。目標是理解塊中語句對程式全域性狀態的集體影響,並將它們的效果總結為簡明的塊概要(其中描述了在進入塊之前必須清理的變數集3)。 。我們在3.1節描述了模擬演算法。
(4)在計算每個基本塊的摘要之後, 我們使用標準可達性分析將塊摘要組合成函式摘要。 函式摘要描述了函式的前後條件(例如,在呼叫當前函式之後的一組已清理的輸入變數)。我們將在3.2節討論這一步驟。
(5)在分析函式期間,我們可能會遇到對 其他使用者定義函式的呼叫 。我們將在3.3節討論建模函式呼叫以及函式分析的順序。
模擬基本塊
概述
圖2給出了虛擬碼,概述了符號模擬過程。
回想一下每個基本塊包含一個線性的語句序列,中間沒有跳躍或跳躍目標。模擬以初始狀態開始,其將每個變數x對映到符號初始值x0。它按順序處理塊中的每個語句,更新模擬器狀態以反映該語句的效果。模擬繼續進行,直到遇到以下任何一種情況:
1.塊的結束;
2.返回宣告。在這種情況下,當前塊被標記為返回塊,並且模擬器評估並記錄返回值;
3.退出宣告。在這種情況下,當前塊被標記為出口塊;
4.呼叫退出程式的使用者定義函式。使用被叫方的功能摘要自動確定此條件(參見第3.2和3.3節)。
請注意,在最後一種情況下,程式的執行也已終止,因此我們從當前塊中刪除任何後續語句和傳出CFG邊緣。
在模擬基本塊之後,我們使用模擬器最終狀態中包含的資訊來概括塊對塊彙總的影響,我們將其儲存在過程內分析中使用(參見第3.2節)。模擬後,狀態本身被丟棄。
以下小節詳細描述了模擬過程。我們首先定義我們建模的PHP子集(第3.1.2節),並討論在符號執行期間模擬狀態和程式值(第3.1.3節,第3.1.4節)的表示。使用值表示,我們描述了分析器如何模擬表示式(§3.1.5)和語句(§3.1.6)。最後,我們描述我們如何表示和推斷塊摘要(第3.1.7節)。
語言
圖3給出了一個 小命令式語言的定義,該語言捕獲了我們認為與SQL注入漏洞相關的PHP構造的子集 。與PHP一樣,語言是動態型別的。我們 模擬三種基本型別的PHP值:字串,布林值和整數。
另外,我們介紹一個特別的用於描述靜態型別未確定的物件的型別(例如,輸入引數)
表示式可以是常量,l-value,一元和二元運算以及型別轉換。值得一提的是左值的定義,因為除了變數和函式引數之外,我們還包含一個命名的下標操作,以便對PHP程式中廣泛使用的陣列和雜湊表訪問提供有限的支援。
語句可以是賦值,函式呼叫,返回,退出或包含。前四種語句型別無需進一步說明。
include語句是指令碼語言獨有的常用功能,它允許程式設計師動態地將程式碼插入到程式中。在我們的語言中,include計算其字串引數,並執行由字串指定的程式檔案,就像它插入該程式點一樣(例如,它共享相同的範圍)。我們將在3.1.6節描述如何模擬這種行為。
陳述
圖4(a)給出了模擬過程中值和狀態的定義。模擬狀態將儲存器位置對映到它們的值表示,其中儲存器位置是程式變數(例如x),或者是通過另一個位置(例如x[key])訪問的散列表中的條目。 請注意,位置的定義是遞迴的,因此我們的演算法支援多級雜湊解引用。
在進入函式時,每個位置L被隱式初始化為符號初始值L0,其構成模擬的初始狀態。我們在狀態中表示的值可以根據型別分為三類:
字串:
字串是許多指令碼語言中最基本的型別,建模字串的精度直接決定了分析的精確度。字串通常通過串聯構造。例如,使用者輸入(通過HTTP get和post方法)通常與預先構造的骨架連線以形成SQL查詢。同樣,查詢的結果可以與HTML模板連線以形成輸出。對連線進行建模可以使分析更好地理解指令碼中的資訊流。因此,我們的字串表示基於連線。字串值表示為字串段的有序串聯,可以是以下之一:字串常量,進入當前塊(l0)時的記憶體位置的初始值,或包含初始值零的字串來自一組記憶體位置的更多元素(包含(σ))。我們使用最後一個表示來模擬函式呼叫的返回值,這些函式呼叫可能不確定地包含全域性變數和輸入引數的組合。例如,在
function f($a, $b) { if (. . .) return $a; else return $b; } $ret = f($x.$y, $z);
我們將第5行的返回值表示為包含({x,y,z}),以模擬它可以包含集合中的任何元素作為子字串的事實。
上面描述的字串表示具有以下好處:
首先,我們獲得當前塊內的字串的自動常量摺疊,這通常用於解析雜湊鍵和區分雜湊引用(例如,在 $key
= “key”中;return $hash[$key]
)。
其次,我們可以通過在後者的最終表示中查詢前者的初始值的出現來跟蹤一個輸入變數的內容如何流入另一個輸入變數。例如,在: $a
= $a
. $b
, $a
的最終表示是 <a0,b>
我們知道如果 $a
或 $b
在進入當前塊時包含未經過授權的使用者輸入,退出時 $a
也是如此。
最後,通過使用contains(σ)跟蹤基於函式摘要的函式返回值,可以實現過程間資料流。我們在3.3節中更詳細地描述了這個方面。
布林值:
在PHP中,執行輸入驗證的常用方法是呼叫一個返回true或false的函式,具體取決於輸入是否格式正確。例如,以下程式碼清理 $userid
:
$ok = is safe($userid); if (!$ok) exit;
呼叫後布林變數 $ok
的值未確定,但它與 $userid
的安全性相關。這激發瞭解釋(σ0,σ1)作為此類布林值的表示:σ0(相應的σ1)表示布林值為假時的有效l值的集合(resp,true)。在上面的示例中, $ok
表示untaint({},{userid})
除此之外,布林的代表還包括常量(true and false)和 unknown
整數:
我們的模擬中不太強調整數運算。我們跟蹤整數常量以及它們之間的二元和一元運算。我們還支援從整數到布林值和字串值的型別轉換。
位置和L值
在圖3中的語言定義中,雜湊引用可以通過賦值進行別名,而L值可以包含具有非常量鍵的雜湊訪問。取決於主機和金鑰的值,相同的L值可以指代不同的儲存器位置,因此,L值不適合作為模擬狀態中的儲存器位置。
圖4(b)給出了我們用於將L值解析為記憶體位置的規則。
var和arg規則將每個程式變數和函式引數對映到由其名稱標識的記憶體位置,並且dim規則通過首先將雜湊表評估到位置然後附加金鑰以形成雜湊條目位置從而解析雜湊訪問。這些規則旨在在存在簡單別名的情況下工作。考慮以下程式:
$hash = $_POST; $key = ’userid’; $userid = $hash[$key];
該程式首先為雜湊表$_POST建立一個別名( $hash
),然後使用該別名訪問userid條目。在進入塊時,初始狀態將每個位置對映到其初始值:
根據var規則,每個變數對映到其自己的唯一位置。在前兩個任務之後,狀態是:
我們使用dim規則解決第3行的 $hash[$key]
: $hash
計算為 _POST0
, $key
計算為常量字串’userid’。因此,L值 $hash[$key]
計算到位置_POST[userid],因此分析將所需值 _POST[userid]0
分配給 $userid
。
表達
我們基於上述值表示執行表示式的抽象評估。由於PHP是一種動態型別語言,因此運算元會隱式轉換為表示式中的操作的適當型別。
圖4(c)給出了模擬PHP中的強制轉換操作的強制轉換規則的代表性示例。例如,布林值true,在字串上下文中使用時,計算結果為“1”。另一方面,false被轉換為空字串而不是“0”。在無法精確表示的情況下,結果是unknown
圖4(c)還給出了三種用於評估表示式的代表性規則。第一個規則處理L值,並通過首先將L值解析為記憶體位置,然後在評估上下文中查詢位置(在進入塊時回想起Γ(L)= L0)來獲得結果。
第二個規則模擬字串連線。我們首先將兩個運算元的值轉換為字串值,結果是兩者的串聯。
最終規則處理布林否定。有趣的案例涉及不明確的值。回想一下,如果對集合σ0(相應的σ1)中的L值進行消毒,則untaint(σ0,σ1)表示未知的布林值,該值為false(resp.true)。根據這個定義,unaint(σ0,σ1)的否定是不明確的(σ1,σ0)。
表示式的分析是不明確的,如果我們無法確定更精確的表示,這可能是漏報的潛在來源。
實驗結果
第3節中描述的分析 已經實現為兩個獨立的部分 :基於開源PHP5.0.5發行版的前端, 將原始檔解析為抽象語法樹 ,以及用OCaml編寫的後端, 將AST讀入記憶體並進行分析 。這種分離可確保最大的相容性,同時最小化對PHP 實現的依賴。
在intrablock,intraprocedural和interprocedural級別中使用不同抽象級別的決定使我們能夠微調我們保留在一個級別的資訊量,而不依賴於另一個級別的演算法,並允許我們快速構建可用工具。
檢查器很大程度上是自動的,幾乎不需要人為干預。我們使用一小組查詢函式(例如mysql查詢)和清理操作(例如,數字)來為檢查器播種。檢查員自動推斷其餘部分。
正則表示式匹配對自動化提出了挑戰。正則表示式用於各種目的,包括但不限於輸入驗證。
一些正則表示式匹配格式良好的輸入,而其他正則表示式檢測格式錯假設一種方式或另一種方式導致誤報或漏報。
我們的解決方案是 維護一個先前看到的正則表示式及其效果的資料庫 (如果有的話)。
預設情況下,以前看不見的正則表示式假定沒有過濾效果,以免因錯誤判斷而錯過任何錯誤。為了使使用者能夠輕鬆指定正則表示式的清理效果,檢查器具有互動模式,當分析遇到以前看不見的正則表示式時會提示使用者,並記錄使用者的答案以供將來參考
使用者宣告正則表示式的規則有將錯誤引入分析的真正潛力;然而,實際上,我們發現這種方法非常有效,它幫助我們找到至少兩個由於過於寬鬆的正則表示式而導致的漏洞。
們的工具在所有實驗中收集了來自使用者的49個正則表示式的資訊(使用者回答每次查詢一次擊鍵),因此使用者的負擔很小。
檢查器通過使用主函式摘要中的資訊來檢測錯誤 - 檢查器將所有在進入時需要被檢測的變數標記為潛在的安全漏洞 。從檢查器的角度來看,這些變數在環境中定義,用於構造SQL查詢而不進行清理。但實際上,這些變數要麼由執行時環境定義,要麼由檢查器不完全理解的某些語言結構定義(例如,我們在下面的案例研究中描述的PHP中的提取操作)。該工具發出錯誤資訊,如果已知變數由使用者控制(例如 $_GET['...']
, $_POST ['...']
, $_COOKIE['...']
等)。對於其他,檢查器會發出警告。
案例研究:PHP融合中的兩個可利用的SQL注入攻擊
在本節中,我們將展示兩個關於PHP融合中可利用SQL注入漏洞的案例研究
我們的工具。 PHP-fusion是一個基於PHP和MySQL的開源內容管理系統(CMS)。它不包括特定於語言環境的自定義模組,它包含超過16,000行PHP程式碼,並且由於其速度,可定製性和豐富的功能而具有廣泛的使用者群。
瀏覽程式碼時,很明顯, 作者在編寫安全性時考慮了安全性,並且在使用查詢字串之前已經特別注意清理輸入
我們的實驗是在最新的6.00.204版軟體上進行的。與我們檢查的其他程式碼庫不同,PHP-fusion使用提取操作將使用者輸入匯入當前環境。例如, extract($_POST,EXTR_OVERWRITE)
具有將 $_POST
雜湊表中的每個鍵的一個變數引入當前範圍,並將 $_POST[key]
的值賦給該變數的效果。此功能減少了鍵入,但會導致檢查器和安全漏洞混淆到軟體中我們構建的兩個漏洞都涉及使用未初始化的變數,其值可以由使用者操作,因為提取操作。
由於PHP-fusion不直接從輸入雜湊值(如 $_GET
or $_POST
)讀取使用者輸入,因此我們的工具不會生成直接的錯誤訊息。相反,我們檢查警告(回想上面關於錯誤和警告的討論),這些警告對應於安全敏感變數,其定義未被檢查器解析(例如,通過提取操作引入,或從配置檔案中讀取)。
我們在PHPfusion中的所有頂級指令碼上運行了我們的檢查器。
該工具生成了22個唯一的警告,其中大部分與構建大量查詢時使用的配置變數相關過濾掉後,4個不同檔案中的7個警告仍然存在。我們相信7個警告中除了一個之外的所有警告都可能導致可利用的安全漏洞。唯一的誤報來自於意外的過濾:
arises from an unanticipated sanitization: /* php-files/lostpassword.php */ if (!preg match("/ˆ[0-9a-z]{32}$/", $account)) $error = 1; if (!$error) { /* database access using $account */ } if ($error) redirect("index.php");
程式不是根據 preg_match 的結果立即終止程式,而是將 $error
標誌設定為true並延遲錯誤處理,這通常不是一個好習慣。可以通過在塊摘要中新增更多資訊來處理這個習慣用法。我們調查了剩餘的潛在攻擊警告的前兩個,並確認兩者在測試安裝中確實可以利用
不出所料由於提取操作,兩個錯誤都成為可能。我們在下面詳細解釋這兩個錯誤
1)用於恢復丟失密碼的指令碼中的漏洞
這是一個可遠端利用的漏洞,允許任何註冊使用者通過精心構建的URL提升其許可權。我們在下面顯示相關程式碼:
/* php-files/lostpassword.php */ for ($i=0;$i<=7;$i++) $new pass .= chr(rand(97, 122)); . . . $result = dbquery("UPDATE ".$db prefix."users SET user_password=md5(’$new_pass’) WHERE user_id=’".$data[’user_id’]."’");
我們的工具發出了 $new_pass
的警告,在進入時未初始化,因此在正常執行期間預設為空字串。該指令碼繼續向 $new_pass
(第23行)新增七個隨機生成的字母,並將其用作使用者的新密碼(第5-7行)。正常執行下的SQL請求採用以下形式:
UPDATE users SET user password=md5(’???????’) WHERE user id=’userid’
但是,惡意使用者只需將新的傳遞欄位新增到其HTTP請求中,例如,將以下字串附加到密碼提醒站點的URL:
&new_pass=abc%27%29%2cuser_level=%27103%27%2cuser_aim=%28%27
上面描述的提取操作將在當前變數範圍內神奇地引入 $new_pass
,並帶有以下初始值:
abc'), user level ='103', user aim = ('
SQL請求現在構造為:
UPDATE users SET user password=md5(’abc’), user level=’103’, user aim=(’???????’) WHERE user id=’userid’
這裡密碼設定為 “abc”,使用者許可權提升到103,這意味著”超級管理員”。新推出的使用者現在可以自由操作網站上的任何內容。
2)訊息傳遞子系統中的漏洞
此漏洞利用了另一種可能未初始化的變數 $result
的使用,其中訊息傳遞子系統中的訊息ID。我們在圖5中顯示相關程式碼。
我們的工具警告在訊息ID中未使用 $result
的結果。在正常輸入時,程式使用級聯if語句初始化 $result
where message id。如程式碼所示,作者非常謹慎地清理用於構造訊息id的 $result
的值。但是,if語句的級聯序列沒有預設分支。因此, $result
可能在格式錯誤的輸入上未初始化訊息ID。我們利用這個事實,並追加
&request where message id=1=1/*
因此,在第11-13行提交的查詢字串變為:
DELETE FROM messages WHERE 1=1 /* AND . . .
無論如何,”/ *:”在MySQL中被視為註釋,因此被忽略。結果是丟失了系統中的所有私人訊息。由於複雜的控制和資料流,不太可能通過程式碼審查或測試發現此錯誤。
我們向PHP-fusion的作者報告了這兩個漏洞,他們立即修復了這些漏洞併發布了該軟體的新版本。
相關工作
靜態技術
WebSSARI是一種基於型別的PHP分析器 。它使用簡單的過程內汙點分析來查詢使用者控制的值流入需要可信輸入的函式(即敏感函式)的情況 。該分析依賴於三個使用者編寫的“前奏”檔案來提供有關以下方面的資訊:
1)所有敏感功能的集合 - 需要過濾輸入;
2)所有無操作的操作集;
3)不可信輸入變數的集合。
不完整的規範導致大量的誤報和漏報。
####WebSSARI有幾個關鍵限制,限制了工具的精度和分析能力:
WebSSARI使用過程內演算法,因此僅模擬不跨越功能邊界的資訊流。
大型PHP程式碼庫通常使用少量系統庫函式(例如,mysql_query)定義處理常見操作(例如,查詢字串構造,認證,清理等)的許多應用程式特定子例程。 我們的演算法能夠自動推斷這些使用者定義函式的資訊流和前後條件 ,而WebSSARI依賴於使用者來指定每個使用者的約束,這是每個檢查的原始碼庫需要重複的重大負擔。 3.3節中的示例表示WebSSARI無法在沒有註釋的情況下進行建模的一些常見使用者定義函式形式。
為了顯示過程間分析有多少提高了分析的準確性,我們關閉了函式摘要,並重復了我們在News Pro上的實驗,這是五個程式碼庫中最小的一個。這一次,分析產生了19條錯誤訊息(而不是8條過程間分析)。
經檢查,由於使用者定義的清理操作,所有11個額外報告都是誤報。
WebSSARI似乎沒有對條件分支進行建模,條件分支代表了我們分析的指令碼中最常見的清理形式之一
例如,我們認為它將在以下程式碼上報告錯誤警告:
if (!is numeric($ GET[’x’])) exit; mysql query(‘‘. . . $ GET[’x’] ...’’);
此外,過程間條件清理(參見3.1.6節中的示例)在程式碼庫中也很常見。
WebSSARI使用基於靜態型別的演算法,該演算法不專門為指令碼中的動態特徵建模。
例如,動態型別可能會引入WebSSARI錯過的細微錯誤。在PHP指令碼中廣泛使用的include語句動態地將程式碼插入到程式中,該程式碼可能包含,誘導或防止錯誤。
Livshits和Lam 開發了一個靜態檢測器,用於Java應用程式中的安全漏洞(例如,SQL注入,跨站點指令碼等)。該演算法使用基於BDD的上下文敏感指標分析來發現從不可信源(例如,使用者輸入)到信任接收器(例如,SQL查詢)的潛在流。此分析的一個限制是它不會對程式中的控制流進行建模,因此可能會錯誤標記隨後流入SQL查詢的已清理輸入。使用條件分支的清理在PHP程式中很常見,因此忽略控制流的技術可能會在此類程式碼庫中導致大量誤報。
其他在C程式碼上證明有效的汙點分析包括CQual,MECA 和MC。他們總共在Linux核心中發現了數百個以前未知的安全錯誤。
克里斯滕森等人開發一個字串分析, 使用無上下文語法來近似Java程式中的字串值 。結果擴充套件為常規語言,並根據預期輸出的規範進行檢查,以確定語法正確性。但是,語法正確性並不需要安全性,因此不清楚如何使這項工作適應SQL注入漏洞的檢測。
Minamide擴充套件了該方法, 併為PHP構建了一個字串分析器 ,引用了SQL注入檢測作為一種可能的應用程式。但是,分析器在PHP中模擬一小組字串操作(例如,連線,字串匹配和替換),並忽略更復雜的功能,如動態型別,轉換和謂詞。此外,框架似乎只是用字串替換來模擬清理,字串替換代表實際程式碼中所有清理的一小部分。因此,準確精確定位注射攻擊仍然具有挑戰性。
古爾德等人 將字串分析與型別檢查相結合 ,不僅可以確保語法正確性,還可以確保Java程式構造的SQL查詢的型別正確性。但是,型別正確性並不意味著安全性,這是我們分析的重點。
動態技術
Scott和Sharp 提出了一個應用級防火牆來集中客戶端輸入的清理。防火牆產品也可以從NetContinuum,Imperva,Watchfire等公司商購。
其中一些防火牆檢測並防範先前已知的攻擊模式,而其他防火牆則保留有效輸入的白名單。這裡的主要限制是前者容易受到誤報和漏報,後者依賴於正確的規範,這很難得到。
Perl汙染模式在不安全的環境中執行期間啟用一組特殊的安全檢查。它防止在需要可信輸入的操作(例如,呼叫子shell的任何命令)中使用不受信任的資料(例如,所有命令列引數,環境變數,從檔案讀取的資料等)。
Nguyen-Tuong 提出了PHP的汙點模式, 與Perl汙點模式不同,它不定義清理操作。相反, 它會單獨跟蹤使用者輸入中的每個字元,並使用一組啟發式方法來確定查詢在包含使用者輸入片段時是否安全 。例如,如果操作符號(例如,“(”,“)”,“%”等)被標記為汙染,則它檢測注入。
這種方法容易受到誤報和影響。請注意,靜態分析也容易受到誤報和漏報的影響。關鍵的區別在於,在靜態分析中,不準確性在編譯時解決,而不是在執行時解決,這是不太容忍的。
結論
我們提出了一種靜態分析演算法,用於檢測PHP中的安全漏洞。我們的分析採用了一種新穎的三層架構,使我們能夠處理指令碼語言獨有的動態特性,如動態型別和程式碼包含。我們通過在六個流行的開源PHP程式碼庫上執行我們的工具並找到105個以前未知的安全漏洞來證明我們的方法的有效性,其中大多數我們認為這些漏洞是可遠端利用的。
個人總結
本文提出了一種新型的以三層結構方式(內部快,過程內,過程間)來靜態分析PHP 程式碼中的漏洞
工具分析的流程:
(1)PHP 原始碼解析為抽象語法樹
(2)將抽象語法樹轉化成控制流圖
(3)使用符號執行的方式去模擬每個基本塊,觀察其對全域性的作用,寫出塊摘要
(4)利用可達性分析,將塊摘要組合成函式