注:命令注入漏洞的分析,及含有命令注入漏洞的函數解析php
含有命令注入漏洞的函數:system()、exec()、passthru()、shell_exec()、``(與shell_exec()功能相同)linux
一、 函數用法
String shell_exec(string command)
command 要執行的命令
二、 low級別
源碼:shell
<?php if( isset( $_POST[ 'Submit' ] ) ) { // Get input $target = $_REQUEST[ 'ip' ]; // Determine OS and execute the ping command. if( stristr( php_uname( 's' ), 'Windows NT' ) ) { // Windows $cmd = shell_exec( 'ping ' . $target ); } else { // *nix $cmd = shell_exec( 'ping -c 4 ' . $target ); } // Feedback for the end user echo "<pre>{$cmd}</pre>"; } ?>
源碼分析:
函數首先判斷環境下的系統,若是是win則執行第一個命令,如果linux執行的命令加上-c選項,覺得linux中ping命令是一直執行的。只有加了-c指定發送的跳數才能中止。
能夠看到在接收用戶輸入的地方,對用戶的輸入沒有作任何的處理。不難看出這就是一個典型的命令注入漏洞。並且孩子是最輕易。
咱們正常測試一下:
能夠看到,正常返回的是ping返回的數據。
咱們經過這個命令執行漏洞進行測試一下:
構造咱們的語句:10.39.1.4 | net user
解釋: | 的意思是前面命令的輸出結果做爲後面命令的輸入。
net user 查看當前系統中存在哪些用戶
測試:
能夠看到當前系統中存在三個用戶。若是做爲×××去利用的話就可使用命令去建立一個用戶。就不在演示
漏洞分析:不處理用戶的任何輸入就直接執行函數中的命令。數組
知識擴展:
; - 分號在linux命令執行的時候,能夠直接執行幾條命令,命令與命令之間用分號隔開。
& 前面的命令執行後接着執行候命的命令
&& 前面的命令執行成功後才能夠執行下面的命令
| 前面的命令輸出結果最爲後面命令輸入的內容
|| 前面的命令執行失敗後纔會執行後面的命令瀏覽器
三、medium級別
源碼:安全
<?php if( isset( $_POST[ 'Submit' ] ) ) { // Get input $target = $_REQUEST[ 'ip' ]; // Set blacklist $substitutions = array( '&&' => '', ';' => '', ); // Remove any of the charactars in the array (blacklist). $target = str_replace( array_keys( $substitutions ), $substitutions, $target ); // Determine OS and execute the ping command. if( stristr( php_uname( 's' ), 'Windows NT' ) ) { // Windows $cmd = shell_exec( 'ping ' . $target ); } else { // *nix $cmd = shell_exec( 'ping -c 4 ' . $target ); } // Feedback for the end user echo "<pre>{$cmd}</pre>"; } ?>
源碼分析:
Str_replace()函數,以其餘字符替換字符串中的一些字符(區分大小寫)。
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );將用戶輸入的內容,含有&&或;的替換爲空。
其餘的部分基本和low相差不大。
這裏的源碼對用戶的輸入進行了初步的過濾,過濾掉了一些可以同時執行命令的符號,可是咱們知道,擁有一樣做用的符號不止&&和;。因此依然能夠進行命令注入。
命令注入測試:
構造語句: 10.39.1.4 & net user
& 前面命令執行後接着執行後面的命令
測試:
依然得到了執行的結果session
漏洞分析:此級別下的源碼雖然對用戶的輸入設置了過濾,可是沒有將特殊符號過濾徹底,僅僅設置黑名單是不夠的,你不知道用戶會輸入什麼,形成有心者亦能夠利用此漏洞。 ide
四、 high級別
源碼:
<?php函數
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = trim($_REQUEST[ 'ip' ]);源碼分析
// Set blacklist $substitutions = array( '&' => '', ';' => '', '| ' => '', '-' => '', '$' => '', '(' => '', ')' => '', '`' => '', '||' => '', ); // Remove any of the charactars in the array (blacklist). $target = str_replace( array_keys( $substitutions ), $substitutions, $target ); // Determine OS and execute the ping command. if( stristr( php_uname( 's' ), 'Windows NT' ) ) { // Windows $cmd = shell_exec( 'ping ' . $target ); } else { // *nix $cmd = shell_exec( 'ping -c 4 ' . $target ); } // Feedback for the end user echo "<pre>{$cmd}</pre>";
}
?>
源碼分析:
這個級別的源碼和medium級別的源碼相差不大,只是將更多的符號加入黑名單。
經過這樣的確實可以有效的防護以前的諸多思路。
測試:
輸入10.39.1.4 | net user
已經不能用那些方法了。具體的利用我也沒有找到合適的方法。
漏洞分析:只是作黑名單的話,老是不夠安全的,只要黑名單不夠完整,就不是很安全。即便你認爲名單已經很完整了。可能還有你不知道的存在能夠利用。
五、impossible級別
源碼:
<?php if( isset( $_POST[ 'Submit' ] ) ) { // Check Anti-CSRF token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input $target = $_REQUEST[ 'ip' ]; $target = stripslashes( $target ); // Split the IP into 4 octects $octet = explode( ".", $target ); // Check IF each octet is an integer if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) { // If all 4 octets are int's put the IP back together. $target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3]; // Determine OS and execute the ping command. if( stristr( php_uname( 's' ), 'Windows NT' ) ) { // Windows $cmd = shell_exec( 'ping ' . $target ); } else { // *nix $cmd = shell_exec( 'ping -c 4 ' . $target ); } // Feedback for the end user echo "<pre>{$cmd}</pre>"; } else { // Ops. Let the user name theres a mistake echo '<pre>ERROR: You have entered an invalid IP.</pre>'; } } // Generate Anti-CSRF token generateSessionToken();
源碼分析:
Explode()函數,將字符串變爲數組。這裏就是將咱們輸入的ip,變成數組
而後判斷數組的前四組數是否爲數字,而且數組中有四個對象。不知足就會報錯提醒。也就是說這裏只容許你輸入四組數字。
若果判斷爲true的話,就會再將這四組數經過點鏈接起來再就行ping命令。
就不測試了,這樣的源碼已經杜絕了你的全部命令注入×××。
一、函數用法
eval(phpcode)
Phpcode 規定要計算的php代碼。一般用分號結束每句代碼的執行。
二、環境源碼:
<?php $var = "var"; if(isset($_GET["name"])){ $arg = $_GET["name"]; eval("\$var=$arg;"); echo "\$var = ".$var; } ?>
構造語句:
name=phpinfo()
測試效果:
三、 ctf題目實例
題目地址bugku中的本地包含:http://120.24.86.145:8003/
題目解析:
源碼:
<?php include "flag.php"; $a = @$_REQUEST['hello']; eval( "var_dump($a);"); show_source(__FILE__); ?>
構造語句:
Hello = file(‘flag.php’)
解析,當參數接收到的構造的語句的時候,代碼就會變爲
Eval(var_dump(file(‘flag.php’)))
Eval函數,執行函數體沒的php代碼;file()函數把整個文件讀到一個數組中。Var_dump()函數 輸出。
因此執行結果就是將flag.php中的內容以數組的形式輸出出來。
獲得flag
一、函數用法:
System(string command,int &return_var)
Command 要執行的命令
Return_var 存放命令的執行後的狀態值
二、環境源碼:
<?php $cmd = $_GET['cmd']; if(isset($cmd)){ echo system("dir".$cmd); } ?>
構造語句:
Cmd=| net user
測試:
經過漏洞咱們得到了系統中存在哪些用戶,一樣的咱們也能夠經過這樣的方法在系統中建立咱們本身的用戶。並能夠加入到管理員組中。這裏就不在說了。
一、函數用法:
shell_exec(string command)
command 要執行的命令
二、環境源碼:
<?php $cmd = $_GET['cmd']; if(isset($cmd)){ echo "<h3>"; echo shell_exec("dir".$cmd); echo "<h3>"; } ?>
四、 測試:
構造語句: | net user
實現方法和上一個函數是同樣的。一樣的函數還有exec()和符號
5、passthru()函數形成的漏洞
一、函數用法:
void passthru (string command, int &return_var)
command 要執行的命令
return_var 存放執行命令後的狀態值
同 exec() 函數相似, passthru() 函數 也是用來執行外部命令(command)的。 當所執行的 Unix 命令輸出二進制數據, 而且須要直接傳送到瀏覽器的時候, 須要用此函數來替代 exec() 或 system() 函數。
二、環境源碼:
<?php $cmd = $_GET['cmd']; if(isset($cmd)){ echo passthru($cmd); } ?>
三、測試
構造語句 cmd=net user
得到用戶列表
總結以上全部函數漏洞形成的命令注入漏洞,每個例子都是由於沒有對用戶的輸入進行處理。在防護漏洞的時候,必定明白一個道理,全部用戶的輸入都是有害的。全部的輸入都是不值得相信的。