e1 = e ^ 0x10001 e2 = (e + 2) ^ 0x10001 g, a, b = xgcd(e1, e2) Z = Zmod(p * q) m = Z(c1) ^ a * Z(c2) ^ b print(long_to_bytes(m))
# https://math.stackexchange.com/questions/1653536/show-that-we-cannot-have-a-prime-triplet-of-the-form-p-p-2-p-4-for # there is no p > 3 that p, p + 2 p + 4 are primes
from sage.allimport * from Crypto.Util.number import *
defsolve(a, b, c): D = b * b - 4 * a * c if is_square(D): x1 = (-b + int(sqrt(D))) // (2 * a) x2 = (-b - int(sqrt(D))) // (2 * a) return x1, x2
n = 1108103848370322618250236235096737547381026108763302516499816051432801216813681568375319595638932562835292256776016949573972732881586209527824393027428125964599378845347154409633878436868422905300799413838645686430352484534761305185938956589612889463246508935994301443576781452904666072122465831585156151 e = 65537 c = 254705401581808316199469430068831357413481187288921393400711004895837418302514065107811330660948313420965140464021505716810909691650540609799307500282957438243553742714371028405100267860418626513481187170770328765524251710154676478766892336610743824131087888798846367363259860051983889314134196889300426
for a inrange(1, 1000): for b inrange(a, 1000): r = solve(a * b, a + b, 1 - n) if r: r = r[0] p = a * r + 1 q = b * r + 1 assert p * q == n phi = (p - 1) * (q - 1) d = inverse_mod(e, phi) m = power_mod(c, d, n) print(long_to_bytes(m))
5.times do puts <<~EOS 1. Sign 2. Find rule 3. Exit EOS
print 'choice? '
case gets.chomp when'1' x, s = ecdsa.sign('Baba') puts 'Baba is:' puts "x = #{x}" puts "s = #{s}" when'2' print 'Which rule do you want to know? '; msg = gets.chomp print 'x? '; x = gets.to_i print 's? '; s = gets.to_i
if ecdsa.verify(msg, x, s) if msg == 'Baba' puts 'Baba is you' elsif msg == 'Flag' puts "Flag is #{ENV['FLAG']}" else puts 'Not Found :(' end else puts 'Invalid :(' end else exit end end
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F a = 0 b = 7 n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
E = EllipticCurve(GF(p), [a, b]) G = E( 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8, )
# def chunks(kk): # return list(map(int, str(kk)[::-1])) # ar = list(map(int, str(kk))) # ret = [] # for a, b in list(zip(*[iter(ar)] * 2))[::-1]: # ret.append(a * 256 + b) # return ret
# kk1v = chunks(kk1) # kk2v = chunks(kk2)
P = PolynomialRing(Zmod(n), [f"b{j+1}_{i}"for j inrange(2) for i inrange(26)]) b1 = P.gens()[:26] b2 = P.gens()[26:] k1 = a + sum(b * 256 ** i for i, b inenumerate(b1)) k2 = a + sum(b * 256 ** i for i, b inenumerate(b2)) f = s1 * k1 - s2 * k2 # print(f(kk1v + kk2v)) # since roots are in 0~9, shifting it make it more easier to find the roots ff = f.subs({b: b + 5for b in b1 + b2}) # print(ff(*[x - 5 for x in kk1v + kk2v])) M = matrix.column(ZZ, vector([ZZ(c) for c, _ in ff])) M = M.augment(matrix.identity(53)) M = M.stack(vector([n] + [0] * 53)) M = M.dense_matrix() row0 = M.LLL()[0] roots = [x + 5for x in row0[1:-1]] assert f(*roots) == 0# try again if failed k1 = k1(roots) k2 = k2(roots) print(f"found {k1 = }") print(f"found {k2 = }") z = int(sha256(b"Baba").hexdigest(), 16) d = ZZ((s1 * k1 - z) % n) assert d == (s2 * k2 - z) % n
# signing z = int(sha256(b"Flag").hexdigest(), 16) k = 48763 s = ((z + d) / k) % n x = (k * G).xy()[0] io.sendlineafter(b"choice? ", b"2") io.sendlineafter(b"Which rule do you want to know? ", b"Flag") io.sendlineafter(b"x? ", str(x).encode()) io.sendlineafter(b"s? ", str(s).encode()) io.interactive()
sign 之中的 k 和 kk 是我自己在
local debug 用的,把 Ruby 那邊改成會 print 出原本的 kk 和
unpack 過的 k 來方便 debug。
5.times do puts <<~EOS 1. Sign 2. Find rule 3. Exit EOS
print 'choice? '
case gets.chomp when'1' x, s = ecdsa.sign('Baba') puts 'Baba is:' puts "x = #{x}" puts "s = #{s}" when'2' print 'Which rule do you want to know? '; msg = gets.chomp print 'x? '; x = gets.to_i print 's? '; s = gets.to_i
if ecdsa.verify(msg, x, s) if msg == 'Baba' puts 'Baba is you' elsif msg == 'Flag' puts "Flag is #{ENV['FLAG']}" else puts 'Not Found :(' end else puts 'Invalid :(' end else exit end end
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F a = 0 b = 7 n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
E = EllipticCurve(GF(p), [a, b]) G = E( 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8, )
P = PolynomialRing( Zmod(n), [f"b{j+1}_{i}"for j inrange(2) for i inrange(26)] + ["d"] ) b1 = P.gens()[:26] b2 = P.gens()[26:-1] d = P.gens()[-1] k1 = a + sum(b * 256 ** i for i, b inenumerate(b1)) k2 = a + sum(b * 256 ** i for i, b inenumerate(b2)) f1 = s1 * k1 - (z + r1 * d) f2 = s2 * k2 - (z + r2 * d)
PP = P.remove_var(d) b1 = PP.gens()[:26] b2 = PP.gens()[26:] f = PP(str(resultant(f1, f2, d))) # print(f(kk1v + kk2v)) # since roots are in 0~9, shifting it make it more easier to find the roots ff = f.subs({b: b + 5for b in b1 + b2}) # print(ff(*[x - 5 for x in kk1v + kk2v]))
M = matrix.column(ZZ, vector([ZZ(c) for c, _ in ff])) M = M.augment(matrix.identity(53)) M = M.stack(vector([n] + [0] * 53)) M = M.dense_matrix() row0 = M.LLL()[0] roots = [x + 5for x in row0[1:-1]] assert f(*roots) == 0# try again if failed k1 = PP(str(k1))(roots) k2 = PP(str(k2))(roots) print(f"found {k1 = }") print(f"found {k2 = }") d = ZZ(((s1 * k1 - z) / r1) % n) assert d == ((s2 * k2 - z) / r2) % n
# signing z = int(sha256(b"Flag").hexdigest(), 16) k = 48763 r = ZZ((k * G).xy()[0]) s = ((z + r * d) / k) % n io.sendlineafter(b"choice? ", b"2") io.sendlineafter(b"Which rule do you want to know? ", b"Flag") io.sendlineafter(b"x? ", str(r).encode()) io.sendlineafter(b"s? ", str(s).encode()) io.interactive()
# See also https://github.com/tsg-ut/pycryptodome from Crypto.PublicKey import DSA from Crypto.Signature import DSS from Crypto.Hash import SHA256 from Crypto.Util.number import getPrime from Crypto.Random.random import randrange from base64 import b64decode from signal import alarm import os
alarm(15)
q = getPrime(256) print(f'q = {q}')
p = int(input('p? ')) h = int(input('h? '))
g = pow(h, (p - 1) // q, p) x = randrange(q) y = pow(g, x, p)
from Crypto.PublicKey import DSA from Crypto.Signature import DSS from Crypto.Hash import SHA256 from base64 import b64encode from pwn import process, remote
defbackdoor(q): defgetP(bits): p = q * q phi = q * (q - 1) while p.bit_length() != bits: p *= 2 phi *= 2 return p, phi // 2
p, phip = getP(2048) assertpow(3, phip + 1, p) == 3 g = pow(3, phip // q, p) assertpow(g, q, p) == 1 h = g assertpow(pow(h, (p - 1) // q, p), q, p) == 1 return p, phip, h
awaitset_salt("flag") set_salt("then") // don't wait, it will block awaitsleep(100) // not needed, just don't make it too fast when testing locally awaitget_salt() // this prints the flag
defforward(self, xs): h = None for x in xs: h = self.cell(x, h) return self.out(h)
definference(model, text): model.eval() with torch.no_grad(): x = embedding("^" + text + "$").unsqueeze(1) y = model(x)[0].sigmoid().cpu().item() return y
model = Model(len(CHARS), 520) model.load_state_dict(torch.load("model_final.pth"))
# some checking for f in ["^T", "^TS", "^TSG", "^TSGX", "^TSGC", "^TSGCTF{"]: xx = embedding(f).unsqueeze(1) h = None for x, y inzip(xx, f): h = model.cell(x, h) print(f, [i for i, x inenumerate(h.tolist()[0]) if x > 0])
# BFS q = deque(["^TSGCTF{"])
whilelen(q) > 0: flag = q.popleft() print(flag) if ( flag.endswith("}") and model(embedding(flag + "$").unsqueeze(1)).sigmoid().cpu().item() > 0.5 ): print("FOUND", flag[1:]) break for c in FLAG_CHARS: f = flag + c xx = embedding(f).unsqueeze(1) h = None for x, y inzip(xx, f): h = model.cell(x, h) iflen([i for i, x inenumerate(h.tolist()[0]) if x > 0]) > 0and f notin q: q.append(f)