この大会は2022/3/5 15:30(JST)~2022/3/7 3:30(JST)に開催されました。
今回もチームで参戦。結果は1949点で225チーム中33位でした。
自分で解けた問題をWriteupとして書いておきます。
Welcome (Sanity Check)
Discordに入り、#rulesチャネルを見ると、ルールの文中にwelcome challengeのフラグが書いてあった。
p_ctf{pl34s3_f0ll0w_th3_rul3s}
PHP train (Web)
PHPの==と===の違いなどを使って、条件を満たすようにする。
FLAG1については、param1を配列として指定すれば、CONSTANT1の値に関係なく、条件を満たす。
FLAG2については、param2とparam3で異なる文字列で、sha1を比較しているが、これも配列指定をすればよい。
FLAG3については、param4で1.2e3と同じ数値を指定すればよい。
FLAG4については、param5のパラメータにスペースを含めることによって条件を満たすようにする。
FLAG5については、param6にmd4が0eから始まる文字列を指定する。その際https://github.com/spaze/hashes/blob/master/md4.mdを参考にする。
FLAG6については、helloworldを置換後に、helloworldになるよう、param7に間に挟み込みよう文字列を指定する。
FLAG7については、param8に1~25の数値を含むように、.envも含めて文字列を指定する。
以下のようにパラメータを指定してアクセスしたら、フラグが表示された。
https://phptrain.challs.pragyanctf.tech/?param1[]=a¶m2[]=b¶m3[]=c¶m4=1200¶m5=%2089¶m6=gH0nAdHk¶m7=hellohelloworldworld¶m8=1.env
p_ctf{ech0_1f_7h3_7r41n_d035_n07_5t0p_1n_y0ur_5t4t10n_7h3n_1t5_n07_y0ur_7r41n}
Hidden and Protected (Forensics)
pngの末尾にzipがくっついている。zipを抽出して、解凍すると、2つのファイルが展開される。
・Double_Encrypted_Password.txt ・image2.jpeg
txtにはこう書いてある。
ABBBAABABBBAABABAABABABABAAAAAABBBAABABBBBAAAABABB
ベーコン暗号と推測し、https://www.dcode.fr/bacon-cipherで復号する。
OLSSVAOLYL
さらにシーザー暗号と推測し、https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipherで復号する。
Rotation 7: HELLOTHERE
これをパスフレーズとしてsteghideを実行する。
$ steghide extract -sf image2.jpeg -p HELLOTHERE wrote extracted data to "flag.txt". $ cat flag.txt p_ctf{G3N3R4L_K3N0B1_TH3_N3G0T14T0R}
p_ctf{G3N3R4L_K3N0B1_TH3_N3G0T14T0R}
Ye Olde Threat (Forensics)
base64文字列をデコードする。
$ echo aHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2ZpbGUvZC8xQUVremJqV1JDZFVwNEY3ZjJ3dExnSWQyd2RTRlkwUXE= | base64 -d https://drive.google.com/file/d/1AEkzbjWRCdUp4F7f2wtLgId2wdSFY0Qq
このURLにアクセスし、ファイルをダウンロードする。pngのようだが、ところどころ壊れているので、修正していく。
・オフセット0x00000000-0x00000005(シグネチャ部分) 89 49 6c 47 63 6d -> 89 50 4e 47 0d 0a ・オフセット0x0000000c-0x0000000f(IHDRチャンク名) 31 48 44 72 -> 49 48 44 52 ・オフセット0x00000025-0x00000028(IDATチャンク名) 31 64 61 37 -> 49 44 41 54 ・オフセット0x0000202d-0x00002030(IDATチャンクサイズ) 08 01 09 02 -> 00 00 20 00 ・オフセット0x00006041-0x00006044(IDATチャンクCRC) f6 48 39 a4 -> a8 9b 38 1a
修正したPNGファイルにはフラグが見つからない。このPNGファイルをStegSolveで開き、Blue plane 2を見ると、フラグが書いてあった。
p_ctf{K@nye_w@nt5_To_Buy_Th3_3n71r3_E4rth}
Perfect Puzzle (Crypto)
暗号処理は以下の通り。
・p, q: 1024ビット素数 ・n = p * q ・e = 65537 ・flag_int: flagの数値化 ・CipherText = pow(flag_int, e, n) ・Xemu: 1024ビット素数 ・Alice = p + Xemu ** 2 ・Bob = q * Xemu ・sum = Xemu * (Xemu + 1) >> 1 ・Result = invdivsum(sum) ・ret = 0 ・sumの回数繰り返し ・sum が i + 1で割り切れる場合、retが1/(i+1)増加 ・CipherText, Alice, Bob, Result表示
Resultが2.0になっているので、sumは完全数。見つかっている完全数は限られている。https://en.wikipedia.org/wiki/List_of_Mersenne_primes_and_perfect_numbersを参考にする。
コードから2048ビット未満と推測されるので、それ以下の完全数の総当たりで、条件を満たすものを探す。p, qを割り出せたら、あとはそのまま復号する。
#!/usr/bin/env python3 from Crypto.Util.number import * from sympy import * CipherText = 149596971555589076155364186420580570749374401138608961998290009825114263148416772478651277321234724062278466223025831775035224109103887370927097231230324908201908263749968832767737017862796581877535194538767636598004538397685647433625803605580636107271455294998120570215920206140799513104969815764397323782297061528436771406170006449117531288516762624306954764709977440515034071280736026924741057203047657693649914954727759355179977253548864147305088480009948437 Alice = 282107567413424138126415916172126379762973487029431335677677351999909735485304760228208386658075380503123901137419658654328175448732740174233462536318627304974901304879611754592414594362308597516549359004265409028150117237817823179344527892839743549388806946124113890322466683297081312475367783738162570544520549179569150033008482592884468354854459703961697842606812 Bob = 66444211849564598649204285138638077348678558382508976397654912859551087895603398701542655997585482323573895063934558694018052442406995794312376093987279068684491709029458439225825559371474422839752950009253788191772668126664288610488535211383255806288769703027437108720296265682565379886651381942112538908474625781728851722312089113677698489150478927871052981645551018211694817730263647445568601019977068831413100897642519594589716447525199022801203505747758062305119871983246399979915166157 ps = [2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203, 2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497, 86243] found = False for p in ps: pn = pow(2, p - 1) * (pow(2, p) - 1) sum = pn * 2 x = symbols('x') eq = Eq(x * (x + 1) - sum, 0) sol = solve(eq, x) for Xemu in sol: if Xemu > 0 and Bob % Xemu == 0: found = True break if found: break q = int(Bob // Xemu) p = int(Alice - Xemu ** 2) n = p * q e = 65537 phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(CipherText, d, n) flag = long_to_bytes(m).decode() print(flag)
p_ctf{M3rs5nne_pr1mes_4re_c00l}
Blind Scout (Crypto)
5つの鍵のModulusのうち、共通する素数が使われているものを探し、素因数分解する。2つの鍵で復号し、フラグの形式になるものを探す。
from Crypto.PublicKey import RSA from Crypto.Util.number import * import itertools import base64 ns = [] for i in range(1, 6): fname = 'pub%d.pem' % i with open(fname, 'r') as f: pem = f.read() pubkey = RSA.importKey(pem) n = pubkey.n e = pubkey.e assert e == 65537 ns.append(n) for c in list(itertools.combinations(ns, 2)): p = GCD(c[0], c[1]) if p > 1: n1 = c[0] n2 = c[1] q1 = c[0] // p q2 = c[1] // p break with open('cipher.txt', 'r') as f: c = bytes_to_long(base64.b64decode(f.read())) phi1 = (p - 1) * (q1 - 1) phi2 = (p - 1) * (q2 - 1) d1 = inverse(e, phi1) d2 = inverse(e, phi2) m1 = pow(c, d1, n1) m2 = pow(c, d2, n2) for m in [m1, m2]: flag = long_to_bytes(m) if flag.startswith(b'p_ctf{'): print(flag.decode())
復号結果は以下の通り。
p_ctf{010100_100000101100_100110100000111010100010100110100010111001010100111000}
このままではフラグは通らない。問題タイトルから点字と推測する。
01 10 11 11 10 10 10 11 10 10 01 10 10 00 00 01 00 11 01 01 01 10 10 10 00 _ 00 10 _ 00 00 10 00 00 00 11 00 10 i _ a m _ d a r e d e v i l
p_ctf{i_am_daredevil} は通らなかった。大文字にしてみる。
p_ctf{I_AM_DAREDEVIL}