from Crypto.Util.number import * from random import * from secret import flag from uuid import UUID p=1329596764371107264260948790524463667078201288962092988229220331099216972202747986235496117149730240332402358728798174199576808159410988077039863933883707283021432596510812652195899704038126374630854432891580277457310166342238907250055728526757955693768208634626765002269557414142205735568171344541059676587026552819564587252379527557854007769644766922798602628730499830452043996042865583066303024746135216694290599886977846557408057361447210602309239731866416103 q=664798382185553632130474395262231833539100644481046494114610165549608486101373993117748058574865120166201179364399087099788404079705494038519931966941853641510716298255406326097949852019063187315427216445790138728655083171119453625027864263378977846884104317313382501134778707071102867784085672270529838293513276409782293626189763778927003884822383461399301314365249915226021998021432791533151512373067608347145299943488923278704028680723605301154619865933208051 g=25 a=randint(3,q-3) for i inrange(64): print(f'g**(a**{i})=',pow(g,pow(a,i,q),p)) f=[randint(3,2**64) for i inrange(64)] f[-1]=1
fa=0 for i inrange(64): fa+=f[i]*pow(a,i,q)%q fa%=q w=None while(1): w=(a+randint(1,q-3))%q fw=0 for i inrange(64): fw+=f[i]*pow(w,i,q)%q fw%=q if(fw): break
from Crypto.Util.number import * from uuid import * p=1329596764371107264260948790524463667078201288962092988229220331099216972202747986235496117149730240332402358728798174199576808159410988077039863933883707283021432596510812652195899704038126374630854432891580277457310166342238907250055728526757955693768208634626765002269557414142205735568171344541059676587026552819564587252379527557854007769644766922798602628730499830452043996042865583066303024746135216694290599886977846557408057361447210602309239731866416103 q=664798382185553632130474395262231833539100644481046494114610165549608486101373993117748058574865120166201179364399087099788404079705494038519931966941853641510716298255406326097949852019063187315427216445790138728655083171119453625027864263378977846884104317313382501134778707071102867784085672270529838293513276409782293626189763778927003884822383461399301314365249915226021998021432791533151512373067608347145299943488923278704028680723605301154619865933208051 g=25 gapow=[] D=open('Crypto03.py','r').readlines()[36:] for i inrange(64): line=D[i] line=line.split('=') gai=int(line[1]) gapow.append(int(gai)) PR=PolynomialRing(Zmod(q),name='X') X=PR.gen(0) line=D[64] line=line.split('=') f=PR(eval(line[1])) line=D[65] line=line.split('=') w=int(line[1]) line=D[66] line=line.split('=') h=int(line[1])
fdivxw=list(f//(X-w)) fmodxw=f%(X-w)
G=1 for i inrange(63): G*=pow(int(gapow[i]),int(fdivxw[i]),p) G%=p u=h*inverse(G,p) AAA=(pow(u,inverse(int(fmodxw),q),p)) print(UUID(int=AAA%(2**128))) #susctf{0bf4a7d7-59f8-35ab-6866-687b470f7f36}
import random as random2 import os from sage.allimport * from sage.stats.distributions.discrete_gaussian_integer import DiscreteGaussianDistributionIntegerSampler as DGDIS n=128 p=31337 D=DGDIS(sigma=1) #Generate the discrete gaussian distribution with sigma = 1
from sage.allimport * from pwn import * from tqdm import * import random n=128 q=31337 sh=process(['python3','task.py']) sh.recvuntil(b':') seedA=sh.recvline(keepends=False).strip() rng=random.Random() rng.seed(seedA) while(1): A=matrix(Zmod(q),[[rng.randint(0,99) for _ inrange(n)]for __ inrange(n)]) if(A.rank()==n): break
Recv=[] for i in tqdm(range(600)): sh.recvuntil(b'>') sh.sendline(b'1') res=eval(sh.recvline(keepends=False)) Recv.append(res)
y=[] for i inrange(n): D=dict() for j inrange(600): D[Recv[j][i]]=1+D.get(Recv[j][i],0) ansi,anst=None,0 for u,v in D.items(): if(v>anst): ansi,anst=u,v y.append(ansi) y=vector(Zmod(q),y) s=A.solve_right(y) print(bytes(s.change_ring(Zmod(200))))
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) # 接收并解析公开种子 seedA = s.recv(1024).decode().split("Public Seed:")[1].strip() # 初始化随机数生成器 rng = random2.Random() rng.seed(seedA.encode())
# 生成满秩的随机矩阵A A = None whileTrue: A = np.array([[rng.randint(0, 99) for _ inrange(n)] for _ inrange(n)], dtype=int) % p if np.linalg.matrix_rank(A) == n: break
# 发送请求获取NUM_Y个y向量 y_list = [] for _ inrange(NUM_Y): try: s.sendall(b"1\n") time.sleep(0.1) # 接收并解析y向量(注意:eval存在安全风险,实际使用可替换为更安全的解析方式) y = eval(s.recv(4096).decode().strip()) iflen(y) == n: y_list.append([yi % p for yi in y]) except: continue
# 发送请求获取c向量(y向量的均值) s.sendall(b"2\n") # 计算y向量的均值并取整、模p c = np.round(np.mean(np.array(y_list, dtype=int), axis=0)).astype(int) % p
# 计算矩阵A的模p逆矩阵 A_inv = matrix_mod_inverse(A, p) if A_inv isNone: return
# 计算s向量并解析为flag s_list = (np.dot(A_inv, c) % p).astype(int).tolist() flag = "".join(map(get_flag_char, s_list)) print(flag) # 提取并打印包含{}的flag核心部分 if"{"in flag and"}"in flag: print(flag[flag.index("{"):flag.index("}") + 1])
from Crypto.Util.number import * for i inrange(10,40): for j inrange(8): for k inrange(8): r=2*3**i*5**j*7**k+1 if(isPrime(r) and r.bit_length() inrange(33,50)): print(r.bit_length(),i,j,k,r)
for i in tqdm(range(100)): sh.recvuntil(b'>') sh.sendline(b'1') sh.recvuntil(b'>') sh.sendline(b'1 '*512) D=dict() for i inrange(32,128,5): sh.recvuntil(b'>') sh.sendline(b'1') sh.recvuntil(b'>') sh.sendline((f'{i} '*100+f'{i+1} '*100+f'{i+2} '*100+f'{i+3} '*100+f'{i+4} '*100).encode()) A=eval(sh.recvline()) for j inset(A[:100]): D[j]=i for j inset(A[100:200]): D[j]=i+1 for j inset(A[200:300]): D[j]=i+2 for j inset(A[300:400]): D[j]=i+3 for j inset(A[400:500]): D[j]=i+4 sh.recvuntil(b'>') sh.sendline(b'2') sh.recvuntil(b'=') C=eval(sh.recvline()) F=[] for i in C: F.append(D[i]) print(bytes(F)) #b'susctf{gcd_P_MInus_on3_aNd_EXPOnENt14I_M4K35_THi5_sTr34M_Clph3R_lnSEcURE_0aBCl59dZbAee76f}'
from pwn import * from Crypto.Util.number import * HOST = "106.14.191.23" PORT = 55011 P = getPrime(33) FLAG_PREFIX = "susctf("
defsend_option(r, option): r.sendlineafter(b'Give me your option>', str(option).encode())
defencrypt(r, msg_list): send_option(r, 1) msg_str = "".join(map(str, msg_list)) r.sendlineafter(b"Input your message array(Decimal Format)>", msg_str.encode()) r.recvuntil(b'[') ciph_str = r.recvuntil(b']', drop=True).decode() return [int(x) for x in ciph_str.split(',')] if ciph_str else []
defget_flag_cipher(r): send_option(r, 2) r.recvuntil(b'Cipher of flag: [') ciph_str = r.recvuntil(b']', drop=True).decode() return [int(x) for x in ciph_str.split(',')]
defsolve(): r = remote(HOST, PORT, timeout=10) r.sendlineafter(b'Please give me a 325 bit prim modulus', str(P).encode())
defbacktrack(pos, current_flag, h_dict): if solution or pos == len(flag_cipher): if pos == len(flag_cipher): solution.append(current_flag) return base_s = initial_state[offset + pos - found_L] # 优先匹配前缀 chars_to_try = [ord(FLAG_PREFIX[pos])] if pos < len(FLAG_PREFIX) elserange(256) for m in chars_to_try: for d in D: s_pred = pow(base_s, d, P) h_pred = flag_cipher[pos] - s_pred # 检查候选合法性和冲突 if h_pred notin h_candidates.get(m, []): continue ifany(v == h_pred and k != m for k, v in h_dict.items()): continue backtrack(pos + 1, current_flag + chr(m), {**h_dict, m: h_pred})
backtrack(0, "", {0: found_H0}) print("Flag:", solution[0] if solution else"未找到") r.close()
classLFSR: def__init__(self,n,p,seed): self.n=n self.p=p self.mask=[1]+[randint(0,p-1) for _ inrange(n-1)] self.state=seed[:n] while(len(self.state)<n): self.state.append(len(self.state)) defgetstate(self): ret=sum([u*v%self.p for u,v inzip(self.state,self.mask)])%self.p self.state.append(ret) self.state.pop(0) return ret
p=getPrime(208) h=32328345448461253988278351927 lfsr1=LFSR(45,p,[randrange(200,p-200,200)+ord(i) for i in token[:45]]) lfsr2=LFSR(45,h,[randrange(200,h-200,200)+ord(i) for i in token[45:]]) print(f'p={p}') print(f'mask={lfsr1.mask}') MONEY = 97 isHint=False cHint=800 for i inrange(500): MENU=f""" ++++++MENU+++++++++ +1.Guess $ 1+ +2.BuyHint $350+ +3.SubmitTkn $2000+ +0.Exit + ++++++NFSR+3+++++++ DOLLAR:{str(MONEY).zfill(4)} CHANCE:{str(500-i).zfill(4)} """ print(MENU) op=int(input('Choice>')) if(op==1): MONEY-=1 x=int(input('Your Guess>')) u=lfsr1.getstate()^((lfsr2.getstate())) if(u==x): print(f'AC, Your answer:{x} Right answer:{u}') MONEY+=7 elif(abs(u-x)<=h): print(f'PC, Your answer:{x} Right answer:{u}') MONEY+=2 else: print(f'WA, Your answer:{x} Right answer:{u}') if(MONEY==0): exit(0) elif(op==2): if(MONEY<350): print(f'Sorry, The hint cost $350, You only have ${MONEY}') continue else: MONEY-=350 print(f'lfsr2.mask={lfsr2.mask}') print(f'lfsr2.state={lfsr2.state}') isHint=True elif(op==3): if(MONEY<2000): print(f'Sorry, token submission cost $2000, You only have ${MONEY}') else: MONEY-=2000 token1=input('NOW! GIVE ME MY TOKEN!>').strip() if(token1.upper()==token): FLAG=getenv('GZCTF_FLAG') print(f'Congraduations! here is your flag!!!:{FLAG}') else: print('Sorry, but I think you could have your flag...') else: exit(0)
harr=D[:90] for i inrange(45): f=sum([u*v for u,v inzip(A,harr[i:45+i])])+sum([u*v for u,v inzip(A,xarr[-45:])])-harr[45+i] xarr.append(f)
B=[] v=[] for i inrange(45,90): f=xarr[i].coefficients() B.append(f[:-1]) v.append(f[-1]) B=matrix(B) print(B.nrows(),B.ncols()) M=block_matrix(ZZ, [ [identity_matrix(45),matrix(B).T,0], [zero_matrix(45),p*identity_matrix(45),0], [zero_matrix(1,45),matrix(v),h], ])
M3L=M.LLL() larr=None for vec in M3L: if(abs(vec[-1])==h): larr=vec*sgn(vec[-1]) break
Z=[larr[i]+harr[i] for i inrange(90)] S=[Z[i]^harr[i] for i inrange(90)] print(Z) print(S)
M=[S[i:i+45] for i inrange(45)] y=S[45:90] p1,p2,p3=1754143 , 6669342923 , 2763347071643 Mp1,Mp2,Mp3=[matrix(Zmod(ppx),M) for ppx in [p1,p2,p3]] vp1,vp2,vp3=[vector(Zmod(ppx),y) for ppx in [p1,p2,p3]] up1,up2,up3=[mmm.solve_left(vvv).change_ring(ZZ) for mmm,vvv inzip([Mp1,Mp2,Mp3],[vp1,vp2,vp3])] print(up1) print(up2) print(up3) B=[crt([up1[i],up2[i],up3[i]],[p1,p2,p3]) for i inrange(45)] Y=S[-45:] print(Y) print(B)
Z=Z[-45:]
for i in tqdm(range(350)): Next=sum([u*v for u,v inzip(A,Z)])%p Mext=sum([u*v for u,v inzip(B,Y)])%h sh.recvuntil(b'>') sh.sendline(b'1') sh.recvuntil(b'>') sh.sendline(str(Next^Mext).encode()) sh.recvuntil(b'Right answer:') S.append(int(sh.recvline(keepends=False))^Next) Z.append(Next) Z.pop(0) Y.append(Mext) Y.pop(0)
for i inrange(350+90): yi=Y.pop(-1) zi=Z.pop(-1) diffy=sum([u*v for u,v inzip(B[1:],Y)])%h diffz=sum([u*v for u,v inzip(A[1:],Z)])%p Y=[(yi-diffy)%h]+Y Z=[(zi-diffz)%p]+Z print(bytes(list(vector(Zmod(200),Z)))) print(bytes(list(vector(Zmod(200),Y)))) TKN=bytes(list(vector(Zmod(200),Z)))+bytes(list(vector(Zmod(200),Y))) sh.recvuntil(b'>') sh.sendline(b'3') sh.recvuntil(b'>') sh.sendline(TKN) print(sh.recvall(timeout=4)) sh.close()
# 参考https://0xffff.one/d/1064 defsolve_lfsr1_state(T, p, mask): """根据T,p,mask求解lfsr1的初始state""" # 这里实现具体的LFSR状态恢复算法 # 返回lfsr1的初始state defBabai(B, t): # not square when using .LLL(), so use IntegerLattice ... B = IntegerLattice(B, lll_reduce=True).reduced_basis G = B.gram_schmidt()[0] b = t for i inreversed(range(B.ncols())): b -= B[i] * ((b * G[i]) / (G[i] * G[i])).round() return t - b
n = 45 m = len(T)
# 状态转移矩阵 A A = Matrix(ZZ, n) for i inrange(n-1): A[i,i+1] = 1 A[n-1,:] = vector(ZZ, mask)
# 初始化 C C = [] mask_vec = vector(ZZ, mask)
# 构造每一行 A_power = identity_matrix(ZZ, n) # A^0 for i inrange(m): row = (mask_vec * A_power) % p # 对每个元素模 p row = vector(ZZ, row) # 确保是 Sage 整数向量 C.append(row) A_power = (A_power * A) % p # 下一步 A^(i+1) 也模 p
CC=C # print(C[0]) C = Matrix(ZZ, C)
A = C b = vector(ZZ, T) p = p r = A.nrows() c = A.ncols()
pIr = p*identity_matrix(r) #M = block_matrix([[A.transpose()], [pIr]]) # [x, k]*[[A.t], [pIr]] = (b-e).t (but not work ... M = block_matrix([[pIr], [A.transpose()]]) # [k, x]*[[pIr], [A.t]] = (b-e).t (this works ... br = Babai(M, b)
print('e = %s' % (b-br)) R = IntegerModRing(p) Ar = matrix(R, CC) state = Ar.solve_right(br)
print("求解lfsr1初始状态完成") print("state:", state) return state
defsolve_lfsr2_and_token(T, p, mask, lfsr1_state): """根据T,p,mask,lfsr1_state求解lfsr2的mask、state和token""" # 这里实现具体的求解算法 h = 32328345448461253988278351927
classLFSR: def__init__(self,n,p,seed): self.n=n self.p=p self.mask=[1]+[randint(0,p-1) for _ inrange(n-1)] self.state=seed[:n] while(len(self.state)<n): self.state.append(len(self.state)) defgetstate(self): ret=sum([u*v%self.p for u,v inzip(self.state,self.mask)])%self.p self.state.append(ret) self.state.pop(0) return ret
defChall(): p=int(input('Give me your prime>')) if(p.bit_length()<226or p.bit_length()>333ornot isPrime(p)): print('Invaid prime!') exit(1) a,b=[int(i)%p for i ininput('Give me your parameters>').split()] assert a**2+b**2 v=2 while(pow(v,p>>1,p)==1): v+=1 Fq2=GF((p,2),modulus=[-v,0,1],name='sqv') E=EllipticCurve(Fq2,[a,b]) x1,x2=[Zmod(p)(i) for i ininput('Give me 2 base points(x_coordinate)>').split()] G1=E.lift_x(x1) G2=E.lift_x(x2) assert G1.order()==G2.order() orderG=G1.order()
defListG(Gx): Gxy=Gx.xy() r=[] r=list(Gxy[0])+list(Gxy[1]) returntuple(r) print(f'Your Point G1: {ListG(G1)}') print(f'Your Point G2: {ListG(G2)}')
for i inrange(44): u,v=random2.randint(0,globalPrime),random2.randint(0,globalPrime) print(f'Your Point:{ListG(u*G1+v*G2)}') u1,v1=[int(i) for i ininput('Give me your answer Result>').split()] assert u1==u and v1==v
for _ inrange(2): op=int(input('Give me your option>')) if(op==1): GetFlag() elif(op==2): Chall() else: exit(0)
qh32=[] qhtmp=qh for i inrange(10): qh32.append(qhtmp&0xffffffff) qhtmp>>=32 print(qh32)
from mttool import MT19937 mt=MT19937() mt.setstate(qh32[-8:]+D) mt.invtwist() mt.invtwist() R=[] for i inrange(624+8): R.append(mt.getstate()) q=0 for i inrange(40): q<<=32 q|=R.pop(-1) print(q,q.bit_length()) q=next_prime(q) print(N%q) p=N//q d=inverse(E,(p-1)*(q-1)) print(long_to_bytes(pow(int(C),int(d),int(N))))
ESEED=[rng.randint(0,6) for _ inrange(5)] ESEED[rng.randint(0,4)]=rng.randint(1,6) EMASK=[rng.randint(0,6) for _ inrange(5)] EMASK[rng.randint(0,4)]=rng.randint(1,6) rng.seed(os.urandom(33)) rng.shuffle(ESEED) rng.shuffle(EMASK) lfsr57=LFSR(5,7,ESEED,EMASK)
token=''.join([random2.choice('0123456789ABCDEFGHJK')for _ inrange(256)]) s=[ord(ch) for ch in token] s=QR(s) seedA=os.urandom(48).hex() print('seedA= ',seedA)
rngA=random2.Random() rngA.seed(seedA) for i inrange(548): op=int(input('Give me your option>')) if(op==1): A=QR([rngA.randint(0,q-1) for _ inrange(256)]) e=QR([ERR[lfsr57.getstate()] for _ inrange(256)]) print('Your Cipher=',list(A*s+e)) elif(op==2): token1=input('GIVE ME MY TOKEN>').strip() if(token1==token): print('Congraduations! Here is your flag:',os.getenv('GZCTF_FLAG')) else: print('Sorry, Wrong Token')
eqArr=[] for T in tqdm(range(547)): sh.recvuntil(b'>') sh.sendline(b'1') sh.recvuntil(b'=') b=eval(sh.recvline().strip()) A=QR([rngA.randint(0,q-1) for _ inrange(256)]) Am=A.matrix().T for j inrange(256): eqArr.append((Am[j],b[j]))
for T in tqdm(TCandidate): eqs=eqArr[::T][:256] M=[] y=[] for i inrange(256): M.append(eqs[i][0]) y.append(eqs[i][1]) M=matrix(Zmod(q),M) for i inrange(251): vecy=vector(Zmod(q),[yj-i for yj in y]) try: token=list(M.solve_right(vecy)) if(all([j in [48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,71,72,74,75] for j in token])): sh.recvuntil(b'>') sh.sendline(b'2') sh.recvuntil(b'>') sh.sendline(bytes(token)) print(sh.recvall(timeout=4)) exit(0) except Exception as e: print(e)
9.总结
SUSCTF 2025也算是成功地举办了,自己从 2024 年的参赛,到 2025 年的出题,感觉一下子仿佛回到了 4 年前自己从参加 0xGame 到 0xGame出题的过程。2025年不知不觉也只剩下四分之一了,顺便回顾了一下自己的2025,之前CTF拿了个省奖,还拿到了密码数学挑战赛的国奖,最后自己规格化总分 86.18 排名年级 397 人第 2,南京校区 221 人第 1(上次拿年级第一甚至还是2015年;上次去西安也是2015年(甚至那一次和今年一样都是8月19日去的西安);笑死,10 years ago once more是吧)。科研的话,目前自己也开始跟着导师一起,步入了正式的轨道,开始了正式地理论推导 和 实验研究过程。