-
-
Save key-moon/b78c0dd3345929190f05de7df7980e2b to your computer and use it in GitHub Desktop.
This file contains 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
const { noise } = require("./perlin.js"); | |
const sharp = require("sharp"); | |
const crypto = require("node:crypto"); | |
const assert = require("node:assert/strict"); | |
const { exit } = require("node:process"); | |
const WIDTH = 256; | |
const HEIGHT = 256; | |
const DEBUG = true; | |
assert(5 <= process.argv.length) | |
const offsetX_0 = Number(process.argv[2]); | |
const offsetY_0 = Number(process.argv[3]); | |
const offsetX_1 = Number(process.argv[4]); | |
const offsetY_1 = Number(process.argv[5]); | |
const seedBegin = Number(process.argv[6]); | |
const seedEnd = Number(process.argv[7]); | |
offsets = [ | |
{ offsetX: offsetX_0, offsetY: offsetY_0 }, | |
{ offsetX: offsetX_1, offsetY: offsetY_1 }, | |
] | |
const targetDigests = process.argv.slice(8); | |
console.error({ offsets, seedBegin, seedEnd, tdLen: targetDigests.length }); | |
if (DEBUG) { | |
const validate_coord = val => { | |
assert(0 <= val && val < 2**32, `value not in range (${val})`); | |
assert(val % (1 / 16) == 0, `invalid step (${val})`); | |
}; | |
validate_coord(offsetX_0); | |
validate_coord(offsetY_0); | |
validate_coord(offsetX_1); | |
validate_coord(offsetY_1); | |
assert(0 <= seedBegin && seedBegin <= 65536, `invalid seedStart (${seedBegin})`); | |
assert(0 <= seedEnd && seedEnd <= 65536, `invalid seedEnd (${seedEnd})`); | |
} | |
const generateFromSeed = async (tag, s) => { | |
const { offsetX, offsetY } = offsets[tag]; | |
noise.seed(s); | |
const colors = []; | |
for (let y = 0; y < HEIGHT; y++) { | |
for (let x = 0; x < WIDTH; x++) { | |
let v = noise.perlin2(offsetX + x * 0.05, offsetY + y * 0.05); | |
v = (v + 1.0) * 0.5; // [-1, 1] -> [0, 1] | |
colors.push((v * 256) | 0); | |
} | |
} | |
const image = await sharp(Uint8Array.from(colors), { | |
raw: { | |
width: WIDTH, | |
height: HEIGHT, | |
channels: 1, | |
}, | |
}).webp({ lossless: true }).toBuffer(); | |
const md5 = crypto.createHash('md5'); | |
const digest = md5.update(image.toString("base64"), 'binary').digest('hex'); | |
if (targetDigests.includes(digest)) { | |
console.log(tag); | |
exit(0); | |
} | |
}; | |
const STEP = 16; | |
const generateNoise = async () => { | |
for (var i = seedBegin; i < seedEnd; i += STEP) { | |
if ((i - seedBegin) % STEP == 0) console.error(`${i - seedBegin} / ${seedEnd - seedBegin}`); | |
const jobs = []; | |
for (var j = 0; j < STEP; j++) { | |
jobs.push(generateFromSeed(0, i + j)); | |
jobs.push(generateFromSeed(1, i + j)); | |
} | |
for (var job of jobs) { | |
await job; | |
} | |
} | |
} | |
generateNoise(); |
This file contains 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
from Crypto.Util.number import * | |
from subprocess import check_output | |
from hashlib import md5 | |
from progressbar import progressbar | |
from pwn import * | |
LOCAL = False | |
PROC = 8 | |
TOTAL = 65536 | |
initial_shift = 188 | |
last_shift = 68 | |
cur = bytes_to_long(b'SECCON') | |
found = [0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0] | |
def add_found(b): | |
global cur | |
cur = cur * 2 + b | |
found.append(b) | |
print(f'[+] {found=}') | |
open(f"backup/{int(time.time())}", "w").write(str(found)) | |
if len(found) % 8 == 0: | |
open(f"backup/f{int(time.time())}", "wb").write(long_to_bytes(cur)) | |
print(long_to_bytes(cur)) | |
_found = list(found) | |
found.clear() | |
for b in _found: | |
add_found(b) | |
# collect samples | |
def call_imggen(digests, offset_x1, offset_y1, offset_x2, offset_y2, begin, end): | |
print(f'[+] call "node imggen.js {offset_x1} {offset_y1} {offset_x2} {offset_y2} {begin} {end} {" ".join(digests)}"') | |
output = check_output(["node", "imggen.js", str(offset_x1), str(offset_y1), str(offset_x2), str(offset_y2), str(begin), str(end), *digests]).strip() | |
print(f'[+] finished. {output=}') | |
return 0 if b'0' in output else 1 if b'1' in output else None | |
# remote | |
BIN_NAME = ["node", './index.js'] | |
REMOTE_ADDR = 'noiseccon.seccon.games' | |
REMOTE_PORT = 1337 | |
def query(scale_x, scale_y): | |
print(f'[+] oracle({scale_x}, {scale_y})') | |
if LOCAL: stream = process(BIN_NAME) | |
else: stream = remote(REMOTE_ADDR, REMOTE_PORT) | |
stream.sendlineafter(b'x: ', str(scale_x).encode()) | |
stream.sendlineafter(b'y: ', str(scale_y).encode()) | |
res = stream.recvline(keepends=False) | |
stream.close() | |
return res.strip() | |
while True: | |
shift = initial_shift - len(found) - 1 | |
digests = [] | |
for i in range(0, 64): | |
print(f'[+] {i} / {64}...') | |
while True: | |
res = query(1 << shift, 1 << shift) | |
digest = md5(res).hexdigest() | |
if digest in digests: continue | |
digests.append(digest) | |
break | |
coord_1, coord_2 = [((cur * 2 + b) & ((1 << 36) - 1)) / 16 for b in [0, 1]] | |
res = call_imggen(digests, coord_1, coord_1, coord_2, coord_2, 0, TOTAL) | |
print(f'[+] {res=}') | |
assert res is not None | |
add_found(res) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment