DVWA靶場通關----(3) CSRF教程


CSRF(跨站請求偽造)

CSRF(跨站請求偽造),全稱為Cross-site request forgery,簡單來說,是攻擊者利用受害者尚未失效的身份認證信息,誘騙受害者點擊惡意鏈接或含有攻擊代碼的頁面,在受害者不知情的情況下以受害者的身份像服務器發起請求,從而實現非法攻擊(改密)。

CSRF主題:

 

Low

源碼解析

<?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方式獲取兩次密碼,兩次密碼輸入一致的話,就可以直接帶入數據中修改密碼。

漏洞復現

(1)先來做個嘗試,將密碼改成123456,兩次都輸入123456,發現直接修改成功了

 (2)測試一下密碼123456,先測試一下原來的密碼(原來的密碼就是你登錄DVWA的密碼)

 原來的密碼很明顯已經不行了,接下來試一下123456

 (3)經過上面的嘗試發現可以成功修改賬號密碼,而且我們發現了URL那里的變化,接下來我們從URL處入手再改一下,首先先重置一下數據庫,把密碼改回來。

在 C:\phpstudy_pro\WWW 文件夾中建立一個 1.html ,里面寫入

<img src="http://127.0.0.3/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#" border="0" style="display:none;"/>

<h1>404<h1>

<h2>file not found.<h2>

這樣的話,當我們打開 1.html 文件的時候,密碼就會被修改成123456,(誘騙受害者點擊這個1.html文件)

 

 

Medium

源碼解析

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Checks to see where the request came from
//stripos(str1, str2)檢查str2在str1中出現的位置(不區分大小寫),如果有返//回True,反之False
//判斷Host字段是否出現在referer字段中
    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);
}

?>

  Medium級別的代碼檢查了保留變量 HTTP_REFERER(http包頭的Referer參數的值,表示來源地址)中是否包含SERVER_NAME(http包頭的Host參數,及要訪問的主機名,這里是127.0.0.3),希望通過這種機制抵御CSRF攻擊。

漏洞復現

其實意思是這個referer中只要出現Host就可以正常操作

惡意網站中是這樣的,顯然是不成立的

Host 127.0.0.3

Referer http://127.0.0.1/

如果是這樣的呢

Host 127.0.0.3

Referer http://127.0.0.1/127.0.0.3.html

這樣就可以繞過,從而實現改密的操作了。

 

High

源碼解析

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Check Anti-CSRF token
//可以看到加入了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級別的代碼增加了Anti-CSRF token機制,用戶每次訪問改密頁面時,服務器會返回一個隨機的token,向服務器發起請求時,需要提交token參數,而服務器在收到請求時,會優先檢查token,只有token正確,才會處理客戶端請求。

漏洞復現

  思路:利用xss,xss可以執行代碼,獲取token(在這路利用XSS其實是獲取的cookie值,但是cookie值中是包含token值的,所以在這個地方我們使用XSS執行。參考文章:https://www.cnblogs.com/zhaof/p/6281482.html)

(1)利用XSS獲取cookie

<script>alert(document.cookie)</script>

 

復制: PHPSESSID=8kha1nlrqamui5c8n6k1au4md1; security=low

(2)抓包修改密碼

 

Impossible

源碼分析

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

?>

漏洞復現

  要求我們先輸入密碼再修改,攻擊者不知道原始密碼的情況下是無法發起 CSRF 攻擊的。

 

常見防范措施

1、加入Anti-CSRF,每次向客戶端發送一個隨機數,當客戶端向服務器發送數據時對比隨機數從而確定身份
2、獲取當前用戶密碼,以此判斷是否為當前用戶操作
3、二次確認(提示、二次密碼、驗證碼)


免責聲明!

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



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