命令注入攻擊的常見模式為:僅僅需要輸入數據的場合,卻伴隨着數據同時輸入了惡意代碼,
而裝載數據的系統對此並未設計良好的過濾過程,導致惡意代碼也一並執行,最終導致信息泄露或者正常數據的破壞。
PHP命令注入攻擊漏洞是PHP應用程序中常見的腳本漏洞之一,國內著名的Web應用程序Discuz!、DedeCMS等都曾經存在過該類型漏洞。
現在開始我們的Command Injection
首先打開Command Injection,發現是一個執行ping的界面,推測若沒有做好過濾,則很有可能執行其他DOS命令
DOS在一行中執行多條命令需使用的符號:
&&:只有當前面的命令執行成功才執行后面的命令
&:無論怎樣總執行后面的命令
||:只有當前面的命令執行失敗才執行后面的命令
|:將前面命令執行的輸出作為后面命令執行的輸入
Low
Low級別的源碼,未對用戶輸入ip做任何過濾
可以看到,low級別的代碼接收了用戶輸入的ip,然后根據服務器是否是Windows NT系統,對目標ip進行不同的ping測試。
但是這里對用戶輸入的ip並沒有進行任何的過濾,所以我們可以進行命令執行漏洞
我們ping一個ip(隨便一個能ping得通的就行,比如本機ip 127.0.0.1)
可以看到能ping通
我們嘗試輸入 127.0.0.1 & ipconfig ,在操作系統中," & 、&& 、| 、 || "都可以作為命令連接符使用,我們在ping完后再執行ipconfig 命令查看ip信息
可以看到,成功執行。然后我們就可以繼續執行我們的命令了。把ipconfig換成其他的系統命令
比如,我們執行 127.0.0.1 & net user xie /add ,嘗試ping完后新建一個用戶,我們就可以成功創建用戶了。
使用&,查看系統用戶
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>"; } ?>
可以看到,medium級別的代碼在low級別的代碼上增加量了對 && 和 ;的過濾,
但並未過濾&,|,||
使用&,查看系統用戶
輸入” 127.0.0.1&;& net view ”時,也是可以的,因為過濾一次后相當於”127.0.0.1 && net view
High
仔細查看過濾代碼發現”|”后面有個空格,因此當輸入”127.0.0.1 |net view”,一樣可以攻擊,”|”是管道符,意思是將前者處理后的結果作為參數傳給后者。
也可以使用一個不會執行的命令和|來執行命令
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(); ?>
stripslashes(string) : 該函數會刪除字符串string中的反斜杠,返回已剝離反斜杠的字符串。
explode(separator,string,limit): 該函數把字符串打散為數組,返回字符串的數組。參數separator規定在哪里分割字符串,參數string是要分割的字符串,可選參數limit規定所返回的數組元素的數目。
is_numeric(string): 該檢測string是否為數字或數字字符串,如果是返回TRUE,否則返回FALSE。
可以看到,Impossible級別的代碼加入了Anti-CSRF token,同時對參數ip進行了嚴格的限制,只有諸如“數字.數字.數字.數字”的輸入才會被接收執行,因此不存在命令注入漏洞。