变种XSS:持久控制

tig3r 2015-11-30 10:42:00

0x00 引言


首先声明,这不是一个新洞,看过 Homakov 文章(最后附)以及译文的人想必对这种漏洞有所了解。

但原文写的太过简单(没有说明利用条件、情景和特性),且译文和我的理解略有偏差,于是就有了这篇文章。

这种漏洞已经存在一段时间了,有没有被利用过尚不得知,虽然利用条件较苛刻,但是当符合条件的站点被攻击后, 影响面和影响程度巨大,并且普通用户不知如何清除, 可导致长期持续攻击。

2014年底的时候,这种漏洞的利用条件没有现在苛刻(比如没有Service-Worker-Allowed头),一年过来 W3C 对规范优化了不少(包括安全方面), 相信不久的将来,很快会被标准更新所扼杀了。

弥留之际,让这个漏洞放点异彩吧。

0x01 一切都从 serviceWorker 说起


Service Worker是基于Web Worker的事件驱动的,他们执行的机制都是新开一个线程去处理一些额外的,以前不能直接处理的任务。对于Web Worker,我们可以使用它来进行复杂的计算,因为它并不阻塞浏览器主线程的渲染。而Service Worker,我们可以用它来进行本地缓存,相当于一个本地的proxy。说起缓存,我们会想起我们常用的一些缓存技术来缓存我们的静态资源,但是老的方式是不支持调试的,灵活性不高。使用Service Worker来进行缓存,我们可以用javascript代码来拦截浏览器的http请求,并设置缓存的文件,直接返回,不经过web服务器,然后,做更多你想做的事情。

  • 我们可以用 javascript 代码来拦截浏览器的 http 请求,并设置缓存的文件,直接返回

相信很多人看到这句已经明白了,通过 js 来代理浏览器 http 请求,也就是说通过执行 js 代码来控制浏览器的请求, 很容易想到,利用 xss 来修改浏览器请求的返回内容。

可怕的是,即便 xss 漏洞被修复了,攻击仍然持续,并且渗透到攻击范围内的每一个 url。

