新手教程-DVWA全級別教程之命令注入

系統環境

因為網上關于dvwa的相關資料都比較舊,所以想重新過一邊dvwa的各個類型的漏洞,順帶初步入門php代碼審計相關的知識。環境安裝可以直接參照網上教程新手指南:手把手教你如何搭建自己的滲透測試環境,已經寫的非常詳細,可以直接按照教程一步步安裝。

簡介

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

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(mode)
這個函數會返回運行php的操作系統的相關描述,參數mode可取值”a” (此為默認,包含序列”s n r v m”里的所有模式),”s ”(返回操作系統名稱),”n”(返回主機名),” r”(返回版本名稱),”v”(返回版本信息), ”m”(返回機器類型)。可以看到,服務器通過判斷操作系統執行不同ping命令,但是對ip參數并未做任何的過濾,linux可以直接使用&&和;來執行多條命令,導致了嚴重的命令注入漏洞。
直接 提交 127.0.0.1&&ls -l 或把 ls -l 改為其他的系統命令也是可以執行的


命令執行

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參數做了一定的過濾,即將“&&”和“;”刪除,本質上采用了黑名單的方式過濾了一些字符,但是黑名單的模式永遠都會存在過濾不全的問題。命令執行同樣還是||的方式。所以我們可以采用的方式有很多種。
ping 127.0.0.1 || ls 當前面的一條命令執行失敗的時候執行后面一條命令


medium

127.0.0.1 & ls &&的是前面一條命令必須執行成功才會執行后面一條命令,&不管前面的命令是否執行成功后面的命令都會執行


medium

127.0.0.1 &;& ls -l 看代碼因為“&&” “;”會被替換成空字符,所以“;”被替換成空字符,命令成功執行。
medium

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的基礎上進一步過濾了& ; | - $ ( ) ` ||一些字符,進一步完善了黑名單機制,但是依然可以繞過。可以看到黑名單機制中‘| ’中后面有一個空格,于是這里又成了一個可以利用的地方。
127.0.0.1|ls -l |是管道符,表示將cmd1的輸出作為cmd2的輸入,并只打印cmd2執行的結果。


high

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進行了嚴格的限制,只有諸如“數字.數字.數字.數字”的輸入才會被接收執行,因此不存在命令注入漏洞。

參考文檔

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。