p = 172036442175296373253148927105725488217 q = 337117592532677714973555912658569668821 e = 17 c = 19441066986971115501070184268860318480501957407683654861466353590162062492971
for mp in GF(p)(c).nth_root(e, all=True): for mq in GF(q)(c).nth_root(e, all=True): m = crt([ZZ(mp), ZZ(mq)], [p, q]) flag = long_to_bytes(m) if flag.startswith(b"dice{"): print(flag)
def_sum(self, L): s = 0 for x in L: s ^= x return s
def_clock(self): b = self._s[0] self._s = self._s[1:] + [self._sum(self._s[p] for p in self._t)] return b
defbit(self): return self._clock()
classRNG: def__init__(self, lfsr, N, nbits): self.lfsr = lfsr self.N = N self.nbits = nbits ifnot (pow(2, 27) < N < pow(2, 31)): raise ValueError("modulus is too big or small") K = pow(2, nbits) // N self.cutoff = K * N
defget_random_nbit_integer(self): res = 0 for i inrange(self.nbits): res += self.lfsr.bit() << i return res defget_random_integer_modulo_N(self): count = 1 whileTrue: x = self.get_random_nbit_integer() if x < self.cutoff: return x % self.N, count count += 1
if __name__ == "__main__": print("Welcome to the unbiased random number factory!") N = int(input("What modulus would you like to use? Choose between 2^27 and 2^31: "))
key = secrets.randbits(n) key_bits = [(key >> i)&1for i inrange(n)] lfsr = LFSR(key_bits, taps) rng = RNG(lfsr, N, 32) for _ inrange(1024): c = input("Enter your command (R,F): ") if c.startswith("R"): x,t = rng.get_random_integer_modulo_N() print("creating this random number took {} attempts".format(t)) elif c.startswith("F"): seed = int(input("what was my seed?")) if seed == key: print(flag) exit(0) else: print("unsupported command")
# get some bits bits = [] known_bits = 0 while known_bits < 64: print(f"{known_bits}") t = get_num() while t > 1: # number are rejected iff highest 2 bits are set bits.extend(["?"] * 30 + [1, 1]) t -= 1 known_bits += 2 bits.extend(["?"] * 32) print("".join(map(str, bits)))
P = PolynomialRing(GF(2), "x") x = P.gen() poly = sum([x ** e for e in taps]) + x ** 64 M = companion_matrix(poly, "bottom")
# construct linear system left = [] right = [] for i, b inenumerate(bits): if b != "?": Mi = M ** i left.append(Mi[0]) right.append(b)
N = 0xBA8CB3257C0C83EDF4F56F5B7E139D3D6AC8ADF71618B5F16A02D61B63426C2C275CE631A0927B2725C6CC7BDBE30CD8A8494BC7C7F6601BCEE5D005B86016E79919E22DA4C431CEC16BE1EE72C056723FBBEC1543C70BFF8042630C5A9C23F390E2221BED075BE6A6AC71AD89A3905F6C706B4FB6605C08F154FF8B8E28445A7BE24CB184CB0F648DB5C70DC3581419B165414395AE4282285C04D6A00A0CE8C06A678181C3A3C37B426824A5A5528EE532BDD90F1F28B7EC65E6658CB463E867EB5280BDA80CBDB066CBDB4019A6A2305A03FD29825158CE32487651D9BFA675F2A6B31B7D05E7BD74D0F366CBFB0EB711A57E56E6DB6D6F1969D52BF1B27B c1 = 0x75240FCC256F1E2FC347F75BBA11A271514DD6C4E58814E1CB20913195DB3BD0440C2CA47A72EFEE41B0F9A2674F6F46A335FD7E54BA8CD1625DAEAAAA45CC9550C566F6F302B7C4C3A4694C0F5BB05CD461B5CA9017F2EB0E5F60FB0C65E0A67F3A1674D74990FD594DE692951D4EED32EAC543F193B70777B14E86CF8FA1927FE27535E727613F9E4CD00ACB8FAB336894CAA43AD40A99B222236AFC219397620CA766CEF2FE47D53B07E302410063EAE3D0BF0A9D67793237281E0BFDD48255B58B2C1F8674A21754CF62FAB0BA56557FA276241CE99140473483F3E5772FCB75B206B3E7DFB756005CEC2C19A3CB7FA17A4D17F5EDD10A8673607047A0D1 c2 = 0xDB8F645B98F71B93F248442CFC871F9410BE7EFEE5CFF548F2626D12A81EE58C1A65096A042DB31A051904D7746A56147CC02958480F3B5D5234B738A1FB01DC8BF1DFFAD7F045CAC803FA44F51CBF8ABC74A17EE3D0B9ED59C844A23274345C16BA56D43F17D16D303BB1541EE1C15B9C984708A4A002D10188CCC5829940DD7F76107760550FAC5C8AB532FF9F034F4FC6AAB5ECC15D5512A84288D6FBE4B2D58AB6E326500C046580420D0A1B474DECA052EBD93AAA2EF972ACEBA7E6FA75B3234463A68DB78FFF85C3A1673881DCB7452390A538DFA92E7FF61F57EDF48662991B8DD251C0474B59C6F73D4A23FE9191AC8E52C8C409CF4902EEAA71714 e = 0xD4088C345CED64CBBF8444321EF2AF8B
Z = Zmod(N) P = PolynomialRing(Z, "t") t = P.gen() R = P.quotient((c1 - t) ^ 5 - c2, "t") t = R._first_ngens(1)[0] # same as s
te = t ** e # same as m basis = [te ^ i for i inrange(6)]
# idk how to find a non trivial linear combination to zero vector in sage # solve_right only gives trivial solution # right_kernel doesn't work modulo N # so I use a stupid LLL hack mm = matrix([list(x) for x in basis]).change_ring(ZZ).stack(matrix.identity(5) * N) reduced, tr = mm.LLL(transformation=True) assert reduced[0] == 0 coefs = tr[0][:6].change_ring(Z)
S = PolynomialRing(Z, "m") m = S.gen() ff = sum([c * m ** i for i, c inenumerate(coefs)]) m = ff.monic().small_roots(X=2 ** 256, epsilon=0.08)[0] print(long_to_bytes(m))
N = 0xBA8CB3257C0C83EDF4F56F5B7E139D3D6AC8ADF71618B5F16A02D61B63426C2C275CE631A0927B2725C6CC7BDBE30CD8A8494BC7C7F6601BCEE5D005B86016E79919E22DA4C431CEC16BE1EE72C056723FBBEC1543C70BFF8042630C5A9C23F390E2221BED075BE6A6AC71AD89A3905F6C706B4FB6605C08F154FF8B8E28445A7BE24CB184CB0F648DB5C70DC3581419B165414395AE4282285C04D6A00A0CE8C06A678181C3A3C37B426824A5A5528EE532BDD90F1F28B7EC65E6658CB463E867EB5280BDA80CBDB066CBDB4019A6A2305A03FD29825158CE32487651D9BFA675F2A6B31B7D05E7BD74D0F366CBFB0EB711A57E56E6DB6D6F1969D52BF1B27B c1 = 0x75240FCC256F1E2FC347F75BBA11A271514DD6C4E58814E1CB20913195DB3BD0440C2CA47A72EFEE41B0F9A2674F6F46A335FD7E54BA8CD1625DAEAAAA45CC9550C566F6F302B7C4C3A4694C0F5BB05CD461B5CA9017F2EB0E5F60FB0C65E0A67F3A1674D74990FD594DE692951D4EED32EAC543F193B70777B14E86CF8FA1927FE27535E727613F9E4CD00ACB8FAB336894CAA43AD40A99B222236AFC219397620CA766CEF2FE47D53B07E302410063EAE3D0BF0A9D67793237281E0BFDD48255B58B2C1F8674A21754CF62FAB0BA56557FA276241CE99140473483F3E5772FCB75B206B3E7DFB756005CEC2C19A3CB7FA17A4D17F5EDD10A8673607047A0D1 c2 = 0xDB8F645B98F71B93F248442CFC871F9410BE7EFEE5CFF548F2626D12A81EE58C1A65096A042DB31A051904D7746A56147CC02958480F3B5D5234B738A1FB01DC8BF1DFFAD7F045CAC803FA44F51CBF8ABC74A17EE3D0B9ED59C844A23274345C16BA56D43F17D16D303BB1541EE1C15B9C984708A4A002D10188CCC5829940DD7F76107760550FAC5C8AB532FF9F034F4FC6AAB5ECC15D5512A84288D6FBE4B2D58AB6E326500C046580420D0A1B474DECA052EBD93AAA2EF972ACEBA7E6FA75B3234463A68DB78FFF85C3A1673881DCB7452390A538DFA92E7FF61F57EDF48662991B8DD251C0474B59C6F73D4A23FE9191AC8E52C8C409CF4902EEAA71714 e = 0xD4088C345CED64CBBF8444321EF2AF8B
Z = Zmod(N) P = PolynomialRing(Z, "x") x = P.gen() g = (c1 - x) ^ 5 - c2 R = P.quotient(g, "t") t = R.gen() # same as s
f = t ^ e # represent s^e as a degree 4 polynomial in t
Pxy = PolynomialRing(Z, "x,y") x, y = Pxy.gens()
f = f.lift().change_ring(Pxy) - y # s^e - m in x, y g = g.change_ring(Pxy) # polynomial in x res = f.resultant(g).univariate_polynomial() m = res.monic().small_roots(X=2**256, epsilon=0.08)[0] print(long_to_bytes(int(m)))
if __name__ == "__main__": print("I heard that fast correlation attacks don't work if your LFSR has more than 10 taps.") print("You have 60 seconds to recover the key.")
key = secrets.randbits(n) key_bits = [(key >> i)&1for i inrange(n)] lfsr = LFSR(key_bits, taps) stream = [lfsr.bit() for _ inrange(m)]
noise = [secrets.randbelow(delta) > prob * delta for i in stream] stream = [i ^ j for i,j inzip(noise, stream)]
print("Here are {} bits of the stream with {}% accuracy".format(m, 100 * prob)) print(int("".join(map(str, stream)), 2))
seed = int(input("what is my key?")) if seed == key: print(flag)
這題因為在題目介紹看到有我不會的 fast correlation attack
就連檔案都沒下載,不過賽後來看才發現有個比我預期的簡單很多的解法(大概也不是
intended)。
P = PolynomialRing(GF(2), "x") x = P.gen() poly = sum([x ** e for e in taps]) + x ** 48 M = companion_matrix(poly, "bottom")
M_powers = [M ** i for i inrange(len(stream))] # cache for speeding up
pbar = tqdm(desc="Brute force with prob 0.8^48") whileTrue: pbar.n += 1 pbar.update() if pbar.n > 30000: print("Unlucky, just try again") exit() chosen_idx = random.sample(range(len(stream)), 48) left = [] right = [] for i in chosen_idx: Mi = M_powers[i] left.append(Mi[0]) right.append(stream[i]) try: kbits = list(map(int, matrix(left).solve_right(vector(right)))) except ValueError: # no solutions continue test_m = 200# we don't need to test that much new_lfsr = LFSR(kbits, taps) new_stream = [new_lfsr.bit() for _ inrange(test_m)] ifsum([x == y for x, y inzip(new_stream, stream)]) >= 0.70 * test_m: recovered_key = int("".join(map(str, kbits[::-1])), 2) print(f"{recovered_key = }") pbar.close() break
#!/usr/local/bin/node // don't mind the ugly hack to read input console.log("What do you want to run?"); let inpBuf = Buffer.alloc(2048); const input = inpBuf.slice(0, require("fs").readSync(0, inpBuf)).toString("utf8"); inpBuf = undefined;
field = [[0] * FLDBASE_Y for _ inrange(FLDBASE_X)] x, y = FLDBASE_X // 2, FLDBASE_Y // 2 field[x][y] = l - 1 for v in msg: for _ inrange(4): x += 1if v & 0x1else -1 y += 1if v & 0x2else -1 x = clamp(0, x, FLDBASE_X - 1) y = clamp(0, y, FLDBASE_Y - 1) if field[x][y] < l - 2: field[x][y] += 1 v >>= 2 field[x][y] = l
return field
defprintart(field): for y inrange(FLDBASE_Y): for x inrange(FLDBASE_X): print(chr(AUG[field[x][y]]), end="") print()
defprintart_num(field): for y inrange(FLDBASE_Y): for x inrange(FLDBASE_X): v = field[x][y] if AUG[v] == ord("S"): v = "S" elif AUG[v] == ord("E"): v = "E" print(v, end=" ") print()
from collections import deque
defreverse_randomart(field, is_goodpath): sx, sy = find_value(field, AUG.index(b"S"))
for dx, dy, bits in directions: xx = clamp(0, x + dx, FLDBASE_X - 1) yy = clamp(0, y + dy, FLDBASE_Y - 1) if cur_field[xx][yy] > 0: copied_field = list(map(list, cur_field)) copied_field[xx][yy] -= 1 next_path = path + [bits] if is_goodpath(next_path): q.append((xx, yy, path + [bits], copied_field))
deffind_value(field, v): for x inrange(FLDBASE_X): for y inrange(FLDBASE_Y): if field[x][y] == v: return x, y
defbordered_to_field(s: bytes): field = [[0] * FLDBASE_Y for _ inrange(FLDBASE_X)] y = 0 for ss in s.strip().splitlines()[1:-1]: line = ss.strip()[1:-1] iflen(line) == 0: continue for x inrange(len(line)): field[x][y] = AUG.index(line[x]) y += 1 return field
withopen("flag", "rb") as f: flag_field = bordered_to_field(f.read())
withopen("hash", "rb") as f: hash_field = bordered_to_field(f.read())
defis_goodpath(path): iflen(path) % 4 == 0: ar = [] for i inrange(0, len(path), 4): d, c, b, a = path[i : i + 4] ar.append((a << 6) | (b << 4) | (c << 2) | d) iflen(ar) > 0andnotbytes(ar).isascii(): returnFalse
pfx = b"un"# guess for x, y inzip(ar, pfx): if x != y: returnFalse
for i, x inenumerate(ar[len(pfx) :]): ifnot ( ord("a") <= x <= ord("z") orord("0") <= x <= ord("9") or x == ord("_") or x == ord("-") or x == ord("}") ): returnFalse if x == ord("}") and i + len(pfx) != len(ar) - 1: returnFalse
flag = b"dice{" + bytes(ar) print(flag) if flag.endswith(b"}"): if randomart(md5(flag).digest()) == hash_field: print("FOUND") exit()
x, y = find_value(known_field, AUG.index(b"E")) print(x, y) field = [[x - y for x, y inzip(r1, r2)] for r1, r2 inzip(flag_field, known_field)] field[x][y] = AUG.index(b"S") printart(field) reverse_randomart(field, is_goodpath)
# flag = b"dice{beh2P02199" # rev = build_dict(flag) # last = get_remote_err(len(flag)).strip().split("\n")[-1] # print(last, rev.get(last, None))
# test flag
# 6: _pickle.UnpicklingError: unpickling stack underflow # 7: _pickle.UnpicklingError: Memo value not found at index 50 # 8: but no persistent_load function was specified. # 9: _pickle.UnpicklingError: Memo value not found at index 959525424 # 10: _pickle.UnpicklingError: Memo value not found at index 959525424 # 11: _pickle.UnpicklingError: Memo value not found at index 959525424 # 12: _pickle.UnpicklingError: invalid load key, '9'.
work_err1 = get_remote_err work_err2 = partial(get_local_err, testflag=b"dice{beh2Ptj0219}") work_err2 = partial(get_local_err, testflag=b"dice{beh2Qdj0219}") for i inrange(4, 9): print(i) print("R", work_err1(i).strip().split("\n")[-1]) lo = work_err2(i).strip().split("\n") print("L", lo[-2]) print(" ", lo[-1]) print()
input("pause")
buf = bytearray(b"dice{buh2Qdj0219}") for c inrange(33, 123): # buf[10] = c buf[6] = c print(chr(c), bytes(buf).decode()) # print("R", work_err1(i).strip().split("\n")[-1]) for i inrange(4, 9): try: lo = get_local_err(i, bytes(buf)).strip().split("\n") print(i) print("L", lo[-2]) print(" ", lo[-1]) except: import traceback
defgift(target, name, value): global used_gift if used_gift: sys.exit(1) used_gift = True setattr(target, name, value)
print("Welcome to the TI-1337 Silver Edition. Enter your calculations below:")
math = input("> ") iflen(math) > 1337: print("Nobody needs that much math!") sys.exit(1) code = compile(math, "<math>", "exec")
bytecode = list(code.co_code) instructions = list(dis.get_instructions(code)) for i, inst inenumerate(instructions): if inst.is_jump_target: print("Math doesn't need control flow!") sys.exit(1) nextoffset = instructions[i+1].offset if i+1 < len(instructions) elselen(bytecode) if inst.opname in banned: bytecode[inst.offset:instructions[i+1].offset] = [-1]*(instructions[i+1].offset-inst.offset)
names = list(code.co_names) for i, name inenumerate(code.co_names): if"__"in name: names[i] = "$INVALID$"
code = code.replace(co_code=bytes(b for b in bytecode if b >= 0), co_names=tuple(names), co_stacksize=2**20) v = {} exec(code, {"__builtins__": {"gift": gift}}, v) if v: print("\n".join(f"{name} = {val}"for name, val in v.items())) else: print("No results stored.")
deftest_chain(links, start, end): current = start for link in links: current = int(''.join( str(int(current & component != 0)) for component in link ), 2) return end == current & end
defmain(): try: withopen('hyperlink.json', 'r') as f: data = json.load(f) except IOError: print('Could not open hyperlink.json') return
print('Welcome to the chain building game.') print('Enter a chain and see if it works:')
chain = input()
legal_chars = set('abcdefghijklmnopqrstuvwxyz{}_') ifany(c notin legal_chars for c in chain): print('Chain contains illegal characters!') return
try: links = [data['links'][c] for c in chain] result = test_chain(links, data['start'], data['target']) except Exception: print('Something went wrong!') return
if result: print('Chain works! Congratulations.') else: print('Oh no! Chain does not reach the target.')
deftest_chain(links, start, end): current = start for link in links: current = int( "".join(str(int(current & component != 0)) for component in link), 2 ) return end == current & end
defstep(cur, *links): for link in links: cur = int("".join(str(int(cur & component != 0)) for component in link), 2) return cur
withopen("hyperlink.json", "r") as f: data = json.load(f)
print(len(data["links"])) print(len(data["links"]["d"])) # for x in data["links"]["w"]: # print(f"{x:0164b}")
defnum2state(n): state_bits = f"{n:0164b}"[36:] return [ int("".join(map(str, state_bits[i + 1 : i + 4][::-1])), 2) for i inrange(0, len(state_bits), 4) ]
chars = "abcdefghijklmnopqrstuvwxyz{}_" current = step( data["start"], data["links"]["d"], data["links"]["i"], data["links"]["c"], data["links"]["e"], data["links"]["{"], data["links"]["e"], data["links"]["v"], data["links"]["e"], ) cur_state = num2state(current) for c in chars: nxt = step(current, data["links"][c]) state = num2state(nxt) g = sum(state) print(c, g)
defdfs(cur, cur_state, flag=""): print(flag) for c in chars: nxt = step(cur, data["links"][c]) state = num2state(nxt) ifany([x > y for x, y inzip(state, cur_state) if x > 0and y > 0]): print(cur_state) print(state) print() dfs(nxt, state, flag + c)
cur = step(data["start"], data["links"]["d"]) # dfs(cur, num2state(cur), 'di') flag = "d" for _ inrange(100): mx = 0 mxc = None for c in chars: nxt = step(cur, data["links"][c]) state = num2state(nxt) g = sum(state) if c == "e": g -= len(flag) if g > mx: mx = g mxc = c flag += mxc cur = step(cur, data["links"][mxc]) print(flag)