并且,当用户察觉到攻击,并且理解这种攻击,进入chrome后台(chrome://appcache-internals), 进行手动清除攻击缓存,攻击仍未失效!当然了,还是有办法清除的,且无须用户手工操作(下文会演示)。

0x02 漏洞原理和演示


serviceWorker的官方标准文档:http://www.w3.org/TR/service-workers/

其操作可以参考:https://github.com/w3c-webmob/ServiceWorkersDemos

首先 serviceWorker 只有在 https 页面中才可以调用 regist。

而 serviceWorker 需要 Promise 支撑,目前支持的浏览器如下:

支持 serviceWorker 的浏览器:

firefox 默认关闭 serviceWorker,可以通过 about:config 打开开关:

支持 fetch 方法(抓包)的浏览器:


开始尝试攻击:

首先在 https 站点中找到一个 Xss,利用 Xss 注册一个serviceWorker.registration实例:

navigator.serviceWorker.register(url).then(function(registration) {
  console.log(registration);
});

注意到有个未知参数 url,这个 url 就是拿来放我们的攻击代码(假设我们能上传一个js到根目录):

var url = '//victim.com/evil.js'

有人说这太难了,往根目录上传 js 文件不可能,那么可以尝试在子目录/任何一个可能的目录上传js文件, 或者和 Homakov 一样,利用 jsonp 接口来代替这个恶意 js 文件。

serviceWorker.register 只支持请求文件返回头的MIME类型为:text/javascript, application/x-javascript, application/javascript

我们知道,jsonp 的 callback 经常是可控的,那么找到一个这样可以写代码的 jsonp 难不难?

Google it !

点击第一个链接:

可以看到,以 taobao.com 为例,第一个 jsonp 接口就存在这样的弱点:callback 可以写入任意代码。

退一步说,只要能输入 []!() 等几个符号,就能构造任意代码了。

以往安全工程师修复 jsonp 接口的 xss 漏洞,都是将页面的mime修改为application/javascript, 或者将 callback 的参数中的html符号实体转义,就觉得杜绝 xss 了,看来以后得换个修法了

若 callback 仅仅代表一个函数名,何不只允许数字、字母和下划线呢?

往 “js/jsonp接口” 里写入恶意代码:

onfetch = function(e) {
  e.respondWith(new Response('任意内容',{
      headers
      ...
    });
  );
}

通过 onfetch 方法拦截 http 请求,并构造返回内容,比如返回:<script>alert(/xss/)</script>

所有在 evil 路径下的请求的内容都被篡改。


让我们本地测试还原一遍场景(注意:本地测试不需要 https):

首先打开网站:

打开正常页面:

这时候点击被攻击页面,此页面事先被注入了 XSS 脚本:

可以看到,这时候 serviceWorker 已经成功注册了

刷新页面,此时返回内容以及被修改了:

这时候再看正常页面,也被攻击了:

首页也是相同的情况:

关闭浏览器,再打开,依旧如此:

0x03 优势、局限性

  • 优势
    • 生存周期久(即便浏览器重启还在)
    • 一旦中招不易清除,包括用户和网站业务方
  • 局限性
    • 需要同域中同时存在 XSS 和弱点 JSONP(或可控js文件)
    • 感染路径受弱点 js 路径的限制
    • 被攻击站点必须是 https

实际利用中,若弱点JSONP路径中不存在网站业务,这个漏洞依然能发挥一定价值。

比如:杀死该JSONP路径以及其子目录的全部接口,从而导致网站无法正常使用。

0x04 中止及防范攻击


1. 如何中止攻击

从上文可以知道,即便 xss 被修复了或者消失了,攻击依然生效,那么如何中止攻击呢?

作为一个普通用户,首先尝试打开 chrome://inspect/#service-workers 查看存活:

的确可以看到被用作攻击的 Worker,点击 terminate 尝试中止:

可以看到以及被清理了,但是打开页面,攻击仍然存在!

浏览器中打开F12,在console中输入:navigator.serviceWorker., 可以看到有 getRegistration 和 getRegistrations 这两种属性。

查询文档:https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/getRegistration

尝试获取注册器,并且调用注销(由于用到 Promise,需要使用 then 调取结果):

navigator.serviceWorker.getRegistration()
  .then(function(registration) {
  registration.unregister();
});

这一次终于清除了。

而对于网站方,如何清除所有攻击呢?

只要将“清除代码”部署在一个未受感染的同域的页面里,当用户访问过后,自然就清除了。

2. 防范方法:

  1. Jsonp 接口的 callback 可以做白名单,或者只允许特定字符(比如数字、字母和下划线)。
  2. Jsonp所在域不应该存在 XSS(一切类型),至少不应该存在业务页面。
  3. 如果做不到2,Jsonp 所在 url 路径下不应该存在网站业务。
  4. 域名内不应存在用户可控的 js 文件。

reference:

评论

E

EtherDream 2015-11-30 11:10:44

javascript 也可以 daemon 进程了

珈蓝夜宇 2015-11-30 11:10:46

good!请问下有实例么

小哲哥 2015-11-30 11:33:51

是不是反射的也可以利用这种方法缓存在本地

T

tig3r 2015-11-30 14:54:33

@珈蓝夜宇 首先得有一个XSS,至于JSONP很好找,我google很快就找到某几个互联网大厂www域名都存在这样可构造的JSONP接口。

T

tig3r 2015-11-30 14:54:55

@小哲哥 嗯,是的

_

_fd 2015-11-30 19:06:50

SW 會 24小時強制refresh一次

Knight 2015-11-30 19:56:38

赞!

隐形人真忙 2015-11-30 22:50:14

思路真不错 XSS rootkit的一种形式

珈蓝夜宇 2015-12-01 11:57:43

@tig3r 我有很多腾讯的反射型XSS,这样也可以吗?

珈蓝夜宇 2015-12-01 11:58:43

@tig3r XSS是在一个三级域名下的,JSONP这个可以随便吗?

0

0x0d 2015-12-01 13:10:52

@珈蓝夜宇 jsonp 不受同源策略影响,根据文末的参考资料(http://sakurity.com/blog/2015/08/13/middlekit.html)反射型应该可以的。

0

0x0d 2015-12-01 13:46:13

然而找了个qq的试了下并没有成功…
据 http://www.w3ctech.com/topic/866 中所述,"有一个需要特别说明的是service worker文件的路径,你一定注意到了在这个例子中,service worker文件被放在这个域的根目录下,这意味着service worker和网站同源。换句话说,这个service work将会收到这个域下的所有fetch事件。如果我将service worker文件注册为/example/sw.js,那么,service worker只能收到/example/路径下的fetch事件(例如: /example/page1/, /example/page2/)。",所以 serviceWorker 是要同源的,条件太苛刻了……

珈蓝夜宇 2015-12-01 13:59:02

@0x0d 搞了半天也一个都没成功 -.-

随机分类

数据分析与机器学习 文章:12 篇
逆向安全 文章:70 篇
其他 文章:95 篇
Exploit 文章:40 篇
iOS安全 文章:36 篇

扫码关注公众号

WeChat Offical Account QRCode

最新评论

Article_kelp

因为这里的静态目录访功能应该理解为绑定在static路径下的内置路由,你需要用s

N

Nas

师傅您好!_static_url_path那 flag在当前目录下 通过原型链污

Z

zhangy

你好,为什么我也是用windows2016和win10,但是流量是smb3,加密

0

0x0dee

标题写错了,是ASX to MP3 3.1.3.7 - '.m3u' Local

K

k0uaz

foniw师傅提到的setfge当在类的字段名成是age时不会自动调用。因为获取

目录