この大会は2024/5/24 21:00(JST)~2024/5/26 21:00(JST)に開催されました。
今回もチームで参戦。結果は1189点で497チーム中99位でした。
自分で解けた問題をWriteupとして書いておきます。
Sanity Check (MISC)
Discordに入り、#rulesチャネルのトピックを見ると、フラグが書いてあった。
L3AK{W3lc0ME_To_L34k_CTF!}
Geosint-1 (OSINT)
Google Mapのように特定の位置の周囲を見ることができるので、指定されたGeoGuessrのシステムでポイントし、Submitする。正しければ、フラグが表示されるという仕組み。
後方に特徴的な橋が見える。

この画像を取り、画像検索すると、ヴェラザノ=ナローズ・ブリッジであることがわかる。Google Mapでこの橋が渡っている川に沿って行くと、周囲の映像と同じような位置がわかった。
https://www.google.co.jp/maps/@40.6342874,-74.0387092,3a,75y,318.21h,96.75t/data=!3m7!1e1!3m5!1sbYHmJefa0cMQM0jmW5RPlA!2e0!6shttps:%2F%2Fstreetviewpixels-pa.googleapis.com%2Fv1%2Fthumbnail%3Fpanoid%3DbYHmJefa0cMQM0jmW5RPlA%26cb_client%3Dmaps_sv.share%26w%3D900%26h%3D600%26yaw%3D318.2084523544373%26pitch%3D-6.7471125241843595%26thumbfov%3D90!7i16384!8i8192?hl=ja&coh=205410&entry=ttu
Bobby Bello Fieldの3つのグリーンの内一番北にあるものの前あたりが該当する。

L3AK{Verr4zz4n0_Br1dge_1s_pR3tty_c00l}
Layout (HARDWARE-RF)
GDS Viewerで開くと、フラグを確認することができた。

