0x00 內容簡介
01 PHP代碼執行函數
02 包含函數
03 命令執行函數
04 文件操作函數
05 特殊函數
0x01 PHP代碼執行函數
1. eval
2. assert
3. preg_replace
主要是/e修正符使preg_replace()將replacement參數當做PHP代碼
4. create_function
它看着很香,但是PHP高版本已經廢除了它,從PHP 7.2.0
開始,create_function()
被廢棄
5. call_user_func
調用test函數,傳入virink,輸出
這里就造成了命令執行
0x02 文件包含“函數”
1. include()
語法:include(/path/to/filename)
include()語句將在其被調用的位置處包含一個文件。包含一個文件與在該語句所在位置復制制定文件的數據具有相同內容的效果。
使用include()時可以忽略括號。
可以根據條件來執行include()語句。在條件語句中使用include()有個怪現象,它必須包圍在語句塊大括號中,或者用其他語句包圍符括起來。
2.require()
語法:require(filename)
require()在很大程度上與include相同,都是將一個模板文件包含到require調用坐在的位置。
require和include之間有兩點重要的區別。首先,無論require的位置如何,制定文件都將包含到出現require的腳本中。例如,即使require放在計算結果為假的if語句中,依然會包含指定文件。
第二個重要的區別是:require出錯時,腳本將停止運行,而在使用include的情況下,腳本將繼續執行。
ps:
include和require都是語句結構(並不是函數)
所以,它可以不加圓括號,直接加引號來包含文件。我習慣不加圓括號。
1 include '01_var.php'; 2 或者 3 include('01_var.php'); 4 或者 5 require '01_var.php'; 6 或者 7 require('01_var.php');
3. include_once()
語法:include_once(filename)
include_once() 語句在腳本執行期間包含並運行指定文件。此行為和 include() 語句類似,唯一區別是include_once()會先判斷一下這個文件在之前是否已經被包含過,如已經包含,則忽略本次包含。
include_once() 應該用於嵌套包含的情況下,想確保它只被包含一次以避免函數重定義,變量重新賦值等問題。
小結:include_once()函數的作用與include相同,不過它會首先驗證是否已經包含了該文件。如果已經包含,則不再執行include_once。否則,則必須包含該文件。除了這一點與include完全相同。
4、require_once()
語法:require_once(filename)
require_once() 語句在腳本執行期間包含並運行指定文件。此行為和 require() 語句類似,唯一區別是require_once()會先判斷一下這個文件在之前是否已經被包含過,如已經包含,則忽略本次包含。
require_once() 應該用於嵌套包含的情況下,想確保它只被包含一次以避免函數重定義,變量重新賦值等問題。
0x03 命令執行函數
命令注入(Command Injection
),對一些函數的參數沒有做過濾或過濾不嚴導致的,可以執行系統或者應用指令(CMD
命令或者 bash
命令)的一種注入攻擊手段。
常見的執行系統命令的函數有
1 system() 2 passthru() 3 exec() 4 shell_exec() 5 popen() 6 proc_open() 7 pcntl_exec()
1. system()函數
string system ( string $command [, int &$return_var ] )
$command為執行的命令,&return_var可選,用來存放命令執行后的狀態碼
system()函數執行有回顯,將執行結果輸出到頁面上
1 <?php 2 system("whoami"); 3 ?>
2. passthru()函數
void passthru ( string $command [, int &$return_var ] )
和system函數類似,$command為執行的命令,&return_var可選,用來存放命令執行后的狀態碼
執行有回顯,將執行結果輸出到頁面上
1 <?php 2 passthru("whoami"); 3 ?>
3. exec()
string exec ( string $command [, array &$output [, int &$return_var ]] )
$command是要執行的命令
$output
是獲得執行命令輸出的每一行字符串,$return_var
用來保存命令執行的狀態碼(檢測成功或失敗)
exec()函數執行無回顯,默認返回最后一行結果
1 <?php 2 echo exec("whoami"); 3 ?>
1 <?php 2 $test = "ipconfig"; 3 exec($test,$array); 4 print_r($array); 5 ?>
4. shell_exec()函數
string shell_exec( string &command)
&command是要執行的命令
shell_exec()函數默認無回顯,通過 echo 可將執行結果輸出到頁面
1 <?php 2 echo shell_exec("whoami"); 3 ?>
反引號 `
shell_exec() 函數實際上僅是反撇號 (`) 操作符的變體,當禁用shell_exec時,` 也不可執行
在php中稱之為執行運算符,PHP 將嘗試將反引號中的內容作為 shell 命令來執行,並將其輸出信息返回
1 <?php 2 echo `whoami`; 3 ?>
5. popen()函數
resource popen ( string $command , string $mode )
函數需要兩個參數,一個是執行的命令command,另外一個是指針文件的連接模式mode,有r和w代表讀和寫。
函數不會直接返回執行結果,而是返回一個文件指針,但是命令已經執行。
popen()打開一個指向進程的管道,該進程由派生給定的command命令執行而產生。
返回一個和fopen()所返回的相同的文件指針,只不過它是單向的(只能用於讀或寫)並且必須用pclose()來關閉。
此指針可以用於fgets(),fgetss()和 fwrite()
1 <?php popen( 'whoami >> c:/1.txt', 'r' ); ?>
1 <?php 2 $test = "ls /tmp/test"; 3 $fp = popen($test,"r"); //popen打一個進程通道 4 5 while (!feof($fp)) { //從通道里面取得東西 6 $out = fgets($fp, 4096); 7 echo $out; //打印出來 8 } 9 pclose($fp); 10 ?>
6. proc_open()函數
1 resource proc_open ( 2 string $cmd , 3 array $descriptorspec , 4 array &$pipes [, string $cwd [, array $env [, array $other_options ]]] 5 )
與popen函數類似,但是可以提供雙向管道
1 <?php 2 $test = "ipconfig"; 3 $array = array( 4 array("pipe","r"), //標准輸入 5 array("pipe","w"), //標准輸出內容 6 array("pipe","w") //標准輸出錯誤 7 ); 8 9 $fp = proc_open($test,$array,$pipes); //打開一個進程通道 10 echo stream_get_contents($pipes[1]); //為什么是$pipes[1],因為1是輸出內容 11 proc_close($fp); 12 ?>
7. pcntl_exec()函數
void pcntl_exec ( string $path [, array $args [, array $envs ]] )
path是可執行二進制文件路徑或一個在文件第一行指定了 一個可執行文件路徑標頭的腳本
args是一個要傳遞給程序的參數的字符串數組。
pcntl是linux下的一個擴展,需要額外安裝,可以支持 php 的多線程操作。
pcntl_exec函數的作用是在當前進程空間執行指定程序,版本要求:PHP > 4.2.0
1 <?php 2 3 pcntl_exec ( "/bin/bash" , array("whoami")); 4 5 ?>
對這些危險函數,可以在php.ini中禁用,進行安全加固
0x04 文件操作函數
1. fopen() 打開文件或者 URL
fopen ( string $filename , string $mode [, bool $use_include_path = false [, resource $context ]] ) : resource
1 $handle = fopen("/home/rasmus/file.txt", "r"); 2 $handle = fopen("/home/rasmus/file.gif", "wb"); 3 $handle = fopen("http://www.example.com/", "r"); 4 $handle = fopen("ftp://user:password@example.com/somefile.txt", "w");
2. copy()復制文件
copy ( string $source , string $dest [, resource $context ] ) : bool
echo copy("要復制的文件路徑/鏈接.txt","target.txt");//bool(true/false)
3. fclose 關閉一個已打開的文件指針
fclose ( resource $handle ) : bool
$handle = fopen('somefile.txt', 'r'); fclose($handle);
4. feof() 測試文件指針是否到了文件結束的位置
feof ( resource $handle ) : bool
1 $file = fopen("demo.txt", "r"); 2 3 //輸出文本中所有的行,直到文件結束為止。 4 while(!feof($file)) 5 { 6 echo fgets($file); 7 } 8 9 fclose($file);
5. fgetc 從文件指針中讀取一個字符
fgetc ( resource $handle ) : string
1 $file = fopen("demo.txt", "r"); 2 echo fgetc($file);//t
6. fgets 從文件指針中讀取一行
fgets ( resource $handle [, int $length ] ) : string
1 $file = fopen("demo.txt", "r"); 2 echo fgets($file,2048);//this is demo.txt 1
7. file() 把整個文件讀入一個數組中
file ( string $filename [, int $flags = 0 [, resource $context ]] ) : array
8. file_get_contents () 將整個文件讀入一個字符串
file_get_contents ( string $filename [, bool $use_include_path = false [, resource $context [, int $offset = -1 [, int $maxlen ]]]] ) : string
9. file_put_contents 將一個字符串寫入文件
file_put_contents ( string $filename , mixed $data [, int $flags = 0 [, resource $context ]] ) : int 該函數將返回寫入到文件內數據的字節數,失敗時返回FALSE
10. unlink() 刪除文件
若成功,則返回 true,失敗則返回 false。
11. rename() 函數重命名文件或目錄
12. mkdir() 創建目錄
若成功,則返回 true,否則返回 false。
13. move_uploaded_file() 將上傳的文件移動到新位置
若成功,則返回 true,否則返回 false。
14. rmdir() 刪除空目錄
只能刪除空的目錄 且不能遞歸刪除
15. scandir() 列出指定路徑中的文件和目錄
scandir ( string $directory [, int $sorting_order [, resource $context ]] ) : array
總結:
0x05 特殊函數
1. phpinfo()
信息泄漏
bool phpinfo ([ int $what = INFO_ALL ] )
輸出 PHP 當前狀態的大量信息,包含了 PHP 編譯選項、啟用的擴展、PHP 版本、服務器信息和環境變量(如
果編譯為一個模塊的話)、PHP環境變量、操作系統版本信息、path 變量、配置選項的本地值和主值、HTTP
頭和PHP授權信息(License)。
2. symlink(),symlink()
軟連接-讀取文件內容
bool symlink ( string $target , string $link )
symlink() 對於已有的 target 建立一個名為 link 的符號連接。
string readlink ( string $path )
readlink() 和同名的 C 函數做同樣的事,返回符號連接的內容。
3. getenv(),putenv()
環境變量
string getenv ( string $varname )
獲取一個環境變量的值。
bool putenv ( string $setting )
添加 setting 到服務器環境變量。 環境變量僅存活於當前請求期間。 在請求結束時環境會恢復到初始狀態。
4. dl()
加載擴展
bool dl ( string $library )
載入指定參數 library 的 PHP 擴展。
5. 配置相關
string ini_get ( string $varname )
成功時返回配置選項的值。
string ini_set ( string $varname , string $newvalue )
string ini_alter ( string $varname , string $newvalue )
設置指定配置選項的值。這個選項會在腳本運行時保持新的值,並在腳本結束時恢復。
void ini_restore ( string $varname )
恢復指定的配置選項到它的原始值。
6. 數字判斷
bool is_numeric ( mixed $var )
如果 var 是數字和數字字符串則返回 TRUE,否則返回 FALSE。
僅用is_numeric判斷而不用intval轉換就有可能插入16進制的字符串到數據庫,進而可能導致sql二次注入。
7. 數組相關
bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )
在 haystack 中搜索 needle,如果沒有設置 strict 則使用寬松的比較。
該函數有一個特性,比較之前會進行自動類型轉換。
$a = '1abc';
in_array($a,array(1,2,3))的返回值會是真
8. PHP變量覆蓋函數
void parse_str ( string $str [, array &$arr ] )
如果 str 是 URL 傳遞入的查詢字符串(query string),則將它解析為變量並設置到當前作用域。
int extract ( array &$var_array [, int $extract_type = EXTR_OVERWRITE [, string $prefix = NULL ]] )
本函數用來將變量從數組中導入到當前的符號表中。檢查每個鍵名看是否可以作為一個合法的變量名,同時也
檢查和符號表中已有的變量名的沖突。
bool mb_parse_str ( string $encoded_string [, array &$result ] )
解析 GET/POST/COOKIE 數據並設置全局變量。 由於 PHP 不提供原始 POST/COOKIE 數據,目前它僅能夠
用於 GET 數據。 它解析了 URL 編碼過的數據,檢測其編碼,並轉換編碼為內部編碼,然后設置其值為 array
的 result 或者全局變量。
bool import_request_variables ( string $types [, string $prefix ] )
將 GET/POST/Cookie 變量導入到全局作用域中。如果你禁止了 register_globals,但又想用到一些全局變
量,那么此函數就很有用。
9. 列目錄
array glob ( string $pattern [, int $flags = 0 ] )
glob() 函數依照 libc glob() 函數使用的規則尋找所有與 pattern 匹配的文件路徑,類似於一般 shells 所用的
規則一樣。不進行縮寫擴展或參數替代。
10. 無參數獲取信息
array get_defined_vars ( void )
返回一個包含所有已定義變量列表的多維數組,這些變量包括環境變量、服務器變量和用戶定義的變量。
array get_defined_constants ([ bool $categorize = false ] )
返回當前所有已定義的常量名和值。 這包含 define() 函數所創建的,也包含了所有擴展所創建的。
array get_defined_functions ( void )
返回一個包含所有已定義函數列表的多維數組
array get_included_files ( void )
返回所有被 include、 include_once、 require 和 require_once 的文件名。