[DOM Clobbering 이란?]
DOM Clobbering은 HTML 요소의 `id`나 `name`이 전역 변수 혹은 함수와 동일한 이름을 가질 때 발생하는 취약점이다. 자바스크립트에서 전역 변수로 사용하려던 이름이 DOM 요소에 의해 "덮어씌워져(clobbered)" 버리는 현상이다.
[DOM 이란?]
DOM (Document Object Model)은 웹 페이지를 구조화하여, 각 요소를 객체(Object) 형태로 표현한 인터페이스(Model)이다. 쉽게 말해, 웹 페이지의 각 요소(텍스트, 이미지 등)를 자바스크립트로 제어하기 위해 브라우저가 내부적으로 만들어 두는 것들이다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>DOM 사용 예시</title>
</head>
<body>
<!-- 변경 대상이 될 제목 -->
<h1 id="myHeading">Hello, World!</h1>
<!-- 클릭 이벤트를 연결할 버튼 -->
<button id="myButton">Change Text</button>
<script>
// 1. 문서에서 특정 DOM 요소를 가져오기
const heading = document.getElementById('myHeading');
const button = document.getElementById('myButton');
// 2. 버튼에 클릭 이벤트(addEventListener) 연결하기
button.addEventListener('click', function() {
// 3. 이벤트 발생 시 DOM을 조작해 h1 텍스트 변경
heading.textContent = 'Hello, DOM!';
});
</script>
</body>
</html>
위 코드는 `myHeading`과 `myButton` DOM 요소를 조작하는 예시이다.
[공격 예시]
<!DOCTYPE html>
<html>
<head>
<title>DOM Clobbering 예제</title>
</head>
<body>
<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||"undefined")
status += "\r\n"
status += "CONFIG.redirectUrl: " + (window.CONFIG?window.CONFIG.redirectUrl||"undefined":"undefined")
config_status.textContent = status
</script>
</script>
</body>
</html>
DOM Clobbering 페이지다.
<!DOCTYPE html>
<html>
<head>
<title>DOM Clobbering 예제</title>
</head>
<body>
<a id="CONFIG" name="redirectUrl"></a>
<a id="CONFIG"></a>
<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||"undefined")
status += "\r\n"
status += "CONFIG.redirectUrl: " + (window.CONFIG?window.CONFIG.redirectUrl||"undefined":"undefined")
config_status.textContent = status
</script>
</script>
</body>
</html>
DOM Clobbering 이후 화면이다.
<a id="CONFIG" name="redirectUrl"></a>
<a id="CONFIG"></a>
위 코드를 추가했다. 그 결과 `CONFIG`와 `CONFIG.redirectUrl`이 모두 설정된 것을 확인할 수 있고, CONFIG가 HTMLCollection으로 검색되는 것을 확인할 수 있다.
`id` 옵션과 `name` 옵션을 위와 같이 설정해줘야 redirectUrl이 제대로 설정된다.
<a id="CONFIG" name="redirectUrl" href="javascript:alert(1)"></a>
<a id="CONFIG"></a>
만약 위와 같이 입력하게 되면
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>")
}
위 코드에 의해
위와 같이 javascript가 먹히는 것을 볼 수 있다.
[대응 방안]
DOMPurify를 사용하면 `id`, `name` 등 attribute를 제거할 수 있다. 따라서 DOMPurify 사용을 권장한다.
[관련 자료 및 출처]
문제
https://dreamhack.io/wargame/challenges/48
출처
https://dreamhack.io/lecture/courses/326
https://dreamhack.io/forum/qna/3908/
https://portswigger.net/web-security/dom-based/dom-clobbering
'웹 해킹 > 개념 노트장' 카테고리의 다른 글
[Tip] CodeQL 간단 사용법 (0) | 2024.12.30 |
---|---|
Relative Path Overwrite (0) | 2024.12.28 |
Web Cache Deception (0) | 2024.12.26 |