1. 程式人生 > >DVWA練習二、Command Injection

DVWA練習二、Command Injection

Command Injection,即命令注入,是指通過提交惡意構造的引數破壞命令語句結構,從而達到執行惡意命令的目的。PHP命令注入攻擊漏洞是PHP應用程式中常見的指令碼漏洞之一,國內著名的Web應用程式Discuz!、DedeCMS等都曾經存在過該型別漏洞

php中常用的系統函式如:system()、exec()、shell_exec、passthru、popen、proc_popen等

命令注入判斷流程:

一、是否呼叫系統命令

二、函式或函式的引數是否可控

三、是否拼接注入命令

首先要知道命令注入的流程,確定可控欄位

確定命令語句、windows下如何連線兩條命令

  • &,&&,|,||命令拼接符

A&B:簡單的拼接,AB之間無制約關係,A無論是夠成功都會執行B

A&&B:A執行成功然後才會執行B

A|B:A的輸出作為B的輸入

A||B:A執行失敗,然後才會執行B

常見漏洞:

bash破殼漏洞(CVE-2014-6271)如果我們能夠控制執行的bash的環境變數,就可以通過破殼漏洞來執行任意程式碼

呼叫第三方元件存在程式碼執行漏洞:

可以看到,Impossible級別的程式碼加入了Anti-CSRF token,同時對引數ip進行了嚴格的限制,只有諸如“數字.數字.數字.數字”的輸入才會被接收執行,因此不存在命令注入漏洞。

很經典的就是WordPress中,可以選擇使用ImageMagick這個常用的圖片處理元件,對使用者上傳的圖片進行處理(預設是ImageMagick庫),造成命令執行。

另外java中的命令執行漏洞:struts2/ElasticsearchGroovy等

漏洞危害:

繼承web服務程式的許可權,執行系統命令

繼承web服務程式的許可權,讀寫檔案

反彈shell

控制整個網站甚至伺服器

可以進一步內網滲透


下面對不同級別的程式碼進行分析。

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  -c 4 ' . $target ); 
    } 
    // Feedback for the end user 
    echo "<pre>{$cmd}</pre>"; 
} 
?> 

相關函式介紹 

stristr(string,search,before_search)

stristr函式搜尋字串在另一字串中的第一次出現,返回字串的剩餘部分(從匹配點),如果未找到所搜尋的字串,則返回FALSE。引數string規定被搜尋的字串,引數search規定要搜尋的字串(如果該引數是數字,則搜尋匹配該數字對應的ASCII值的字元),可選引數before_true為布林型,預設為“false”,如果設定為“true”,函式將返回search引數第一次出現之前的字串部分。

php_uname函式

(PHP 4>= 4.0.2, PHP 5, PHP 7)

php_uname — 返回執行 PHP 的系統的有關資訊

stringphp_uname ([ string$mode ="a" ] )

php_uname()返回了執行 PHP 的作業系統的描述。這和 最頂端上輸出的是同一個字串。如果僅僅要獲取作業系統的名稱。可以考慮使用常量PHP_OS,不過要注意該常量會包含 PHP 構建(built)時的作業系統名。

在一些舊的 UNIX 平臺,它有可能無法檢測到當前系統的資訊,然後會還原顯示成構建 PHP 時的系統資訊。這僅僅在你的 uname() 函式庫不存在或無法執行時發生。

引數 ¶

mode

mode是單個字元,用於定義要返回什麼資訊:

o    'a':此為預設。包含序列"s n r v m"裡的所有模式。

o    's':作業系統名稱。例如:FreeBSD

o    'n':主機名。例如:localhost.example.com

o    'r':版本名稱,例如:5.1.2-RELEASE

o    'v':版本資訊。作業系統之間有很大的不同。

o    'm':機器型別。例如:i386

o    漏洞利用

o    window和linux系統都可以用&&來執行多條命令

o    127.0.0.1&&netuser

Linux下輸入127.0.0.1&&cat /etc/shadow甚至可以讀取shadow檔案,可見危害之大。

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>"; 
} 
?>

可以看到,相比Low級別的程式碼,伺服器端對ip引數做了一定過濾,即把”&&”、”;”刪除,本質上採用的是黑名單機制,因此依舊存在安全問題。

漏洞利用

1、127.0.0.1&netuser

因為被過濾的只有”&&”與”;”,所以”&”不會受影響。

2、由於使用的是str_replace把”&&”、”;”替換為空字元,因此可以採用以下方式繞過:

127.0.0.1&;&ipconfig


這是因為”127.0.0.1&;&ipconfig”中的”;”會被替換為空字元,這樣一來就變成了”127.0.0.1&&ipconfig,會成功執行。

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級別的程式碼,High級別的程式碼進一步完善了黑名單,但由於黑名單機制的侷限性,我們依然可以繞過。

漏洞利用

黑名單看似過濾了所有的非法字元,但仔細觀察到是把”| ”(注意這裡|後有一個空格)替換為空字元,於是”|”成了“漏網之魚”。

127.0.0.1|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(); 
?> 

相關函式介紹

stripslashes(string)

stripslashes函式會刪除字串string中的反斜槓,返回已剝離反斜槓的字串。

explode(separator,string,limit)

把字串打散為陣列,返回字串的陣列。引數separator規定在哪裡分割字串,引數string是要分割的字串,可選引數limit規定所返回的陣列元素的數目。

is_numeric(string)

檢測string是否為數字或數字字串,如果是返回TRUE,否則返回FALSE。

可以看到,Impossible級別的程式碼加入了Anti-CSRF token,同時對引數ip進行了嚴格的限制,只有諸如“數字.數字.數字.數字”的輸入才會被接收執行,因此不存在命令注入漏洞。