PHP代碼審計學習(8)——CSRF漏洞

CSRF

  跨站請求僞造(英語:Cross-site request forgery),也被稱爲 one-click attack 或者 session riding,通常縮寫爲 CSRF 或者 XSRF, 是一種挾制用戶在當前已登錄的Web應用程序上執行非本意的操作的攻擊方法。跟(XSS)相比,XSS 利用的是用戶對指定網站的信任,CSRF 利用的是網站對用戶網頁瀏覽器的信任。與XSS攻擊相比,CSRF攻擊往往不大流行(因此對其進行防範的資源也相當稀少)和難以防範,所以被認爲比XSS更具危險性

攻擊思路

  CSRF(Cross-site request forgery)跨站請求僞造:攻擊者誘導受害者進入第三方網站,在第三方網站中,向被攻擊網站發送跨站請求。利用受害者在被攻擊網站已經獲取的註冊憑證,繞過後臺的用戶驗證,達到冒充用戶對被攻擊的網站執行某項操作的目的。

  一個典型的CSRF攻擊有着如下的流程:

受害者登錄a.com,並保留了登錄憑證(Cookie)。
攻擊者引誘受害者訪問了b.com。
b.com 向 a.com 發送了一個請求:a.com/act=xx。瀏覽器會默認攜帶a.com的Cookie。
a.com接收到請求後,對請求進行驗證,並確認是受害者的憑證,誤以爲是受害者自己發送的請求。
a.com以受害者的名義執行了act=xx。
攻擊完成,攻擊者在受害者不知情的情況下,冒充受害者,讓a.com執行了自己定義的操作。

挖掘思路

  CSRF主要是越權操作,出現的位置自然就是要有權限控制的地方,所以在黑盒審計的時候,多注意管理後臺、交易管理,用戶操作等地方,找交互頁面抓包查看token頭,若沒有刪referer再提交是否返回一致,若一致則有可能有CSRF。

  在白盒的時候,就看核心代碼有沒有驗證referer和token,若核心文件沒有則去功能點找

案例

  直接上DVWA的源碼(我太菜了不會寫這個場景)

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // 獲取用戶的輸入
    $pass_new  = $_GET[ 'password_new' ];
    $pass_conf = $_GET[ 'password_conf' ];

    // 確認兩次輸入的密碼是否相同,相同就更新數據庫內的信息
    if( $pass_new == $pass_conf ) {
        // 以下兩段代碼都是防止SQL注入的
        $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 );

        // 更新數據庫內的信息,具體函數作用以及對代碼的理解,在暴力破解那裏我寫過的,這裏就不寫了
        $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>' );

        // 修改成功,返回信息給用戶
        echo "<pre>Password Changed.</pre>";
    }
    else {
        // 兩次輸入的密碼不同,所以返回信息給用戶
        echo "<pre>Passwords did not match.</pre>";
    }

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

?>

  可以看到,服務器收到修改密碼的請求後,會檢查參數password_newpassword_conf是否相同,如果相同,就會修改密碼,並沒有任何的防CSRF機制

  抓一下包

 

 

 

   構造http://192.168.43.167/DVWA/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#

  當受害者點擊了這個鏈接,他的密碼就會被改成password,這樣就完成了一次CSRF攻擊,當然這種很明顯,可以使用BP自帶的POC攻擊

 

 

   誘導受害者使用瀏覽器訪問生成的html文件,點擊submit,會發現密碼修改成功。用戶密碼變成了123456

防禦

  1、將cookie設置爲HttpOnly 

  CRSF攻擊很大程度上是利用了瀏覽器的cookie,爲了防止站內的XSS漏洞盜取cookie,需要在cookie中設置"HttpOnly"屬性,這樣通過程序(js、applet等)無法讀取到cookie信息。避免了攻擊者僞造cookie的情況出現。服務端的CSRF方式方法很多樣,但總的思想都是一致的,就是在客戶端頁面增加僞隨機數。  

  2、Cookie Hashing(所有表單都包含同一個僞隨機值)

    這可能是最簡單的解決方案了,因爲攻擊者不能獲得第三方的Cookie(理論上),所以表單中的數據也就構造失敗了

  3、驗證碼

  這個方案的思路是:每次的用戶提交都需要用戶在表單中填寫一個圖片上的隨機字符串,厄....這個方案可以完全解決CSRF,但個人覺得在易用性方面似乎不是太好,還有聽聞是驗證碼圖片的使用涉及了一個被稱爲MHTML的Bug,可能在某些版本的微軟IE中受影響。

  在業界目前防禦 CSRF 攻擊主要有三種策略:驗證 HTTP Referer 字段;在請求地址中添加 token 並驗證;在 HTTP 頭中自定義屬性並驗證。

參考

  https://www.freebuf.com/articles/web/118352.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章