from Crypto.Util.number import * from Crypto.Cipher import AES from Crypto.Util.Padding import pad from hashlib import sha256
p = 142031099029600410074857132245225995042133907174773113428619183542435280521982827908693709967174895346639746117298434598064909317599742674575275028013832939859778024440938714958561951083471842387497181706195805000375824824688304388119038321175358608957437054475286727321806430701729130544065757189542110211847 a = 118090659823726532118457015460393501353551257181901234830868805299366725758012165845638977878322282762929021570278435511082796994178870962500440332899721398426189888618654464380851733007647761349698218193871563040337609238025971961729401986114391957513108804134147523112841191971447906617102015540889276702905 b = 57950149871006152434673020146375196555892205626959676251724410016184935825712508121123309360222777559827093965468965268147720027647842492655071706063669328135127202250040935414836416360350924218462798003878266563205893267635176851677889275076622582116735064397099811275094311855310291134721254402338711815917 s = 35701581351111604654913348867007078339402691770410368133625030427202791057766853103510974089592411344065769957370802617378495161837442670157827768677411871042401500071366317439681461271483880858007469502453361706001973441902698612564888892738986839322028935932565866492285930239231621460094395437739108335763 A = 27055699502555282613679205402426727304359886337822675232856463708560598772666004663660052528328692282077165590259495090388216629240053397041429587052611133163886938471164829537589711598253115270161090086180001501227164925199272064309777701514693535680247097233110602308486009083412543129797852747444605837628 B = 132178320037112737009726468367471898242195923568158234871773607005424001152694338993978703689030147215843125095282272730052868843423659165019475476788785426513627877574198334376818205173785102362137159225281640301442638067549414775820844039938433118586793458501467811405967773962568614238426424346683176754273 ct = bytes.fromhex( "e0364f9f55fc27fc46f3ab1dc9db48fa482eae28750eaba12f4f76091b099b01fdb64212f66caa6f366934c3b9929bad37997b3f9d071ce3c74d3e36acb26d6efc9caa2508ed023828583a236400d64e" )
defattack(c1, c2, e1, e2): g, a, b = xgcd(e1, e2) if g != 1: return return power_mod(c1, a, n) * power_mod(c2, b, n) % n
for t inrange(start - 10, start + 5): rng = Random(t) es = [rng.randint(1, n) for _ inrange(10)] for i inrange(len(es)): for j inrange(i, len(es)): m = attack(c1, c2, es[i], es[j]) if m isnotNoneandb"corctf{"in long_to_bytes(m): print(long_to_bytes(m)) exit() # corctf{y34h_th4t_w4snt_v3ry_h1dd3n_tbh_l0l}
from pwn import * from Crypto.Util.number import long_to_bytes
# context.log_level = "debug"
# io = process(["python", "corruptedcurves.py"]) io = remote("be.ax", 31345) io.recvuntil(b"p = ") p = ZZ(io.recvline()) io.recvuntil(b"flag y = ") flag_y = ZZ(io.recvline()) F = GF(p)
defget(): whileTrue: x = randint(2**384, p - 2**384) io.sendlineafter(b"x = ", str(x).encode()) io.recvuntil(b"e = ") e = ZZ(io.recvline()) r = io.recvline() ifb":("in r: continue y = ZZ(r.split(b" = ")[-1]) return x, y, e
defecc(a, b, x, y): return y ^ 2 - (x ^ 3 + a * x + b)
varnames = ",".join( ["at", "bt"] + [f"a{i}"for i inrange(64)] + [f"b{i}"for i inrange(64)] ) P = PolynomialRing(F, varnames) at, bt = P.gens()[:2] aa = P.gens()[2 : 2 + 64] bb = P.gens()[-64:]
from tqdm import tqdm
polys = [] for _ in tqdm(range(64)): x, y, e = get() aaa = [a if x == "0"else1 - a for a, x inzip(aa, f"{e:064b}"[::-1])] bbb = [b if x == "0"else1 - b for b, x inzip(bb, f"{e:064b}"[::-1])] aaaa = at * 2 ^ 64 + sum([x * 2 ^ i for i, x inenumerate(aaa)]) bbbb = bt * 2 ^ 64 + sum([x * 2 ^ i for i, x inenumerate(bbb)]) f = ecc(aaaa, bbbb, x, y) polys.append(f) pp = [] for f, g inzip(polys, polys[1:]): pp.append(f.sylvester_matrix(g, at).det()) ppp = [] for f, g inzip(pp, pp[1:]): ppp.append(f.sylvester_matrix(g, bt).det())
# LLL of large matrix is really slow M, v = Sequence(ppp[:16]).coefficient_matrix() print(vector(v)) M = M.T.dense_matrix() nr, nc = M.dimensions() print(nr, nc) B = block_matrix( ZZ, [[matrix.identity(nc) * p, matrix.zero(nc, nr)], [M, matrix.identity(nr)]] ) B[:, :nc] *= 2 ^ 512 print(B.dimensions()) B = B.LLL() print(B[0][nc:-1])
sol = B[0][nc:-1] raa = list(sol[:64]) rbb = list(sol[64:]) bt = ( pp[0] .subs({s: v for s, v inzip(aa + bb, raa + rbb)}) .univariate_polynomial() .roots(multiplicities=False)[0] ) at = ( polys[0] .subs({s: v for s, v inzip(aa + bb, raa + rbb)}) .subs(bt=bt) .univariate_polynomial() .roots(multiplicities=False)[0] ) a = ZZ((at * 2 ^ 64 + sum([x * 2 ^ i for i, x inenumerate(raa)]))) b = ZZ((bt * 2 ^ 64 + sum([x * 2 ^ i for i, x inenumerate(rbb)]))) print(a) print(b)
P = PolynomialRing(F, "x") x = P.gen() f = x ^ 3 + a * x + b - flag_y ^ 2 for x in f.roots(multiplicities=False): print(long_to_bytes(ZZ(x))) # corctf{i_h0pe_you_3njoyed_p1ecing_t0geth3r_th4t_curv3_puzz1e_:)}
defget(): whileTrue: try: r = io.recvuntil(b"more> ").splitlines() e = ZZ(r[-4].split(b" = ")[-1]) x = ZZ(r[-3].split(b" = ")[-1]) y = ZZ(r[-2].split(b" = ")[-1]) return x, y, e except: pass
defecc(a, b, x, y): return y ^ 2 - (x ^ 3 + a * x + b)
varnames = ",".join( ["at", "bt"] + [f"a{i}"for i inrange(48)] + [f"b{i}"for i inrange(48)] ) P = PolynomialRing(F, varnames) at, bt = P.gens()[:2] aa = P.gens()[2 : 2 + 48] bb = P.gens()[-48:]
from tqdm import tqdm
polys = [] for _ in tqdm(range(2 + 48 + 48)): x, y, e = get() aaa = [a if x == "0"else1 - a for a, x inzip(aa, f"{e:048b}"[::-1])] bbb = [b if x == "0"else1 - b for b, x inzip(bb, f"{e:048b}"[::-1])] aaaa = at * 2 ^ 48 + sum([x * 2 ^ i for i, x inenumerate(aaa)]) bbbb = bt * 2 ^ 48 + sum([x * 2 ^ i for i, x inenumerate(bbb)]) f = ecc(aaaa, bbbb, x, y) polys.append(f) M, v = Sequence(polys).coefficient_matrix() sol = vector(M[:, :-1].solve_right(-M[:, -1])) print(sol) at, bt = sol[:2] aa = sol[2 : 2 + 48] bb = sol[-48:] a = ZZ((at * 2 ^ 48 + sum([x * 2 ^ i for i, x inenumerate(aa)]))) b = ZZ((bt * 2 ^ 48 + sum([x * 2 ^ i for i, x inenumerate(bb)]))) print(a) print(b)
P = PolynomialRing(F, "x") x = P.gen() f = x ^ 3 + a * x + b - flag_y ^ 2 for x in f.roots(multiplicities=False): print(long_to_bytes(ZZ(x))) # corctf{cr4ftin6_f3as1ble_brut3s_unt1l_y0u_mak3_it!}
from hashlib import sha256 from Crypto.Cipher import AES from Crypto.Util.Padding import unpad from tqdm import tqdm import itertools
withopen("output.txt", "rb") as f, open("fixed.txt", "w") as f2: f2.write(f.read()[2:].decode("utf-16-le"))
withopen("fixed.txt") as f: c = int(f.readline().strip(), 16) c = f"{c:0{118*128}b}"[::-1] c = [c[i : i + 128] for i inrange(0, len(c), 128)] out = [sum([int(y) for y in x]) % 2for x in c] ct = bytes.fromhex(f.readline().strip()) iv, ct = ct[:16], ct[16:]
taps = [1, 2, 7, 3, 12, 73] P = PolynomialRing(GF(2), "x") x = P.gen() f = sum([x ^ i for i in taps]) + x ^ 128 M = companion_matrix(f, "bottom") M128 = M ^ 128
P = PolynomialRing(GF(2), ",".join([f"k{i}"for i inrange(128)])) s = vector(P.gens()) eqs = [] for i in tqdm(range(118), desc="progress"): eqs.append(sum(s) - out[i]) s = M128 * s
M, v = Sequence(eqs).coefficient_matrix() M = M.dense_matrix() sol0 = vector(M[:, :-1].solve_right(-M[:, -1])) ker = M[:, :-1].right_kernel().basis_matrix()
for z in itertools.product([0, 1], repeat=ker.dimensions()[0]): sol = sol0 + vector(GF(2), z) * ker kk = sum([x * 2 ^ i for i, x inenumerate(sol[::-1].change_ring(ZZ))]) aeskey = sha256(int(kk).to_bytes(16, "big")).digest()[:32] cip = AES.new(aeskey, AES.MODE_CBC, iv=iv) flag = cip.decrypt(ct) ifb"corctf{"in flag: print(unpad(flag, 16)) # corctf{m4yb3_w3_sh0uld_ju5t_cut_hum4n5_0ut_0f_th1s_c0mpl3t3ly_1f_th3y_d3c1d3_t0_f4k3_shuffl3_0r_s0m3th1ng}
花上很久的時間看 code 後我在測試一些東西的時候把題目的檔案用 prettier
給 format 了,就找到了它有問題的點:
1 2 3 4 5 6
const mine = followers.get(req.username)
// force all params to be strings for safety [body.u, body.r, body.n] = params.map( p => (body[p] ?? '').toString() )
上面是一段在 /follow 裡面的
code,看起來相當正常,但是只要你 format 之後它就會變成這樣:
1 2 3 4
const mine = (followers.get(req.username)[ // force all params to be strings for safety (body.u, body.r, body.n) ] = params.map(p => (body[p] ?? '').toString()))
// get followers const mine = followers .get(req.username) .filter(v => v !== undefined)
if (mine.includes('admin')) { // lock the account so people don't stumble onto the flag users.set(req.username, crypto.randomBytes(16).toString('hex'))
// give the flag return res.send( `Endorsed by the admin?! Here's your flag: ${process.env.FLAG}` ) }
letmut user: User = match serde_json::from_value(body) { Ok(user) => user, Err(_) => { returnJson(APIResponse { status: APIStatus::Error, data: None, message: Some(String::from("Missing username or password")), }) } };
if user.username.len() < 5 || user.password.len() < 7 { returnJson(APIResponse { status: APIStatus::Error, data: None, message: Some(String::from("Username or password too short")), }); }
if DB.contains_key(&user.username) { returnJson(APIResponse { status: APIStatus::Error, data: None, message: Some(String::from("A user already exists with that username")), }); }