DVWA--Command Injection(命令執行)--四個等級

Command Injection,也就是我們常說的命令執行,DVWA共有四個等級

索引目錄:

Low

Medium

High

Impossible


命令執行漏洞的原理: :在操作系統中, & 、&& 、| 、 || 都可以作爲命令連接符使用,用戶通過瀏覽器提交執行命令,由於服務器端沒有對執行函數進行過濾,從而造成可以執行危險命令

PHP的命令執行函數主要有: :system、exec、passthru、shell_exec與’ '(這個並不是函數,只是代表他可以執行命令)

常用url編碼
%20 = 空格
%5c = \
%26 = &
%7c = |

command1 & command2 :不管command1執行成功與否,都會執行command2(將上一個命令的輸出作爲下一個命令的輸入)
command1 && command2 :先執行command1執行成功後纔會執行command2
command1 | command2 :只執行command2
command1 || command2 :command1執行失敗,再執行command2(若command1執行成功,就不再執行command2)

Low

源代碼:
<?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  -n 4 ' . $target );
    } 

    // Feedback for the end user 
    echo "<pre>{$cmd}</pre>"; 
} 

?> 

stristr(string,search,before_search) :搜索字符串在另一字符串中的第一次出現,返回字符串的剩餘部分(從匹配點),如果未找到所搜索的字符串,則返回 FALSE

string 必需。規定被搜索的字符串

search 必需。規定要搜索的字符串
如果該參數是數字,則搜索匹配該數字對應的 ASCII 值的字符

before_search 可選。默認值爲 “false” 的布爾值
如果設置爲 “true”,它將返回 search 參數第一次出現之前的字符串部分

註釋:該函數是二進制安全的
註釋:該函數是不區分大小寫的,如需進行區分大小寫的搜索,請使用 strstr() 函數
舉例:

<?php
echo stristr("Hello world!","WORLD");
?>
/*結果
world!
*/

php_uname ($mode) :返回運行 PHP 的系統的有關信息,也就是返回運行 PHP 的操作系統的描述
$mode 是單個字符,用於定義要返回什麼信息:
‘a’:此爲默認。包含序列 “s n r v m” 裏的所有模式
‘s’:操作系統名稱。例如: FreeBSD
‘n’:主機名。例如:DESKTOP-XXXXXXX
‘r’:版本名稱,例如: 5.1.2-RELEASE
‘v’:版本信息。操作系統之間有很大的不同
‘m’:機器類型。例如:i386

shell_exec() :通過 shell 環境執行命令,並且將完整的輸出以字符串的方式返回。也就是說, PHP先運行一個shell環境, 然後讓shell進程運行你的命令, 並且把所有輸出已字符串形式返回, 如果程序執行有錯誤或者程序沒有任何輸出, 則返回null
在這裏插入圖片描述

Low級別的代碼對提交的參數沒有進行過濾,僅僅使用使用stristr與php_uname判斷操作系統是否是Windows NT,因此我們可以使用命令連接符來實現命令執行

滲透測試:
在這裏插入圖片描述
command1 && command2 :先執行command1後執行command2
在這裏插入圖片描述
command1 & command2 :先執行command2後執行command1
在這裏插入圖片描述
command1 | command2 :只執行command2
在這裏插入圖片描述
command1 || command2 :command1執行失敗,再執行command2(若command1執行成功,就不再執行command2)
在這裏插入圖片描述
在這裏插入圖片描述


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  -n 4 ' . $target ); 
    } 

    // Feedback for the end user 
    echo "<pre>{$cmd}</pre>"; 
} 

?> 

array() :用於創建數組
在 PHP 中,有三種類型的數組:
索引數組 - 帶有數字索引的數組
關聯數組 - 帶有指定的鍵的數組
多維數組 - 包含一個或多個數組的數組
說明:
array() 創建數組,帶有鍵和值。如果在規定數組時省略了鍵,則生成一個整數鍵,這個 key 從 0 開始,然後以 1 進行遞增

要用 array() 創建一個關聯數組,可使用 => 來分隔鍵和值

要創建一個空數組,則不傳遞參數給 array():
$new = array();
關聯數組舉例:

<?php
$age=array("Bill"=>"1","Steve"=>"2","Mark"=>"3");
echo "Bill is " . $age['Bill'] . " years old.";
?>
/*結果:
Bill is 1 years old.
*/

str_replace(find,replace,string,count) :以其他字符替換字符串中的一些字符(區分大小寫)
find 必需。規定要查找的值
replace 必需。規定替換 find 中的值的值
string 必需。規定被搜索的字符串
count 可選。對替換數進行計數的變量

該函數必須遵循下列規則:
如果搜索的字符串是數組,那麼它將返回數組
如果搜索的字符串是數組,那麼它將對數組中的每個元素進行查找和替換
如果同時需要對數組進行查找和替換,並且需要執行替換的元素少於查找到的元素的數量,那麼多餘元素將用空字符串進行替換
如果查找的是數組,而替換的是字符串,那麼替代字符串將對所有查找到的值起作用
註釋:該函數區分大小寫。請使用 str_ireplace() 函數執行不區分大小寫的搜索
註釋:該函數是二進制安全的
舉例:

<?php
echo str_replace("world","Shanghai","Hello world!");
?>
/*結果:
Hello Shanghai!
*/

