mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Add content from: DOM-based Extension Clickjacking
This commit is contained in:
parent
3b40ab6ab7
commit
8057a189ac
@ -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 extension’s 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 manager’s UI is present (root tag names, attributes) and whether it’s 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 aren’t 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 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.
|
||||
|
||||
### 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}}
|
@ -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 extension’s 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}}
|
||||
|
||||
|
||||
|
||||
|
@ -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}}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user