import { readFileSync } from 'node:fs';
import os from 'node:os';
import crypto from 'node:crypto';
import {
Worker,
isMainThread,
parentPort,
workerData,
} from 'node:worker_threads';
const PREFIX = 'ccaf33e3512e31f3';
function md5Hex(text) {
return crypto.createHash('md5').update(text, 'utf8').digest('hex');
}
function buildWasmAuth() {
const wasmBytes = readFileSync(new URL('./build/release.wasm', import.meta.url));
let nowMs = Date.now();
const imports = {
env: {
abort(message, fileName, lineNumber, columnNumber) {
throw new Error(`abort(${message}, ${fileName}, ${lineNumber}, ${columnNumber})`);
},
'Date.now': () => nowMs,
},
};
return WebAssembly.instantiate(wasmBytes, imports).then(({ instance }) => {
const { exports } = instance;
const memory = exports.memory;
function liftString(pointer) {
if (!pointer) return null;
const u32 = new Uint32Array(memory.buffer);
const u16 = new Uint16Array(memory.buffer);
const lengthU16 = u32[(pointer - 4) >>> 2] >>> 1;
const start = pointer >>> 1;
const end = start + lengthU16;
let out = '';
let i = start;
while (end - i > 1024) {
out += String.fromCharCode(...u16.subarray(i, i + 1024));
i += 1024;
}
out += String.fromCharCode(...u16.subarray(i, end));
return out;
}
function lowerString(value) {
if (value == null) return 0;
const length = value.length;
const pointer = exports.__new((length << 1) >>> 0, 2) >>> 0;
const u16 = new Uint16Array(memory.buffer);
const start = pointer >>> 1;
for (let i = 0; i < length; i++) u16[start + i] = value.charCodeAt(i);
return pointer;
}
function pinString(str) {
const ptr = lowerString(str);
if (exports.__pin) exports.__pin(ptr);
return ptr;
}
const uPtr = pinString(workerData?.username ?? 'admin');
const pPtr = pinString(workerData?.password ?? 'admin');
function authenticateAt(tsMs) {
nowMs = tsMs;
const retPtr = exports.authenticate(uPtr >>> 0, pPtr >>> 0) >>> 0;
return liftString(retPtr);
}
return {
exports,
authenticateAt,
};
});
}
function formatUtc(ms) {
return new Date(ms).toISOString();
}
if (isMainThread) {
const username = 'admin';
const password = 'admin';
const startUtc = Date.UTC(2025, 11, 21, 16, 0, 0, 0); // 2025-12-22 00:00:00 CST
const endUtc = Date.UTC(2025, 11, 21, 21, 0, 0, 0) - 1; // 2025-12-22 04:59:59.999 CST
const argWorkers = process.argv[2] ? Number(process.argv[2]) : undefined;
const workers = Number.isFinite(argWorkers) && argWorkers > 0 ? Math.floor(argWorkers) : os.cpus().length;
(async () => {
const { authenticateAt } = await buildWasmAuth();
const samples = [startUtc, startUtc + 1, startUtc + 1234567];
for (const ts of samples) {
const jsonText = authenticateAt(ts);
const jsonTrim = jsonText.trim();
const canonical = JSON.stringify(JSON.parse(jsonText));
const a = md5Hex(jsonTrim);
const b = md5Hex(canonical);
if (a !== b || jsonTrim !== canonical) {
console.error('一致性检查失败:不能直接用 jsonText.trim() 做 canonical');
console.error({ ts, a, b, jsonTrimEqualCanonical: jsonTrim === canonical });
process.exit(2);
}
}
console.log('OK: jsonText.trim() == JSON.stringify(JSON.parse(jsonText)),启用快速爆破');
console.log('range(UTC):', startUtc, '->', endUtc, 'count', endUtc - startUtc + 1);
console.log('range(ISO):', formatUtc(startUtc), '->', formatUtc(endUtc));
console.log('workers:', workers, 'PREFIX:', PREFIX);
const shared = new SharedArrayBuffer(4);
const stop = new Int32Array(shared);
const total = endUtc - startUtc + 1;
const chunk = Math.floor(total / workers);
let finished = 0;
const workerList = [];
function stopAll() {
Atomics.store(stop, 0, 1);
for (const w of workerList) w.terminate();
}
for (let i = 0; i < workers; i++) {
const s = startUtc + i * chunk;
const e = (i === workers - 1) ? endUtc : (s + chunk - 1);
const w = new Worker(new URL(import.meta.url), {
workerData: { id: i, start: s, end: e, username, password, shared },
});
workerList.push(w);
w.on('message', (msg) => {
if (msg?.type === 'found') {
console.log('\nFOUND', msg.ts, formatUtc(msg.ts));
console.log(msg.jsonText.trim());
console.log('check', msg.check);
console.log(`flag{${msg.check}}`);
stopAll();
} else if (msg?.type === 'progress') {
process.stderr.write(`worker ${msg.id}: ${msg.ts}\r`);
}
});
w.on('exit', () => {
finished++;
if (finished === workers && Atomics.load(stop, 0) === 0) {
console.log('\nnot found in range');
}
});
w.on('error', (err) => {
console.error('worker error', err);
stopAll();
process.exit(1);
});
}
})().catch((e) => {
console.error(e);
process.exit(1);
});
} else {
(async () => {
const { id, start, end, shared, username, password } = workerData;
const stop = new Int32Array(shared);
const { exports, authenticateAt } = await buildWasmAuth();
void username;
void password;
const GC_EVERY = 20000;
let iter = 0;
for (let ts = start; ts <= end; ts++) {
if (Atomics.load(stop, 0) === 1) return;
const jsonText = authenticateAt(ts);
const jsonTrim = jsonText.trim();
const check = md5Hex(jsonTrim);
if (check.startsWith(PREFIX)) {
Atomics.store(stop, 0, 1);
parentPort.postMessage({ type: 'found', ts, jsonText: jsonTrim, check });
return;
}
iter++;
if (exports.__collect && (iter % GC_EVERY) === 0) exports.__collect();
if ((iter % 1_000_000) === 0) parentPort.postMessage({ type: 'progress', id, ts });
}
})().catch((e) => {
parentPort.postMessage({ type: 'error', error: String(e?.stack || e) });
});
}