SECCON Beginners CTF 2019 write-up
チームm1z0r3として参加(傍観)しました。開催時ちょうど出先だったので、まともに参加できず、warm-up以外はただ眺めて方針を言っただけでした。。。
帰ってからちゃんとcrypro全問とmisc一問解きました。
解けた問題
[warmup] So Tired[Crypto,115pts]
ちょうど電車の中なので、テザリングで問題を解いてた。
最強の暗号を作りました。 暗号よくわからないけどきっと大丈夫!
とやけに長い暗号文が与えられました。最後の方で5+K5v4B8HzgzA==
が見えたので、とりあえずbas64でデコードしてみた。
結果をファイルに書き出しfile
コマンドで見るとzlib
データということが判明。
zlib.decopress()
にかましたら、またbase64っぽいやつになった。
試行錯誤の末、この二つの繰り返しだと踏んでsolverを書いて一発でflagが出ました。
↓はそのsolverです
# coding: utf-8 for i in range(100): print i dd = base64.b64decode(ct) if 'ctf4b' in dd: print dd break dd = zlib.decompress(dd) if 'ctf4b' in dd: print dd break for i in range(1000): print i dd = base64.b64decode(dd) if 'ctf4b' in dd: print dd break dd = zlib.decompress(dd) if 'ctf4b' in dd: print dd break
flagctf4b{very_l0ng_l0ng_BASE64_3nc0ding}
Party[Crypto,223pts]
Let's 暗号パーティ
あと暗号化用スクリプトと暗号文が渡されました。
#暗号化スクリプト from flag import FLAG from Crypto.Util.number import bytes_to_long, getRandomInteger, getPrime def f(x, coeff): y = 0 for i in range(len(coeff)): y += coeff[i] * pow(x, i) return y N = 512 M = 3 secret = bytes_to_long(FLAG) assert(secret < 2**N) coeff = [secret] + [getRandomInteger(N) for i in range(M-1)] party = [getRandomInteger(N) for i in range(M)] val = map(lambda x: f(x, coeff), party) output = list(zip(party, val)) print(output)
[(5100090496682565208825623434336918311864447624450952089752237720911276820495717484390023008022927770468262348522176083674815520433075299744011857887705787, 222638290427721156440609599834544835128160823091076225790070665084076715023297095195684276322931921148857141465170916344422315100980924624012693522150607074944043048564215929798729234427365374901697953272928546220688006218875942373216634654077464666167179276898397564097622636986101121187280281132230947805911792158826522348799847505076755936308255744454313483999276893076685632006604872057110505842966189961880510223366337320981324768295629831215770023881406933), (3084167692493508694370768656017593556897608397019882419874114526720613431299295063010916541874875224502547262257703456540809557381959085686435851695644473, 81417930808196073362113286771400172654343924897160732604367319504584434535742174505598230276807701733034198071146409460616109362911964089058325415946974601249986915787912876210507003930105868259455525880086344632637548921395439909280293255987594999511137797363950241518786018566983048842381134109258365351677883243296407495683472736151029476826049882308535335861496696382332499282956993259186298172080816198388461095039401628146034873832017491510944472269823075), (6308915880693983347537927034524726131444757600419531883747894372607630008404089949147423643207810234587371577335307857430456574490695233644960831655305379, 340685435384242111115333109687836854530859658515630412783515558593040637299676541210584027783029893125205091269452871160681117842281189602329407745329377925190556698633612278160369887385384944667644544397208574141409261779557109115742154052888418348808295172970976981851274238712282570481976858098814974211286989340942877781878912310809143844879640698027153722820609760752132963102408740130995110184113587954553302086618746425020532522148193032252721003579780125)]
単純な多項式方程式の計算でした
のような式が三つがありました
よって連立してsympy使って解いた。
# solver.py import sympy from Crypto.Util.number import long_to_bytes exec(open('encrypted').read().strip()) a,b,c = sympy.symbols('a b c') expr = [] for x,y in z: tmp = a + b*x + c*x**2-y expr.append(tmp) r = sympy.solve(expr,[a,b,c]) print long_to_bytes(r[a])
flag ctf4b{just_d0ing_sh4mir}
Go RSA[Crypto,363pts]
Nだけなくしちゃったんだよなあ……。
Server: nc 133.242.17.175 1337
問題文通りnetcatしてみたら
1. enc(flag)がくれる
2. 送りつける平文を暗号化してくれる* 3
3. 秘密鍵d
まぁ、Nがないわけですね。
最初2,3,5を送ってgcdでnを求めようと思ったが、上手くいけず
試しに-1を送ってみたらまさか通った、
eは奇数のため
Nはこれで入手できたので、あとは複合するだけです。
from gmpy import gcd,mpz from Crypto.Util.number import long_to_bytes from pwn import * while True: ip,port = "133.242.17.175",1337 io = remote(ip,port) c = io.recvline() c = eval(c[19:]) io.recvuntil('> ') io.sendline('-1') c2 = eval(io.recvline().strip()) print c2 io.recvuntil('> ') io.sendline('3') c3 = eval(io.recvline().strip()) io.recvuntil('> ') io.sendline('5') c5 = eval(io.recvline().strip()) d = io.recvline() d = eval(d[10:]) n = c2+1 print n m = pow(c,d,n) print long_to_bytes(m) if 'ctf4b' in long_to_bytes(m): print long_to_bytes(m) break else: continue
flag ctf4b{f1nd_7he_p4ramet3rs}
Bit Flip[Crypro,396pts]
平文を1ビットランダムで反転させる能力を手に入れた!
File: bitflip.py
Server: nc 133.242.17.175 31337
from Crypto.Util.number import bytes_to_long import random N = 82212154608576254900096226483113810717974464677637469172151624370076874445177909757467220517368961706061745548693538272183076941444005809369433342423449908965735182462388415108238954782902658438063972198394192220357503336925109727386083951661191494159560430569334665763264352163167121773914831172831824145331 e = 3 FLAG = bytes_to_long(open('flag', 'rb').read()) r = 1 << random.randrange(0, FLAG.bit_length() // 4) C = pow(FLAG ^ r, e, N) print(C)
早々にcoppersmithのFranklin-Reiter Related Message Attackと気づいて、メンバーに言ったらすぐ解いてくれたが、自分が解く時結構苦戦しました。
ももいろさんのコードをそのままやればできるはずだが、なぜか自分は最初diffの部分をbruteforceしようと思った。
from Crypto.Util.number import long_to_bytes #exec(open('frank').read()) ct = [33460967930651042564008329494837980959989903859210697421802306279164621522687556814718235426111472547179095329371506382390014453846091397832498600503239318321010755518869476348035475014069822783161625493689769776352756995160846240078842031192708266413703448094909589244233878164639106160103912289438284532951, 35767470795467826626462219405218933905532798348984975613284120383492541445125994872372814500011529932489701983142275580480838210299890062839431655315781938554677350092881704540017377748405584214318021791801390834437575079426825881380116885654989459718950805516298665349023074086528990085624070703653325590626, 2564767480510465230025376237485323465247347695767670175449224103561779300575591945349037051568803129039497886094466895116814508667226331922270653397257175611435834481444137923198078723295284476543076934928703086503949903527333767882768961960752424916858651191341982753280463984103242342990373600472836273483, 48435977819599167293699473693205310917010250721248336492061287216379692891690691913767776069993911112239078185069288585022377993407270013401637539048567366526297730605589951913845745872046158333042631889854531385928428660788578942630939788805433004268454651608813773788184844655098499352542867632893087089862, 70243886202594041384149567279846398108812572645105073366462606332641138118730202337380722533868511370427257637609073439393551732783916350915670572090839624554072402040626243669086780305822849504543665527511573152185251528039856817426643797216433781977178180000264280600433349179693943419348506755320080926694, 56073186874991156857455984286684500442906235298857187632607776454964999796759688131079504400025542651062833165579892099321785638532878398946777427851711272910781669617329188445433612821472292131082921802664259975670362919592393670596478369004299401092384846933003092047569839327675819547737050008092855586836, 76973946533903301664341043538088060381425103867343158161579223936021109952721928226649404602045450132057340858205331299178226892039280164374466121273289679601927740750394666755935423240638326819231534726682109186304705616758011069263053347795504543107507654422375687528839427587126700855441423639423394856915, 49654154495482283465834374278541758019608540780454081817664398472317688626329722856959095884025794014552636483510868510209039491680134524145557941720491231286814385904119640028052534147728739758655222825827641976571227089805222280335420420592070351022229307985817960062100669012614681238209307730930907097822, 43127534228950588003064862597617662349110503750643598403895078065209780109199580967321519663285345035915141004019522531717660071908459330437728550039841396677044821855383201329486465004296535288616321397257850646054096663686972817521272024268602548417965146689582261300067924995202141674341056643542839881709, 57689275579576395277674386946337672158924398165151862094706053940830821532864260543417237811918166807469715046584334237149250584727692745234746142171573175423785721026709593407664046881589413366706252864920052167228324308547218195967450249948207887341536607780400807107730207032926117718549982543342765633452, 52359266544766452482523975685608230407291002763343708814586323783536687163032519294172952791019189972735544414177241032748822987128020591624518112210653204778035127348730617786610234768247540041763186245947296196728495533871800544502941653267136708893036674478754400011664069241697039722736589615301087984767, 38844834597621755927122817069901146449872652071559225576929653719687546171913834706512962460338554916524680815254372597395506874917236317267396410010981378138718936802206799767435370326551257259787965495758168188779021198496511984668695738922224971732694952548129382773592529943971677475172616574617049917266, 65629968065768428556355481091340719361116741954090679498200327504380027400680764581274354973606760186939105604187865883111048765492587922739179675879975061207040589702673604068461675060948522167495142009134118186484638258930209624450387799273925135732923965394541431779018125927937023326149589446756683291575, 42931548833801764667442686792357953483640108421931662235100823765650887206728669527853083362065574312034401943127260307486662029021664321290485915120573764222508091524383596332156757300055325893277712136182289687677900418079735270414024337891273172139106857868598826210870661754777950107969285904122398033903] def short_pad_attack(c1, c2, e, n): PRxy.<x,y> = PolynomialRing(Zmod(n)) PRx.<xn> = PolynomialRing(Zmod(n)) PRZZ.<xz,yz> = PolynomialRing(Zmod(n)) g1 = x^e - c1 g2 = (x+y)^e - c2 q1 = g1.change_ring(PRZZ) q2 = g2.change_ring(PRZZ) h = q2.resultant(q1) h = h.univariate_polynomial() h = h.change_ring(PRx).subs(y=xn) h = h.monic() kbits = n.nbits()//(2*e*e) diff = h.small_roots(X=2^kbits, beta=0.5)[0] # find root < 2^kbits with factor >= n^0.5 return diff 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] N = 82212154608576254900096226483113810717974464677637469172151624370076874445177909757467220517368961706061745548693538272183076941444005809369433342423449908965735182462388415108238954782902658438063972198394192220357503336925109727386083951661191494159560430569334665763264352163167121773914831172831824145331 for i in range(len(ct)): for j in range(len(ct)-1): ct1 = ct[i] ct2 = ct[j+1] try: diff = short_pad_attack(ct1,ct2,3,N) except: continue m = related_message_attack(ct1,ct2,diff,3,N) if 'ctf4b' in long_to_bytes(m): print long_to_bytes(m) break
flag ctf4b{b1tfl1pp1ng_1s_r3lated_m3ss4ge}
Sliding Puzzle[Misc,206pts]
帰りの新幹線で解いてみました、
競技はとっくに終わったが、
一応気になった問題なので、取り込みました。
---------------- | 0 | 2 | 3 | | 6 | 7 | 1 | | 8 | 4 | 5 | ----------------
↑のようなpuzzleから0だけ動かして、
数字の昇順に並べ換えらせるまでの手順を遅れれば良い。
なんとなく深さ優先探索(合ってる?)でできそうなので、
競プロの人は普通に解けると思います。
競プロできない自分は他の方の実装を弄って終わった。
from m1z0r3 import * from pwn import * ...略... #Prints the solutions if the prnt = True if prnt == True: print solutions old_tmp = [flatten for inner in eval(solutions[1]) for flatten in inner] old_idx = old_tmp.index(0) for i in solutions[2:]: tmp = [flatten for inner in eval(i) for flatten in inner] idx = tmp.index(0) diff = idx - old_idx if diff == 3: ss.append('2') elif diff == -3: ss.append('0') elif diff == 1: ss.append('1') elif diff == -1 : ss.append('3') t = PuzzleNode(n, eval(i)) t.__str__(i) print "The next step is :" old_idx = idx return ss #return "The frontier size, number of steps and error code are :" , steps, frontierSize, err, ip,port = '133.242.50.201',24912 #s,f = sock(ip,port) io = remote(ip,port) #print recv_line(f) n = 0 while True: print n priv = io.recvline() if '----------------' not in priv: print priv break puzzle = [] for _ in range(3): t = [] tmp = io.recvline().strip().replace(' | ',',').replace('|','',1).replace('|','') for i in tmp.split(','): t.append(int(i)) puzzle.append(t) print io.recvline() print io.recvline() print puzzle #test = [[0,2,3],[6,7,1],[8,4,5]] #print solvePuzzle(3,test,heuristics[1],True) r = solvePuzzle(3, puzzle, heuristics[2], True) print r r = ','.join(r) print r io.sendline(r) n += 1 print io.recvline()
flag ctf4b{fe6f512c15daf77a2f93b6a5771af2f723422c72}
他の問題
気が向いたら
所感
去年より難しいと感じています、楽しかったです。