corCTF 2021 writeup
久しぶりにwriteupを書く気がします。
Result
Writeup
misc
yeetcode
Brush up on your coding skills and ace your next interview with YeetCode! Flag is at ./flag.txt
https://yeetcode.be.ax
ファイル:yeetcode.tar.xz
引数a, bが渡されるとその和を返り値とする関数fを作るとCongrat!とほめてくれますほめてくれます。
def f(a,b): return a+b
tar.xzを解凍してyeet.pyを見るとテストケース10個の内2個は固定値でした。固定値かどうかは実際関係なかったのです。
FLAGが./flag.txtにあるということで、このプログラムから開けないか試してみました。
def f(a,b): g = open("./flag.txt","rb").read() return a+b
このプログラムを提出したところ、エラーは吐かれませんでした。ということはファイルを開けたでしょう。あとは手作業ゲーです。
def f(a,b): #example g = open("./flag.txt","rb").read() if g[0] == ord("c"): return a+b else: return 0
これでg[0]が"c"かどうか分かります。if文が真ならCongrat!と褒められ、偽なら当たってないと言われます。if文をこんな限定的にせず、二分探索とかの方が効率的です。
corctf{1m4g1n3_cp_g0lf_6a318dfe}
crypto
fibonary
Warmup your crypto skills with the superior number system!
ファイル:enc.py, flag.enc
フィボナッチ数列のナップザック暗号ですね。超増加数列ではありませんが、復号可能です。
f = open("flag.enc") a = f.readlines() print(a) enc = a[0].split() print(enc) fib = [1, 1] for i in range(2, 11): fib.append(fib[i - 1] + fib[i - 2]) flag = "" for i in range(len(enc)): val = 0 for j in range(len(enc[i])): if enc[i][j] == "1": val += fib[len(fib)-1-j] flag += chr(val) print(flag)
corctf{b4s3d_4nd_f1bp!113d}
4096
I heard 4096 bit RSA is secure, so I encrypted the flag with it.
ファイル:4096.tar.xz
nが32bit素数128個の積であるmultiple prime RSAです。
factorDBでは素因数分解できないので、sageに投げます。
from Crypto.Util.number import * n = (中略) c = (中略) e = 65537 fac = "(中略)" #sagemathの結果を入れる primes = list(map(int,fac.split(" * "))) phi = 1 for p in primes: phi *= (p-1) d = inverse(e,phi) m = pow(c,d,n) print(long_to_bytes(m))
corctf{to0_m4ny_pr1m3s55_63aeea37a6b3b22f}
dividing_secrets
I won't give you the secret. But, I'll let you divide it.
nc crypto.be.ax 6000
ファイル:server.py
離散対数問題ですが、変数divに代入する値を適切にすれば簡単に解けます。
flagの最終文字を求めます。
x = 256k+l とすると、lが最終バイトです。div=256を投げると、gk を渡されます。それを256乗し、その値とg×lがencrypted flagになります。lは256通りしかないのでbrute forceで解けます。
flagの最終2文字目を求めます。
先ほどのkがxに該当します。なのでencrypted flag = gkとなります。
k = 256k'+l' となり、l'を先と同様に求めます。
これらを繰り返しflagの全ての文字を求めていきます。
HOST, PORT = "crypto.be.ax", 6000 s, f = sock(HOST, PORT) g = int(read_until(f).split()[-1]) p = int(read_until(f).split()[-1]) enc = int(read_until(f).split()[-1]) t = 1 bef = enc flag = "" for i in range(64): t *= 256 print(i,read_until(f,"number> ")) s.send(str(t).encode()+b"\n") tmp = int(read_until(f).strip()) print(tmp) for j in range(256): if (pow(tmp,256,p)*pow(g,j,p))%p == bef: flag += chr(j) break bef = tmp print("flag =",flag[::-1])
corctf{qu4drat1c_r3s1due_0r_n0t_1s_7h3_qu3st1on8852042051e57492}
supercomputer
I ran this code with a supercomputer from the future to encrypt the flag, just get your own and decryption should be simple!
ファイル:supercomputer.tar.xz
n = (pq) × r, a1 = randrange(n), t = (a1n) + ( (n-a1)n) とあります。flagがv(p, t) とxorされます。
関数vは、tが素数pの何乗で割り切れるかの最大値を返り値とします。
ではtはpで何回割れるのでしょうか? tを展開します。
( (n-a1)^n) =n^n - C0×n^(n-1)×a1 + ... + Ck×n×a1^(n-1) - a1^n
となり、最終項が(a1n)と打ち消されます。
この時点でtがnの倍数であることが分かります。( (n-a1)n) を展開した際にnが掛けられない唯一の項が打ち消されました。
次に、( (n-a1)n) の最終2項目の係数Ckを求めます。パスカルの三角形を考えると、x乗するときの2項目と最終2項目の係数はxです。つまりCk = nです。
( (n-a1)^n) =n^n - C0×n^(n-1)×a1 + ... + Ck'×n^2×a1^(n-2)+ n×n×a1^(n-1) - a1^n
a1n 以外n2で括ることができる=tがn2の倍数であることが分かりました。
n = (pq) × rより、tがn2の倍数であれば2q回pで割れます。ゆえにv(p, t)の返り値は2qです。
import pwn import binascii from Crypto.Util.number import * p,q,r = (中略) enc = b'(中略)' print(pwn.xor(binascii.unhexlify(enc),long_to_bytes(q*2)))
corctf{1_b3t_y0u_d1dnt_4ctu411y_d0_th3_m4th_d1d_y0u?}
babyrsa
discord is the best place to store secrets
ファイル:babyrsa.PNG, output.txt, script.py
script.pyやbabyrsa.PNGを見ると、10進数表記のn, p, qの一部の桁は見えています。Coppersmithを使うのにどう落とし込むか…。
pの不明な桁数がいくつか、nを参考すると41桁あることが分かりました。
p = int( str(pの上位84桁)+(不明な41桁)+str(pの下位30桁) ) です。下位41+30桁がすべて0の時と9の時とで、上位bitがどこまで一致するか確かめたところ275bit一致しました。つまり不明な41桁がなんであろうとpの上位275bitは一定となります。
SageMathを使ってCoppersmith's Attackをやってみる - ももいろテクノロジー
いつもの資料を使います。コード内のkbitsは未知のbit数を表し、pが512bitならkbits = 219となります。つまり512-219 = 293bitは既知でないといけません。
ここで、pの上位275bitは分かっていて、残り293-275=18bitをbrute forceします。218 ≒ 260000なので余裕です。
n = (中略) pbar = (中略) PR.<x> = PolynomialRing(Zmod(n)) for i in range(pow(2,18) ): pbar = pbar + (i<<219) f = x + pbar x0 = f.small_roots(X=2^kbits, beta=0.3) if len(x0) > 0: print(x0[0] + pbar) break
ちなみにSageMathCell使うとループが3000回程度で止まってしまいます。
頑張って止まったところからやり直すこと数時間…。flag出てよかった。
corctf{1_w4s_f0rc3d_t0_wr1t3_ch4ll5_4nd_1_h4d_n0_g00d_1d345_pl5_n0_bully_;-;}