HITCON CTF 2019 Quals Writeup October 15, 2019 # Misc ### EmojiiVM It's too long to directly print each character, but we can push 1,1,1,2,...,9,9 into the stack, and write a simple loop to print the table. Unfortunately my blog doesn't support emojis, so here's no solution. ### heXDump Xxd only overwrites the first bytes of the file, so we can just enumerate each byte. ```python from pwn import * r=remote('13.113.205.160',21700) def get(): r.recvuntil('0) quit\n') r.send('2\n') return r.recvuntil('\n')[:-1] r.recvuntil('0) quit\n') r.send('1337\n') fh=get() known='hitcon{' while True: flag=False for j in range(32,127): print j t=known+chr(j) r.recvuntil('0) quit\n') r.send('1\n') r.recvuntil('format)\n') r.send(t.encode('hex')+'\n') if get()==fh: known=t flag=True break print known if not flag: break ``` # Crypto ### Very Simple Haskell If a bit in the flag is 1, the answer will multiply square of a specific prime number. Then we can use meet-in-middle to find the answer. However, here N is too big, so just factorize the primes is okay. ```python from gmpy2 import * from Crypto.Util.number import isPrime primes=[] pinv={} for i in range(2,5000): if isPrime(i): pinv[i]=len(primes) primes.append(i) print(len(primes)) n=134896036104102133446208954973118530800743044711419303630456535295204304771800100892609593430702833309387082353959992161865438523195671760946142657809228938824313865760630832980160727407084204864544706387890655083179518455155520501821681606874346463698215916627632418223019328444607858743434475109717014763667 base=129105988525739869308153101831605950072860268575706582195774923614094296354415364173823406181109200888049609207238266506466864447780824680862439187440797565555486108716502098901182492654356397840996322893263870349262138909453630565384869193972124927953237311411285678188486737576555535085444384901167109670365 req=84329776255618646348016649734028295037597157542985867506958273359305624184282146866144159754298613694885173220275408231387000884549683819822991588176788392625802461171856762214917805903544785532328453620624644896107723229373581460638987146506975123149045044762903664396325969329482406959546962473688947985096 req=req*invert(base,n)%n flag='hitcon{' for i in range(6): t=0 for j in range(8): r=28+i*8-j if req%primes[r]==0: t|=1<15 else 120 for i in range(1,16): for j in f[i-1]: x,y=j if y>len(s)-x: continue v=f[i-1][j] for k in range(1+min(y,len(s)-x)): if (y-k)*2>len(s)-(x+k): continue nv=(ps[x+k]-ps[x])*i+v upd(f[i],g[i],(x+k,(y-k)*2),nv,j) if x+k==len(s): if nv>i&1) else: assert x t=0 while x>>t: t+=1 for i in range(t-2,-1,-1): s.append(x>>i&1) @nb.jit(nopython=True) def compress(s): t={-1:-1} t.pop(-1) for i in s: t[i]=0 for i in s: t[i]+=1 for i in range(10): t[i+48]+=100 t[34]+=40 t2=[] for i in t: t2.append((t[i],i)) t=t2 t.sort() t=t[::-1] tx=[] for i2 in t: tx.append(i2[0]) tx.append(1) tp=[4]*11+[5]*8+[6]*4 tpx=[0 for i in range(257)] for i in range(len(t)): tpx[t[i][1]]=tp[i] tpx[256]=tp[-1] tpc=get_hdict(tpx) tl=getkl(tpx+[0]) tlu={} for ii in tl: tlu[ii[0]]=0 for ii in tl: tlu[ii[0]]+=1 tlux=[] for i in tlu: tlux.append((tlu[i],i)) tlux.sort() tlux=tlux[::-1] tlk_=[] for ii in tlux: tlk_.append(ii[0]) tlkl=cal_huffman(tlk_) tlklu=[0]*19 for i in range(len(tlux)): tlklu[tlux[i][1]]=tlkl[i] res=[0] res.pop() res+=[1] #final ad(res,2,2) #type ad(res,5,0) #hlit ad(res,5,0) #hdist tlklc=get_hdict(tlklu) rest=[0] rest.pop() ad(rest,3,tlklu[16]) ad(rest,3,tlklu[17]) ad(rest,3,tlklu[18]) ad(rest,3,tlklu[0]) tlklu[16]=0 tlklu[17]=0 tlklu[18]=0 tlklu[0]=0 for i in range(100): su=0 for j in tlklu: su+=j if su==0:break j = (8 + i // 2) if (i % 2 == 0) else (7 - i // 2) ad(rest,3,tlklu[j]) tlklu[j]=0 ad(res,4,(len(rest)-12)/3) #hclen res+=rest for ii in tl: ad(res,-1,tlklc[ii[0]]) if ii[0]==16: ad(res,2,ii[1]) elif ii[0]==17: ad(res,3,ii[1]) elif ii[0]==18: ad(res,7,ii[1]) for i in s: ad(res,-1,tpc[i]) ad(res,-1,tpc[256]) while len(res)%8: res+=[0] fin=[] for i in range(0,len(res),8): tuu=0 for j in range(8): tuu+=res[i+j]<t2[-1][0]+(1<<1900) or (t2[-1][0].bit_length()==2048 and j[0].bit_length()==2048 and t2[-1]!=j): t2.append(j) t=t2 t=t[:K] tb=t[0][0].bit_length() if i%10==0: print i+1,os-tb,'%.5f'%((os-tb)/(i+1.)) s=t if t[0][0].bit_length()==2048: cnt+=1 if cnt>=15: break full=(1<<2048)-1 mask=full for i in range(len(s)-1): if s[i+1][0].bit_length()!=2048: continue t=full^s[i][0]^s[i+1][0] if (t>>2045)!=7: continue mask&=t mask^=full t=0 while (1<2: sn=[] st=[] for j in s: if j[-1]: st.append(j) else: sn.append(j[:-1]) for j in range(len(st)-1): a=st[j] b=st[j+1] at=mul(a,b[-1]) bt=mul(b,a[-1]) t=sub(at,bt) assert t[-1]==0 sn.append(t[:-1]) s=sn for i in s: if i[0]: a,b=i g=gcd(a,b) a/=g;b/=g tn=sold[0]/abs(b) tn*=req/tn if req%tns[i] res+=c*fac[len(s)-i-1] return res def fkth(n,k): s=[0 for i in range(n)] for i in range(n-1,-1,-1): s[i]=n-i-1-(k%fac[n-i]//fac[n-i-1]) for j in range(i+1,n): if s[j]>=s[i]: s[j]+=1 return s def fwalk(s,k): t=fcount(s) t=max(0,t-k) st=fkth(len(s),t) s.sort() res=[] for i in st: res.append(s[i]) return res fac=[1] for i in range(1,100): fac.append(fac[-1]*i) def ROR4(x,y): x%=(1<<32) assert y>=0 and y<32 return ((x>>y) | (x<<(32-y))) % (1<<32) def keystr(s): r='%016x'%s u='' for i in range(16,0,-2): u+=r[i-2:i] return u L=49 enc='04dd5a70faea88b76e4733d0fa346b086e2c0efd7d2815e3b6ca118ab945719970642b2929b18a71b28d87855796e344d8' for key in range(1<<16): raw=[0]*L okey=key key=(6364136223846793005*(key%0x10000)+6364136223846793006)%(1<<64) for T in range(16): Carr=[_ for _ in range(256)] for v41 in range(255,0,-1): v154=v41+1 v51=key if ((1<<32)-v154)%v154: v155=key while True: v155 = (1 + 6364136223846793005 * v155) % (1<<64) v156 = ROR4((v51 ^ (v51 >> 18)) >> 27, v51 >> 59) v51 = v155 if v156 < (1<<32) - (((1<<32)-v154) % v154): break else: v155 = (1 + 6364136223846793005 * v51) % (1<<64) v157 = (v51 ^ (v51 >> 18)) >> 27 v51 >>= 59 v156 = ROR4(v157, v51) key = v155 v158 = v156 % v154 Carr[v41],Carr[v158]=Carr[v158],Carr[v41] dest = 0 for i in range(0,64,32): dest += ROR4((key ^ (key >> 18)) >> 27, key >> 59) << i key = (1 + 6364136223846793005 * key) % (1<<64) Darr = Carr[:L] Darr=fwalk(Darr,dest) tmp=[] for i in range(L-1,-1,-1): tmp.append(raw[i]^Darr[i]) raw=tmp res='' ok=True for i in range(0,L*2,2): t=int(enc[i:i+2],16)^raw[i//2] res+=chr(t) ok=ok and t>=32 and t<=127 if ok: print(res) if okey%100==0: print(okey) ```