L3AK{w3LcoM3_To_HArDw4R3!}
Hidden (REV)
Ghidraでデコンパイルする。
undefined8 FUN_001013e5(undefined8 param_1,long param_2) { int iVar1; char *__s2; __s2 = (char *)FUN_0010137d(); if ((*(long *)(param_2 + 8) != 0) && (iVar1 = strcmp(*(char **)(param_2 + 8),__s2), iVar1 == 0)) { puts("Correct!"); return 0; } puts("Wrong!"); return 0; } void * FUN_0010137d(void) { void *pvVar1; pvVar1 = malloc(0x200); FUN_00101214(pvVar1,0x4c,0x33,0x41,0x4b,0x7b,0x62,0x34,0x62,0x79,0x5f,0x73,0x54,0x33,0x50,0x73, 0x7d,0); return pvVar1; }
FUN_0010137d関数で引数に渡しているコードをASCIIコードとして結合すると、フラグになりそう。
>>> bytes([0x4c,0x33,0x41,0x4b,0x7b,0x62,0x34,0x62,0x79,0x5f,0x73,0x54,0x33,0x50,0x73,0x7d])
b'L3AK{b4by_sT3Ps}'
L3AK{b4by_sT3Ps}
Really Simple Algorithm (CRYPTO)
サーバの処理概要は以下の通り。
・e = 1337 ・size = 1024 ・以下繰り返し ・p, q: 1024ビット素数 ・n = p * q ・option: 数値入力 ・optionが1の場合 ・message: 入力→数値化 ・enc_msg = pow(message, e, n) ・n, enc_msgを表示 ・optionが2の場合 ・enc_flag = pow(フラグの数値化, e, n) ・n, enc_flagを表示 ・optionが3の場合、終了
Hastad's Broadcast Attackで復号する。
#!/usr/bin/env python3 import socket from Crypto.Util.number import * from sympy.ntheory.modular import crt from gmpy2 import iroot def recvuntil(s, tail): data = b'' while True: if tail in data: return data.decode() data += s.recv(1) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('193.148.168.30', 5668)) for _ in range(4): data = recvuntil(s, b'\n').rstrip() print(data) e = 1337 ns = [] cs = [] for _ in range(e): data = recvuntil(s, b': ') print(data + '2') s.sendall(b'2\n') data = recvuntil(s, b'\n').rstrip() print(data) ns.append(int(data.split(' ')[-1])) data = recvuntil(s, b'\n').rstrip() print(data) cs.append(int(data.split(' ')[-1])) me, _ = crt(ns, cs) m, success = iroot(me, e) assert success flag = long_to_bytes(m).decode() print(flag)
実行結果は以下の通り。
Welcome to the L3ak Really Simple Algorithm (RSA) Encryption Service™!
Here you can encrypt your own message, or choose to receive the encrypted flag.
Good luck!
(1) Encrypt Message
(2) Receive Flag
(3) Exit
Select Option: 2
n = 17174931731156529458002853476994633232360264628689265534723755925243038170232171246118177178249712289804216770145531104090968864923615156475160729564808128170537434703047827764024174531751137320122330629322954497916782089604528822712011950348413544687326766594034027065014122047689089265279290881965084305965509120952780299518704139811795646734104828640841632984098475964491826094865282342891585391556795859726144505657626072648920933815665109844268911666543325990982542327311125913200428638634189502325040956328683809919506334613479182357932207463000567179139242027508841470214302682736622596710545949741700663949103
flag = 11177563111593026837289848116822445170889918216794060058556700252742256468152248455463609727625872611435212349814431875624542569241511097922806051127725167078689847071422441250294253133938045756651455480986578621033484506835994992330097485229317603408936060527619464594196035069900144478805344041858627415660942515209118243920047671369026661170447463000119803969606099280328684520495354222208417441847052255313771854966622246620695420834470395898627505283043136628361601300474790102555909265768841110265456535689573118137319200258450267043814628376190817080861607960182762591450998085243159691124479141773448283815959
(1) Encrypt Message
(2) Receive Flag
(3) Exit
Select Option: 2
n = 16785254444187310479246706237562827469967680899254854206099526794498371043384479379723162575017112722995640076061545136009385657544791520678748600346653791964566686852941536505634338032543219895155748875226656628066397511490941174606333662679458943107272407122782806393212359613986186827499180388468836053103728408297227153482293812419175456791019348142188831941989037358418741803493261864857035178440639883286491714466362151811517374488027531026376403696091975399749429503307799294343132976575740839010968161840615427329210444411933601315010545929562311668802661383890253528457381944578267299583616215025102722142683
flag = 3858395372306622130332404257143424400085915953628333840003764145690002350101610856018582850497248647555389302191981739941146899249276955510912571796667278167458332570407627921340554344385814541058819380987634522982374342582615265025242190474226937369558628849968936734125501660589626968419674643152696859615574678674516557623691258748537541211031352041531164973822305866470290062803689813514924294802305248989013413105385698759374399445784729697382636416985115933618936115423750447793360080689170922620176824388612992918614121775891039084885911529154129480511721924849027003413018469963371957972250501096307442475303
:
:
(1) Encrypt Message
(2) Receive Flag
(3) Exit
Select Option: 2
n = 15784330843315732305818840236838315475471499802480233831700652385565351264481198880252255992585167314015109835277865422849530867509752051369722126956642601595057094660675663450955669956945806062930683029322844072135436365471070569260308746156916858644636391982095983543197427743295576949035658598380850177650840501778731960674463820644931363224309578728868553823049144138736351600152622633737316439618022596812657966925566359169374358948838253455028534194740454281678227757875334349279734195134625105664622520121893954779858195743024889091956734573792582661989342486386793906752433573624871782800361047251938036803819
flag = 8805940144413235988602731977332684857126763796125664556819845152455257407351700944804678592146349320189173678418674604009835843622450489542961571633827104230652137426385193280911834504354958733432039356637137941851719413647866813240412946863255650518183085069132326800891167473010224874425799150555024313298492543729139006561799291624460392302484570739309113920014236689387314025004797759385992861926649378255408338403017289241480050980049900963436182104782427198254450923620584737594391152140046055985327395160540836249229400870580388104020797071554011487930425083375122276198270502161739406061844336518249443179997
(1) Encrypt Message
(2) Receive Flag
(3) Exit
Select Option: 2
n = 22119644369512239563954541425398519351333394170915004314891644119900335190380073460368616041039439648607431460336742463934504201225266969814860789994230832420993570885284282828412659320903651401486173205426766581616501650271002366684930277585202761910496717750978323778114933633289750457212725430263444682132082589024671212046677921411838174728819823622110104786919737970358924066450090960159342605181754880306871133548677879047851771766798159207277439620742596258236980681768867676460531371361283469318594321242152176744132964047137339536502943570554843483205086815865703766915556259303151954300105385928990267249107
flag = 1716770341357323972841741286212606919654869453219292498489982600276844456130800630733637266840131006623721925322789509177115192688110807300730462720552820925130467778182770977679815891001621148984327197559729142740566547208534532197661939026204048856532765718661976785435427319537859456208370223473693300304311596495280701792078836047015295238565213502666989983279508139282219319921535348164764110200061964056116456927872876644531496331505724873347792720151122283074944011276016186325781432403424035694620292321536218531809124209833415214881978714289992771405792855999392417109942572098672348267920116058723158864736
L3AK{H4sTAD5_bR0aDc45T_4TtacK_1s_pr3tTy_c0ol!}
L3AK{H4sTAD5_bR0aDc45T_4TtacK_1s_pr3tTy_c0ol!}
Related (CRYPTO)
暗号の処理概要は以下の通り。
・p, q: 1024ビット素数 ・n = p * q ・e = 0x101 ・variables, ct1 = encrypt(FLAG) ・padded_variables, padded_message = pad(FLAG) ・m: FLAGの数値化 ・a, b: ランダム2以上n以下の整数 ・(a, b), a * m + bを返却 ・a1 = variables[0] ・b1 = variables[1] ・variables, ct2 = encrypt(FLAG) ・a2 = variables[0] ・b2 = variables[1] ・n, a1, b1, ct1, a2, b2, ct2を表示
以下のように式を変形することができる。
m1 = a1 * m + b1 m2 = a2 * m + b2 ↓ m1 * inverse(a1, n) * a2 % n = (a2 * m + b1 * inverse(a1, n) * a2) % n m2 % n = (a2 * m + b2) % n
new_m1 = m1 * inverse(a1, n) * a2 % n とすると以下のようになる。
new_m1 = (a2 * m + b1 * inverse(a1, n) * a2) % n
m2 = (a2 * m + b2) % n
new_ct1 = pow(new_m1, e, n) = pow(m1, e, n) * pow(inverse(a1, n) * a2, e, n)
= ct1 * pow(inverse(a1, n) * a2, e, n)平文のnew_m1とm2は差がわかり、new_ct1とct2がわかるので、Franklin-Reiter Related Message Attackで復号できる。
#!/usr/bin/env sage from Crypto.Util.number import * def related_message_attack(c1, c2, diff, e, n): PRx.<x> = PolynomialRing(Zmod(n)) g1 = x^e - c1 g2 = (x+diff)^e - c2 def gcd(g1, g2): while g2: g1, g2 = g2, g1 % g2 return g1.monic() return -gcd(g1, g2)[0] e = 0x101 with open('out.txt', 'r') as f: params = f.read().splitlines() n = int(params[0].split(' ')[-1]) a1 = int(params[1].split(' ')[-1]) b1 = int(params[2].split(' ')[-1]) ct1 = int(params[3].split(' ')[-1]) a2 = int(params[4].split(' ')[-1]) b2 = int(params[5].split(' ')[-1]) ct2 = int(params[6].split(' ')[-1]) diff = (b2 - b1 * inverse(a1, n) * a2) % n new_ct1 = ct1 * pow(inverse(a1, n) * a2, e, n) % n m2 = int((related_message_attack(new_ct1, ct2, diff, e, n) + diff) % n) m = (m2 - b2) * inverse(a2, n) % n FLAG = long_to_bytes(m).decode() print(FLAG)
L3AK{r3l4teD_m3s54GeS_Ar3_1nS3cuR3_1n_RsA}
Survay (MISC)
アンケートに答えたら、フラグが表示された。
L3AK{thanks_for_the_honest_feedback_hope_to_see_you_next_year}