드림핵 - WHA(Client Side)

Document Object Model Vulnerability

김가윤 2023. 4. 20. 19:28

1. 서론

 

Document Object Model (DOM)은

브라우저가 HTML 문서를

관리하기 위해 사용하는 객체 모델이다.

 

DOM에 이벤트 헨들러를 추가하거나

DOM을 변경하는 방식으로 웹 페이지 수정이 가능하다.

 

DOM은 자바스크립트에서 접근할 수 있도록

각종 API를 제공한다.


2. Document Object Model

 

Document Object Model(DOM, 문서 객체 모델)이란

웹 페이지에 대한 프로그래밍 인터페이스이다.

 

웹 개발자가 작성한 웹 문서는

브라우저에서 파싱되어 DOM으로 표현된다.

 

DOM 내에서 웹 개발자가 작성한 HTML 문서는

트리 형태가 되어 노드로 표현되고 해당 노드들은

자바스크립트에서 접근할 수 있다.

 

Figure 1. DOM 예제

var elem = document.getElementById("name");
elem.innerText = "My name is dream";
var div_elem = document.createElement("div");
var text_node = document.createTextNode("Welcome to dreamhack");
div_elem.appendChild(text_node);

 

자바스크립트를 이용해

DOM에 존재하는 Element의 내용을 수정하고

새로운 Element를 생성하는 예제 코드이다.

 

2-1 Dom Clobbering

 

Dom Clobbering은

id, form 등 HTML에서 이용되는

식별자 속성을 이용해

자바스크립트에서 접근 가능한

DOM 객체들의 속성 및 메소드 등을 변조하는 기법

 

웹 프로그래밍을 공부하다 보면

document.getElementById() 를 사용하지 않고도

노드 id를 변수처럼 사용할 수 있다.

 

Figure 2. link1 변수

 

이는 편리한 기능일 수 있으나,

만약 HTML 마크업이 사용자나 제삼자로부터 제공된다면

문제가 발생할 수 있다.

 

Figure 3. 예상했던 값과 다른 값을 반환

 

만약 웹 애플리케이션이

미리 정의되지 않은 전역 변수에 접근한다면

공격자가 입력한 요소로 대체되어 반환될 수 있다.

 

DOM Clobbering을 방어할 수 있는

가장 효율적인 방법은

간접적 메소드 호출 및 접근자를 사용하는 것이다.

HTMLFormElement.prototype.reset.call(elm), 
Object.getOwnPropertyDescriptor(Node.prototype, 'textContent').set.call(elm, '')

 

하지만, 사용이 번거로워

보편적으로 사용되지는 않는다.

 

그럼에도 불구하고 third-party 라이브러리 (jQuery)와의

상호작용에서 취약점이 발생할 가능성이 높은데,

id, name 등 식별자 attribute를 제거할 수 있는

DOMPurify와 같은 라이브러리를 사용하는 것이 좋다.

 

2-2 Dom Clobbering 실습

 

소스

<!-- HTML CODE IS INJECTED HERE -->
<div id="config_status" style="white-space: pre;"></div>
<script>
if (window.CONFIG) {
    if (CONFIG.redirectUrl) {
        location.href = CONFIG.redirectUrl
    } else {
        document.write("<h1>redirectUrl is empty</h1>")
    }
} else {
    document.write("<h1>CONFIG is not defined.</h1>")
}
status = "CONFIG: " + (window.CONFIG||"NOT DEFINED")
status += "\r\n"
status += "CONFIG.redirectUrl: " + (window.CONFIG?window.CONFIG.redirectUrl||"NOT DEFINED":"NOT DEFINED")
config_status.textContent = status
</script>

 

정답

--> a.b와 같은 하위 속성을 만들기 위해 HTMLCollections를 이용할 수 있습니다.
<a id="a" name="b"></a>
<a id="a"></a>
window.a 를 출력시켜보면 b key를 가진 것도 존재하는 것을 볼 수 있습니다.
HTMLCollection(2) [a#a, a#a, a: a#a, b: a#a]
이를 이용해 공격 코드를 제작해 보면 다음과 같습니다.
<a id="CONFIG" name="redirectUrl" href="javascript:alert(1);"></a>
<a id="CONFIG"></a>

 

2-3 DOM-based XSS

 

자바스크립트 단에서

이용자의 데이터를 가져와 사용하다가

XSS 취약점이 발생하기 때문에

서버 단에서 올바르게 XSS를 필터링하여도

DOM-based XSS가 발생할 수 있다.

 

대표적으로

자바스크립트에서 URL의 파라미터나 해시를 가져와

innerHTML, outerHTML, insertAdjacentHTML과 같이

HTML에 마크업을 삽입할 수 있도록 해주는 기능에서 발생한다.

 

Figure 4. DOM-basesd XSS가 발생하는 자바스크립트 예시 코드

var name_el = document.getElementById("name");
name_el.innerHTML = `My name is ${decodeURIComponent(location.hash.slice(1))}.`;

 

다음과 같이 공격 코드를 작성할 수 있다.

https://host/domxss.html#<img src=@ onerror=alert(1)>

 

innerHTML로 스크립트를 삽입할 때에는

<script> 태그를 이용한 자바스크립트 실행은 불가능하기 때문에

반드시 event handler를 이용해 실행해야 한다.

 

DOM-based XSS를 방어하기 위해서는

이용자의 입력 값을 자바스크립트에서

동적으로 HTML에 추가하는 행위를

최대한 지양해야 한다.

 

또한, 만약 문서 내에 굳이

HTML로 삽입할 필요가 없다면

innerHTML 대신에 innerText를 사용해야 한다.


3. 정리