array_keys(array,value,strict) :返回包含數組中所有鍵名的一個新數組
array 必需。規定數組
value 可選。您可以指定鍵值,然後只有該鍵值對應的鍵名會被返回

strict 可選。與 value 參數一起使用。可能的值:
true - 返回帶有指定鍵值的鍵名。依賴類型,數字 5 與字符串 “5” 是不同的
false - 默認值。不依賴類型,數字 5 與字符串 “5” 是相同的

如果提供了第二個參數,則只返回鍵值爲該值的鍵名
如果 strict 參數指定爲 true,則 PHP 會使用全等比較 (===) 來嚴格檢查鍵值的數據類型
舉例:

<?php
$a=array("x"=>"A","y"=>"B","z"=>"C");
print_r(array_keys($a));
?>
/*結果:
Array ( [0] => x [1] => y [2] => z ) 
*/

過濾核心代碼理解:

array_keys( $substitutions )Array ( [0] => && [1] => ; ) ,也就是arry(&& , ;)
$substitutions$substitutions = array( '&&' => '', ';'  => '', )&&;是鍵,''爲鍵值,轉換一下也就是array( [0] => '', [1]  => '', ),再轉化一下就是arry('','')
假設$target=127.0.0.1 && ipconfig

解釋1$target = str_replace( arry(&& , ;), arry( '&&' => '', ';'  => '', ), "127.0.0.1 && ipconfig" );搜索"127.0.0.1 && ipconfig"中的&&;
替換成數組arry( '&&' => '', ';'  => '', )&&;對應的值
那麼str_replace()函數會將$target中的&&;替換爲''

解釋2$target = str_replace( arry(&& , ;), arry('',''), "127.0.0.1 && ipconfig" );搜索"127.0.0.1 && ipconfig"中的&&;
替換成''

注:這裏的解釋1和解釋2只是爲了幫助理解

因此,從Medium的源代碼可以看出,它在Low代碼層面上增加了對上傳參數的過濾,將上傳參數的&&和;轉化爲空,但是它僅僅只能過濾&&和;,我們可以使用&繼續進行命令執行

滲透測試:
在這裏插入圖片描述
在這裏插入圖片描述


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  -n 4 ' . $target ); 
    } 

    // Feedback for the end user 
    echo "<pre>{$cmd}</pre>"; 
} 

?> 

High的代碼也就是在Medium的代碼上面進行了一次升級,增加了過濾的黑名單,但是,我們仔細看源代碼會發現,本來可以過濾一個|,就可以過濾所有|、||、|||等等,可是你仔細觀察一下,會發現過濾的|後面有一個空格,也就表示,它過濾的是|空格,並沒有過濾|,所以我們可以利用|進行繞過

滲透測試:

繞過方法一:
在這裏插入圖片描述
看了上面一幅圖,大家也許就會有疑惑了,明明源代碼裏有過濾||,爲什麼還能執行呢?
我們仔細看一下它的黑名單:
在這裏插入圖片描述
從上面可以看出,它確實有過濾||,但是,你注意到了順序嗎!!它是由上到下依次查找轉義,它首先轉義|空格
所以127.0.0.1 || ipconfig經過過濾後就是127.0.0.1 |ipconfig,這裏的|是原命令語句(127.0.0.1 || ipconfig)左邊的,因此,最後的執行命令便成了127.0.0.1 |ipconfig

如果我們把黑名單過濾的順序修改一下會怎樣呢?如下圖:
在這裏插入圖片描述
執行結果:
在這裏插入圖片描述
此時我們會發現無法執行,因爲它首先過濾了||

繞過方法二:
在這裏插入圖片描述
在這裏插入圖片描述


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  -n 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(separator,string,limit) :把字符串打散爲數組

參數 描述
separator 必需。規定在哪裏分割字符串
string 必需。要分割的字符串
limit 可選。規定所返回的數組元素的數目。可能的值:(1)大於 0 - 返回包含最多 limit 個元素的數組;(2)小於 0 - 返回包含除了最後的 -limit 個元素以外的所有元素的數組;(3)0 - 返回包含一個元素的數組

舉例:

<?php
$str = "Hello world. I love Shanghai!";
print_r (explode(" ",$str));
?>  
/*結果
Array ( [0] => Hello [1] => world. [2] => I [3] => love [4] => Shanghai! )
*/

is_numeric($var) :用於檢測變量是否爲數字或數字字符串
$var要檢測的變量
如果指定的變量是數字和數字字符串則返回TRUE,否則返回FALSE

sizeof(array,mode) :計算數組中的單元數目或對象中的屬性個數
array 必需。規定數組
mode 可選。規定模式。可能的值:
0 - 默認。不計數多維數組中的所有元素
1 - 遞歸地計數數組中元素的數目(計算多維數組中的所有元素)

當變量未被設置,或是變量包含一個空的數組,該函數會返回 0。可使用 isset() 變量來測試變量是否被設置
舉例:

<?php
$cars=array("Volvo","BMW","Toyota");
echo sizeof($cars);
?>
/*結果
3
*/

Impossible級別的代碼加入了Anti-CSRF token,並對提交的參數進行嚴格的過濾,不僅過濾了反斜槓;也使用is_numeric檢測變量是否爲數字字符串或數字,使得非數字字符串或數字的全部“封殺”,從而達到阻止危險的命令執行

注:這所有源代碼中的的ping -c 4 ip現在已經不適用了,現在windows的版本應該是ping - n 4 ip了,我都已經在源代碼中修改了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章