Skip to content

Instantly share code, notes, and snippets.

@key-moon
Created November 17, 2022 17:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save key-moon/b78c0dd3345929190f05de7df7980e2b to your computer and use it in GitHub Desktop.
Save key-moon/b78c0dd3345929190f05de7df7980e2b to your computer and use it in GitHub Desktop.
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();
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