利用Flash进行Json CSRF攻击
/这时很早以前的话题了,整理一下原理和工具脚本等,以作为笔记。
0x01 CSRF与Json CSRF
一般的,我们说CSRF都是在GET/POST请求中通过构造HTML表单如param=value来提交给服务器,服务器得到数据并处理请求;而Json CSRF则是提交Json格式的数据。
相比之下,提交Json格式的数据,这种请求包更难构造,因为表单无法伪造Content-Type字段、无法提交格式正确的Json数据,因此需要利用其它技术组合利用。
当然,两者的漏洞存在的前提是一样的,即无CSRF token。
0x02 Json CSRF的几种情形
未校验Content-Type字段和Json数据格式
此时直接使用Burpsuite生成的CSRF PoC即可利用,这里我们可以明显地看到Json数据最后会带上=号,因此也正是服务端未校验Json数据格式才能成功。
这里假设某站点Json端点通过POST方式提交Json数据,该接口用于添加新用户和邮箱,我们用Burpsuite抓包然后生成PoC如下,当然实际生成的情况中提交数据的特殊字符会被编码掉:
1 | <html> |
而发送的POST请求包大致如下:
1 | POST / HTTP/1.1 |
可以看到,Content-Type字段为text/plain,Json数据最后会多出个=号,那是因为Json数据放在了input标签中name属性值中,而input标签的value属性为空,表单提交时是会以name=value的形式提交的。
缺点:无法伪造Content-Type字段;不校验Json数据格式。
未校验Content-Type字段,校验Json数据格式但最后的Json键值可填入=号
此时需要稍微改下前面的表单PoC,在input标签的value处写上相应的值来使Json数据格式正确:
1 | <html> |
在POST的请求体中,看到Content-Type字段依然为text/plain,但Json数据最后并无=号,而是在Json数据中最后的键值对的值中前面多了个=号,这时闭合构造的结果:
缺点:无法伪造Content-Type字段;Json数据值可带=号。
校验Content-Type字段和Json数据格式,允许跨域OPTIONS
如果校验了Content-Type字段必须为application/json的话,前面两种方式都不行了。
当跨域请求为复杂请求时,浏览器会发送OPTIONS请求,用来让服务端返回允许的方法(如GET、POST),允许被跨域访问的Origin(来源或者域),还有是否需要Credentials(认证信息)等。
下面使用Fetch和XHR方法的前提都是要发起OPTIONS请求来进行预检,之后才是真正地发送Json数据包。
Fetch
使用JS的Fetch()方法可以解决Content-Type字段的问题:
1 | <html> |
抓包可看到会先发送OPTIONS请求,再发送真正的请求;在请求中Content-Type字段为application/json,Json数据也是正确的格式。
缺点:跨域发送OPTIONS请求。
XHR
使用XMLHttpRequest可以解决Content-Type字段的问题:
1 | <html> |
抓包可看到会先发送OPTIONS请求,再发送真正的请求;在请求中Content-Type字段为application/json,Json数据也是正确的格式。
缺点:跨域发送OPTIONS请求。
校验Content-Type字段和Json数据格式
此时便需要用到Flash + HTTP 307技巧来实现利用了,在下一节说明。
0x03 Flash + HTTP 307
个人理解的公式:无CSRF token + Flash + HTTP 307 = Json CSRF
解决了哪些问题:
- Flash可以自定义Header请求,从而伪造Content-Type字段;
- HTTP 307和其他3xx HTTP状态码不同之处在于,307可以确保重定向请求发送之后,请求的方法和请求主体不会发生任何改变,会原封不动地转发出去;
- Flash访问同域或存在crossdomain.xml允许的服务器的307跳转文件可避免Flash跨域访问时必须要求目标站点存在crossdomain.xml且配置允许的特定情况;
适用场景
目标Json端点无CSRF token机制,其所能接收的Header的Content-Type必须为application/json,且严格校验了Json格式数据。
关键文件
在发起攻击前,需要我们准备好几个关键的文件。
Flash文件
第一个是用于向307文件发起请求的诱使用户访问的Flash的swf文件,作用就是构造Json数据,伪造Content-Type字段并访问攻击者控制的服务器的307文件,至于as文件如何编译看下Flash XSS相关文章即可:
1 | package |
实现307跳转功能的文件
该文件放置于攻击者控制的服务器上,可与Flash文件放置在同一服务上,可用PHP或Python实现。
PHP实现307跳转的代码,简单粗暴:
1 |
|
Python实现的代码,基于BaseHTTPServer实现的,用于和Flash文件放置在同一个Web服务:
1 | import BaseHTTPServer |
crossdomain.xml
这个文件是否需要看情况:当Flash文件和307跳转文件同域,则无需该文件;若两个文件不同域,为了使Flash文件能够成功跨域访问,则需要攻击者在307跳转文件所在的Web服务器上放置crossdomain.xml并设置允许Flash文件所在的域能够访问,如:
1 | <cross-domain-policy> |
利用过程
借个FreeBuf上的图:
用户在浏览器中登录
http://victim-site/
用户被重定向到
http://attacker-ip:8000/csrf.swf
Flash文件加载成功,并向
http://attacker-ip:8000/
发送带有自定义Header的POST Payload。攻击者的服务器发送HTTP 307重定向,这样便能让POST响应body和自定义HTTP头按原样发送到
http://victim-site/
目标用户刷新自己的
http://victim-site/
页面,并发现自己的帐户已经被删除了
案例
可参考:http://www.0xby.com/902.html
0x04 工具
现成美好的轮子已经很多了,无需我们自己再造了,下面是个人收集的两个。
Python起的Web服务,包括307文件都在一个Web服务中,理解原理可参考这个构造payload:
https://github.com/appsecco/json-flash-csrf-poc
更全面的工具,包括显示界面等HTML文件,PHP文件实现的307跳转功能:
https://github.com/sp1d3r/swf_json_csrf/
0x05 防御方法
Json CSRF还是CSRF漏洞,采用CSRF通用防御即可成功防御。
主要有 5 种策略:验证 HTTP的Referer字段、在请求地址中添加 token 并验证、在 HTTP 头中自定义属性并验证、使用POST替代GET等。
(1)、验证 HTTP的Referer字段,在 HTTP 头的Referer字段记录了该 HTTP 请求的来源地址。顺便解决了非法盗链、站外提交等问题。在通常情况下,访问一个安全受限页面的请求必须来自于同一个网站。
(2)、在请求地址中添加 token 并验证,可以在 HTTP请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。抵御 CSRF 攻击的关键在于:在请求中加入攻击者所不能伪造的信息,并且该信息不存在于 Cookie 之中。
(3)、在 HTTP 头中自定义属性并验证,也是使用 token 并进行验证,但并不是把 token以参数的形式置于 HTTP 请求而是放到 HTTP 头中自定义的属性里。通过XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把token 值放入其中。这样解决了前一种方法在请求中加入 token 的不便,同时,通过这个类请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会通过 Referer 泄露到其他网站。
(4)、严格区分好 POST 与 GET 的数据请求,尽量使用POST来替代GET,如在 asp 中不要使用 Request 来直接获取数据。同时建议不要用 GET 请求来执行持久性操作。
(5)、使用验证码或者密码确认方式,缺点是用户体验差。