掃描代碼漏洞Show Code Vulnerability Scanner這個工具能夠掃描PHP代碼中是否有存在漏洞。
說明:
PHP代碼漏洞可以有許多原因,其中很多可以歸因于部分程序員在開始寫代碼時候缺乏經(jīng)驗。這些漏洞被發(fā)現(xiàn)的話會導(dǎo)致數(shù)據(jù)丟失,危及網(wǎng)站的安全。
php漏洞原理:
PHP是一種服務(wù)器端的,嵌入HTML的腳本語言。PHP區(qū)別其他語言的地方是它的代碼在服務(wù)器端執(zhí)行,例如收集表格數(shù)據(jù),生成動態(tài)頁面內(nèi)容,或者收發(fā)cookies等,今天我們來了解一下它的漏洞問題。
一 全局變量
全局變量,就是能夠在整個程序執(zhí)行的過程中都存在的變量;赑HP的應(yīng)用程序的主函數(shù)一般都是接受用戶的輸入,然后對輸入數(shù)據(jù)進行處理,然后把結(jié)果返回到客戶端瀏覽器。為了使PHP代碼訪問用戶的輸入盡可能容易,實際上PHP是把這些輸入數(shù)據(jù)看作全局變量來處理的。
<form method="get" action="get.php">
<input type="text" name="test">
<input type="submit">
</form>
這段代碼會顯示一個文本框和提交按鈕。當(dāng)用戶點擊提交按鈕時,頁面就會將用戶輸入的數(shù)據(jù)傳遞到“get.php”,當(dāng)“get.php”運行時,“$test”就會自動創(chuàng)建,包含了用戶在文本框輸入的數(shù)據(jù)。我們可以看出,攻擊者可以按照自己的意愿創(chuàng)建任意的全局變量。下面的認證代碼暴露了PHP的全局變量所導(dǎo)致的安全問題:
<?php
if ($password == "monster")
$pass = 1;
……………
if ($pass == 1)
echo "認證通過";
?>
上面的代碼首先檢查用戶的密碼是否為“monster”,如果匹配的話,則設(shè)置“$pass”為“1”,之后如果“$pass”的值為“1”的話,就會認證通過。
從表面看起來,這是正確的,但是這段代碼犯了想當(dāng)然的錯誤,它假定“$pass”在沒有設(shè)置值的時候是空的,卻沒有想到,攻擊者可以創(chuàng)建任何全局變量并賦值,通過提交“http://server/get.php?pass=1”的方法,我們完全可以欺騙這段代碼,使它相信我們是已經(jīng)認證過的。
二 過濾輸入/輸出轉(zhuǎn)義
過濾是Web應(yīng)用安全的基礎(chǔ)。它是你驗證數(shù)據(jù)合法性的過程。通過在輸入時確認對所有的數(shù)據(jù)進行過濾,你可以避免未過濾數(shù)據(jù)在你的程序中被誤信及誤用。大多數(shù)流行的PHP應(yīng)用的漏洞最終都是因為沒有對輸入進行恰當(dāng)過濾造成的。最好的方法是把過濾看成是一個檢查的過程。
另外一個Web應(yīng)用安全的基礎(chǔ)是對輸出進行轉(zhuǎn)義或?qū)μ厥庾址M行編碼,以保證原意不變。例如,O'Reilly在傳送給MySQL數(shù)據(jù)庫前需要轉(zhuǎn)義成O\'Reilly。單引號前的反斜杠代表單引號是數(shù)據(jù)本身的一部分,而不是并不是它的本義。
為了區(qū)分數(shù)據(jù)是否已轉(zhuǎn)義,還是建議定義一個命名機制。對于輸出到客戶機的轉(zhuǎn)義數(shù)據(jù),使$html數(shù)組進行存儲,該數(shù)據(jù)首先初始化成一個空數(shù)組,對所有已過濾和已轉(zhuǎn)義數(shù)據(jù)進行保存。
<?php
$html = array( );
$html['username'] = htmlentities($clean['username'], ENT_QUOTES, 'UTF-8');
echo "<p>Welcome, {$html['username']}.</p>";
?>
htmlspecialchars( )函數(shù)與htmlentities( )函數(shù)基本相同,它們的參數(shù)定義完全相同,只不過是htmlentities( )的轉(zhuǎn)義更為徹底。
通過$html['username']把username輸出到客戶端,你就可以確保其中的特殊字符不會被瀏覽器所錯誤解釋。如果username只包含字母和數(shù)字的話,實際上轉(zhuǎn)義是沒有必要的,但是這體現(xiàn)了深度防范的原則。
SQL 注入是PHP應(yīng)用中最常見的漏洞之一,事實上,開發(fā)者需要同時犯以上兩個錯誤才會引發(fā)一個SQL注入漏洞。
三 遠程文件
PHP是一種具有豐富特性的語言,提供了大量的函數(shù),使編程者實現(xiàn)某個功能很容易。但是從安全的角度來看,功能越多,要保證它的安全性就越難,遠程文件就是說明這個問題的一個很好的例子:
<?php
if (!($fo = fopen("$file", "s"))
echo("文件$file打開錯誤 ");
?>
上面的腳本試圖打開文件“$filename”,如果失敗就顯示錯誤信息。那么如果我們能夠指定“$file”的話,就能利用這個腳本瀏覽任何文件。但是,這個腳本還存在一個不太明顯的特性,那就是它可以從任何其它WEB或FTP站點讀取文件。實際上,PHP的大多數(shù)文件處理函數(shù)對遠程文件的處理是透明的。
例如:
如果指定“$file”為“http://target/scripts/..%c1%1c../winnt/system32/cmd.exe?/c+dir”,則上面的代碼實際上是利用主機target上的unicode漏洞,執(zhí)行了dir命令。
這使得支持遠程文件的include(),require(),include_once()和require_once()在上下文環(huán)境中變得更有趣。這些函數(shù)主要功能是包含指定文件的內(nèi)容,并且把它們按照PHP代碼解釋。
例如:
<?php
include($dir."/ attack.php");
?>
上例中“$dir”一般是一個在執(zhí)行代碼前已經(jīng)設(shè)置好的路徑,如果攻擊者能夠使得“$dir”沒有被設(shè)置的話,那么他就可以改變這個路徑。但是攻擊者并不能做任何事情,因為他們只能在他們指定的路徑中訪問文件“attack.php”。但是由于有了對遠程文件的支持,攻擊者就可以做任何事情。例如,攻擊者可以在某臺服務(wù)器上放一個文件“attack.php”,里面包含了惡意代碼
然后把“$dir”設(shè)置為“http://evilhost/”,這樣我們就可以在目標(biāo)主機上執(zhí)行上面的惡意代碼,將結(jié)果返回到客戶的瀏覽器中。
需要注意的是,攻擊服務(wù)器(也就是evilhost)應(yīng)該不能執(zhí)行PHP代碼,否則攻擊代碼會在攻擊服務(wù)器,而不是目標(biāo)服務(wù)器執(zhí)行。
四 文件上載
PHP自動支持基于RFC 1867的文件上載,我們看下面的例子:
<form method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="hidden" name="maxfilesize" value="1024">
<input type="submit">
</form>
上面的代碼讓用戶從本地機器選擇一個文件,當(dāng)點擊提交后,文件就會被上載到服務(wù)器。這顯然是很有用的功能,但是PHP的響應(yīng)方式會使這項功能變的不安全。當(dāng) PHP在它開始解析被調(diào)用的PHP代碼之前,它會先接受遠程用戶的文件,檢查文件的長度是否超過 “$ maxfilesize variable”定義的值,如果通過這些測試的話,文件就會被存在服務(wù)器的一個臨時目錄中。
因此,攻擊者可以發(fā)送任意文件給運行PHP的主機,在PHP程序還沒有決定是否接受文件上載時,文件就已經(jīng)被保存在服務(wù)器上面了。
現(xiàn)在我們看一下處理文件上載的PHP程序,正如上面所說,文件被接收并且存在服務(wù)器上(位置一般是/tmp),文件名一般是隨機的。PHP程序需要上載文件的信息以便處理它,這可以通過兩種方式,一種方式是在PHP 3中已經(jīng)使用的,另一種是在我們對以前的方法提出安全公告后引入的。
但是,我們可以肯定的說,問題還是存在的,大多數(shù)PHP程序還是使用老的方式來處理上載文件。PHP設(shè)置了四個全局變量來描述上載文件,比如說上面的例子:
$file = Filename on local machine (e.g "/tmp/phpxXuoXG")
$file_size = Size in bytes of file (e.g 1024)
$file_name =遠程系統(tǒng)上的文件名(e.g "c:/file.txt")
$file_type = Mime type of uploaded file (e.g "text/plain")
然后PHP程序開始處理根據(jù)“$file”指定的文件,問題在于“$file”不一定是一個PHP設(shè)置的變量,任何遠程用戶都可以指定它。如果我們使用下面的方式:
http://vulnhost/file.php?file=/ ... file_name=file.txt
就導(dǎo)致了下面的PHP全局變量(當(dāng)然POST方式也可以(甚至是Cookie)):
$file = "/etc/passwd"
$file_size = 10240
$file_type = "text/plain"
$file_name = "file.txt"
上面的表單數(shù)據(jù)正好滿足了PHP程序所期望的變量,但是這時PHP程序不再處理上載的文件,而是處理“/etc/passwd”(通常會導(dǎo)致內(nèi)容暴露)。這種攻擊可以用于暴露任何敏感文件的內(nèi)容。
我 在前面已經(jīng)說了,新版本的PHP使用HTTP_POST_FILES[]來決定上載文件,同時也提供了很多函數(shù)來解決這個問題,例如有一個函數(shù)用來判斷某個文件是不是實際上載的文件。這些函數(shù)很好的解決了這個問題,但是實際上肯定有很多PHP程序仍然使用舊的方法,很容易受到這種攻擊。
作為文件上載的攻擊方法的一個變種,我們看一下下面的一段代碼:
<?php
if (file_exists($file))
include("$file");
?>
如 果攻擊者可以控制“$file”的話,很顯然它可以利用“$file”來讀取遠程系統(tǒng)上的任何文件。攻擊者的最終目標(biāo)是在遠程服務(wù)器上執(zhí)行任意指令, 但是他無法使用遠程文件,因此,他必須得在遠程服務(wù)器上創(chuàng)建一個PHP文件。這乍看起來好象是不可能的,但是文件上載幫了我們這個忙,如果攻擊者先在本地 機器上創(chuàng)建一個包含PHP代碼的文件,然后創(chuàng)建一個包含名為“file”的文件域的表單,最后用這個表單通過文件上載把創(chuàng)建的包含PHP代碼的文件提交 給上面的代碼,PHP就會把攻擊者提交的文件保存起來,并把“$file”的值設(shè)置為攻擊者提交的文件,這樣file_exists()函數(shù)會檢查通過,攻擊者的代碼也將執(zhí)行。
五 Session文件
PHP 4 以上的版本提供了對sessions的支持,它的主要作用是在PHP程序中保存頁與頁之間的狀態(tài)信息。例如,當(dāng)一個用戶登陸進入網(wǎng)站,他登陸了這個事 實以及誰登陸進入這個網(wǎng)站都被保存在session中,當(dāng)他在網(wǎng)站中到處瀏覽時,所有的PHP代碼都可以獲得這些狀態(tài)信息。
事實上, 當(dāng)一個session啟動時,就會生成一個隨機的“session id”,如果遠程瀏覽器總是在發(fā)送請求時提交這個“session id”的話,session就會一直保持。這通過Cookie很容易實現(xiàn),也可以通過在每頁提交一個表單變量來實現(xiàn)。PHP程序可以用session注冊一個特殊的變量,它的值會在每個PHP腳本結(jié)束后存在session文件中,也會在每個PHP腳本開 始前加載到變量中。下面是一個簡單的例子:
<?php
session_destroy();
$session_auth = "shaun";
session_register("session_auth");
?>
新版本的PHP都會自動把“$session_auth”的值設(shè)置為“shaun”,如果它們被修改的話,以后的腳本都會自動接受修改后的值,這對無狀態(tài)的Web來說的確是種很不錯的工具,但是我們也應(yīng)該小心。
一個很明顯的問題就是確保變量的確來自session,例如,給定上面的代碼,如果后續(xù)的腳本是下面這樣的話:
<?php
if (!empty($session_auth))
// Grant access to site here
?>
上面的代碼假定如果“$session_auth”被置位的話,就是從session,而不是從用戶輸入來置位的,如果攻擊者通過表單輸入來置位的話,他就 可以獲得對站點的訪問權(quán)。注意攻擊者必須在session注冊該變量之前使用這種攻擊方法,一旦變量被放進了session,就會覆蓋任何表單輸入。
Session 數(shù)據(jù)一般是保存在文件中,目錄一般是“/tmp”,文件名一般是類似 “sess_<session id>”的形式,這個文件包含變量名稱,變量類型,變量值和一些其它的數(shù)據(jù)。在多主機系統(tǒng)中,因為文件是以運行Web服務(wù)器的用戶身份保存的,因此惡意的站點擁有者就可以通過創(chuàng)建一個session文件來獲得對其它站點的訪問,甚至可以檢查session文件中的敏感信息。
常見的針對session的攻擊手段就是會話劫持。它是所有攻擊者可以用來訪問其它人的會話的手段的總稱。所有這些手段的第一步都是取得一個合法的會話標(biāo)識來偽裝成合法用戶,因此保證會話標(biāo)識不被泄露非常重要。