CSRF 漏洞測試

CSRF簡介

CSRF中文名:跨站請求僞造,英文譯爲:Cross-site request forgery,CSRF攻擊就是attacker(攻擊者)利用victim(受害者)還沒有失效的身份認證信息(cookie、session等),以某種方式誘騙victim點擊attacker精心製做的惡意連接或者訪問包含惡意攻擊代碼的頁面,當victim觸發成功以後,惡意代碼會被執行,瀏覽器默默的向目標service發出請求加載着victim還沒有失效的身份認證信息,致使victim替attacker完成了非法操做好比:在某些論壇上發佈大量的惡意言論、網站用戶密碼被惡意篡改、帳戶金額被盜取、刪除網站我的信息~~~~~php

漏洞測試

經過DVWA平臺,對CSRF漏洞進行測試,讓你們走進CSRF的世界html

環境:dvwa服務IP      :192.168.43.146mysql

           attacker服務IP :192.168.43.150sql

low 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);
}

?> 

 

代碼審計以後發現:網站沒有對CSRF作出防範,只對網站進行了SQL防護(經過mysqli_real_escape_string()函數的過濾做用,將用戶傳入的數據中的特殊字符進行轉義,有效預防了attacker對網站的SQL注入攻擊)跨域

mysqli_real_escape_string()函數詳細介紹:瀏覽器

定義和用法
mysql_real_escape_string() 函數轉義 SQL 語句中使用的字符串中的特殊字符。

下列字符受影響:

\x00
\n
\r
\
'
"
\x1a
若是成功,則該函數返回被轉義的字符串。若是失敗,則返回 false。

語法
mysql_real_escape_string(string,connection)

參數         描述
string         必需。規定要轉義的字符串。
connection     可選。規定 MySQL 鏈接。若是未規定,則使用上一個鏈接。

//有效預防了數據庫攻擊

既然網站沒有對CSRF保護那麼attacker就能夠直接進行攻擊服務器

用戶正常修改密碼:cookie

用戶非正常修改密碼:session

attacker製做含有惡意攻擊代碼網頁

惡意代碼:

<iframe hidden src="http://192.168.43.146/dvwa/vulnerabilities/csrf/?password_new=attacker&password_conf=attacker&Change=Change#"></iframe>

attacker將代碼嵌入本身的釣魚網頁中,當victim受害者被誘導訪問該網頁時,惡意代碼就會自動被瀏覽器所執行並攜帶着victim未失效的身份認證信息向目標服務器發出請求,而victim卻毫無察覺,本身的用戶密碼已經被attacker惡意篡改

victim被attacker誘導瀏覽本身網站上的圖片(惡意代碼就隱藏在該網頁中)

你會發現該網站一切好像很正常&很美好,但本身殊不知道已經被攻擊了,網站密碼已經被修改成attacker

此時victim再去登錄時會發現本身已經login不上了

medium 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);
}

?> 

代碼審計發現:該網站進行了referer字段檢測,該字段限制了不是同一個域的不能跨域訪問,attacker要想進行CSRF攻擊只要繞過if條件就能夠,接下來分析該if條件

if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false )

$_SERVER[ 'HTTP_REFERER' ] 獲取網頁請求的來源URL

$_SERVER[ 'SERVER_NAME' ] 獲取目標服務器的域名

$_SERVER[ 'HTTP_REFERER' ]和$_SERVER[ 'SERVER_NAME' ]經過stripos()進行匹配,查看$_SERVER[ 'SERVER_NAME' ]字符串是否包含在$_SERVER[ 'HTTP_REFERER' ]中,從而判斷用戶的服務請求是不是跨域請求,如果跨域請求則會被目標服務器所拒絕訪問

attacker能夠有兩種方法進行繞過:

第一種:將網頁的名字改成$_SERVER[ 'SERVER_NAME' ].html
第二種:添加網頁父目錄包含$_SERVER[ 'SERVER_NAME' ]

在這裏使用第一種方法進行繞過:

victim瀏覽該網頁,惡意代碼被成功執行,victim的網站密碼被惡意篡改

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

?> 

代碼審計發現:該網站進行了user_token的檢測

user_token:

當用戶每次訪問修改用戶密碼頁面時,服務器會先返回一個隨機的token,接下來當用戶向服務器發起修改密碼請求時,須要提交user_token,當請求到達服務器時,服務器會優先檢查token,判斷客戶端的token和服務端的token是否匹配,若不匹配,服務器則會拒絕客戶端的請求

在這裏attacker是不能僞造token的,由於token是一個很長的隨機數,attacker要想CSRF攻擊成功,只有經過利用網站的XSS漏洞獲取用戶的token

XSS利用代碼獲取user_token:

<iframe src="../csrf" onload=alert(document.getElementsByName('user_token'))></iframe>

有關XSS的利用能夠查看筆者的這篇文章(https://www.cnblogs.com/qftm/p/10317166.html)

利用user_token進行CSRF攻擊

構造惡意代碼:

victim瀏覽存在惡意攻擊的網頁

攻擊成功

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

?> 
代碼審計發現:用戶修改網站密碼不只須要user_token的驗證還須要用戶輸入當前密碼進行驗證,所以,attacker不能對用戶進行CSRF攻擊

總結

學過CSRF和XSS以後,你可能會有疑惑,它們兩個同樣嗎,不用多說,相信你們看名字就知道不同

CSRF攻擊是直接利用用戶還沒有失效的cookie,並僞造特殊的請求對用戶形成危害的一種攻擊手段

XSS攻擊是直接盜取用戶的cookie,所形成的一種攻擊手段

二者看似類似,當又有一些不同的地方

相關文章
相關標籤/搜索