この大会は2020/8/15 0:00(JST)~2020/8/16 0:00(JST)に開催されました。
今回もチームで参戦。結果は194点で552チーム中75位でした。
自分で解けた問題をWriteupとして書いておきます。
Amsterdam
添付のコードの処理概要は以下の通り。
■comb(n, k) ・k = min(k, n - k) ・u = n * (n-1) * ... * (n-k+1) ・d = 1 * 2 * ... * k ・u//d(=組合せの数)を返す。 ■encrypt(msg, n, k) ・m = ['1'] + ['0' for i in range(n - 1)] ・i = 1~nについて、comb(n - i, k)とmsgの比較の結果により計算 ・3進数として見てそれにより計算
以上の処理から逆算する。
from Crypto.Util.number import * from functools import reduce import operator def comb(n, k): if k > n : return 0 k = min(k, n - k) u = reduce(operator.mul, range(n, n - k, -1), 1) d = reduce(operator.mul, range(1, k + 1), 1) return u // d def get_m(n): z = [] r = n while True: z.insert(0, r % 3) r = r // 3 if r == 0: break m = 0 for v in z: if v == 1: m += 1 elif v == 2: m -= 1 m *= 2 return m // 2 with open('output.txt', 'r') as f: enc = int(f.read().rstrip().split(' = ')[1]) m = get_m(enc) m = list(bin(m)[2:]) n = len(m) msg = 0 k = 0 for i in range(n, 1, -1): if m[i-1] == '1': k += 1 msg += comb(n - i, k) flag = long_to_bytes(msg) print flag
実行結果は以下の通り。
..:: CCTF{With_Re3p3ct_for_Sch4lkwijk_dec3nt_Encoding!} ::..
CCTF{With_Re3p3ct_for_Sch4lkwijk_dec3nt_Encoding!}
Gambler
$ nc 05.cr.yp.toc.tf 33371 Please submit a printable string X, such that md5(X)[-6:] = 436d29 and len(X) = 15 aaaaaaaaaaa3b c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + Hi, there is a strong relation between philosophy and the gambling! + + Gamble as an ancient philosopher and find the flag :) + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | Options: | [C]ipher flag! | [E]ncryption function! | [T]ry the encryption | [Q]uit E def encrypt(m, p, a, b): assert m < p and isPrime(p) return (m ** 3 + a * m + b) % p | Options: | [C]ipher flag! | [E]ncryption function! | [T]ry the encryption | [Q]uit C | encrypt(bytes_to_long(flag)) = 4339765736830935414327965338053684580043454821290341525216211716629855521006492403426648253523243969172076764249860030760412141126792833762698294650295993 | Options: | [C]ipher flag! | [E]ncryption function! | [T]ry the encryption | [Q]uit T | please enter your message to encrypt: 0 | encrypt(0) = 1089301495525915394959217783050238720360823156044460562942045915433765226363143224942220585780797051983913183133330187520635392023778046748500434599782334
この暗号化の処理から以下のようになることがわかる。
m=0 c = b % p = b m=1 c = (a + b + 1) % p m=2 c = (a*2 + b + 8) % p
差分を計算し、aを数回求め、正負の値が出るようにする。両方ともmod pでは同じ値を示すので、以下の式が成り立つ。
p = 正の値 - 負の値
あとはsageでmodulo p上の三次方程式を解けば、フラグが求められる。
#!/usr/bin/env sage import socket import itertools import re import string import hashlib from Crypto.Util.number import * def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('05.cr.yp.toc.tf', 33371)) data = recvuntil(s, '\n').rstrip() print data pattern = 'that (.+)\(X\)\[-6:\] = (.+) and len\(X\) = (.+)' m = re.search(pattern, data) alg = m.group(1) h = m.group(2) l = int(m.group(3)) for c in itertools.product(string.letters + string.digits + '!#$%&()+-*=.,:+[]{}', repeat=4): X = 'a' * (l - 4) + ''.join(c) if alg == 'md5': try_h = hashlib.md5(X).hexdigest() elif alg == 'sha1': try_h = hashlib.sha1(X).hexdigest() elif alg == 'sha224': try_h = hashlib.sha224(X).hexdigest() elif alg == 'sha256': try_h = hashlib.sha256(X).hexdigest() elif alg == 'sha384': try_h = hashlib.sha384(X).hexdigest() elif alg == 'sha512': try_h = hashlib.sha512(X).hexdigest() if try_h[-6:] == h: print X s.sendall(X + '\n') break data = recvuntil(s, '[Q]uit\n').rstrip() print data print 'E' s.sendall('E\n') data = recvuntil(s, '[Q]uit\n').rstrip() print data print 'C' s.sendall('C\n') data = recvuntil(s, '[Q]uit\n').rstrip() print data flag_enc = int(data.split('\n')[0].split(' ')[-1]) encs = [] for i in range(8): print 'T' s.sendall('T\n') data = recvuntil(s, ':\n').rstrip() print data print str(i) s.sendall(str(i) + '\n') data = recvuntil(s, '[Q]uit\n').rstrip() print data enc = int(data.split('\n')[0].split(' ')[-1]) encs.append(enc) b = encs[0] a01 = [] for i in range(7): a = encs[i+1] - encs[i] - ((i+1)**3 - i**3) if a not in a01: a01.append(a) if a01[0] > 0: a = a01[0] p = a01[0] - a01[1] else: a = a01[1] p = a01[1] - a01[0] print '[+] a =', a print '[+] b =', b print '[+] p =', p PR.<x> = PolynomialRing(Zmod(p)) f = x**3 + a * x + b - flag_enc x = f.roots() for x0 in x: m = x0[0] flag = long_to_bytes(m) if flag.startswith('CCTF{'): print flag break
実行結果は以下の通り。
Please submit a printable string X, such that sha256(X)[-6:] = dcec57 and len(X) = 34 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaau4:H ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + Hi, there is a strong relation between philosophy and the gambling! + + Gamble as an ancient philosopher and find the flag :) + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | Options: | [C]ipher flag! | [E]ncryption function! | [T]ry the encryption | [Q]uit E def encrypt(m, p, a, b): assert m < p and isPrime(p) return (m ** 3 + a * m + b) % p | Options: | [C]ipher flag! | [E]ncryption function! | [T]ry the encryption | [Q]uit C | encrypt(bytes_to_long(flag)) = 5859516123032408533939710338576303083349657177204288009870620113808657974777306952491312119968507733782625057335054668782484329039657233624056698649884479 | Options: | [C]ipher flag! | [E]ncryption function! | [T]ry the encryption | [Q]uit T | please enter your message to encrypt: 0 | encrypt(0) = 3637655651634145666149005129567650238506907370016588111100276114666277871801383820019190490265615402427492341457234915175477949683389630837892818806483316 | Options: | [C]ipher flag! | [E]ncryption function! | [T]ry the encryption | [Q]uit T | please enter your message to encrypt: 1 | encrypt(1) = 6684357881294328590827758239283935840508256629140296502574070083663474657706694077011405369969103934322873783266172317422303466082228788559258018890537923 | Options: | [C]ipher flag! | [E]ncryption function! | [T]ry the encryption | [Q]uit T | please enter your message to encrypt: 2 | encrypt(2) = 9731060110954511515506511349000221442509605888264004894047864052660671443612004334003620249672592466218255225075109719669128982481067946280623218974592536 | Options: | [C]ipher flag! | [E]ncryption function! | [T]ry the encryption | [Q]uit T | please enter your message to encrypt: 3 | encrypt(3) = 3044830652562186554641560518436170068234378799214462545904358445175680930299518352118531703785023105414819829718421119070044005355378749771648575733506042 | Options: | [C]ipher flag! | [E]ncryption function! | [T]ry the encryption | [Q]uit T | please enter your message to encrypt: 4 | encrypt(4) = 6091532882222369479320313628152455670235728058338170937378152414172877716204828609110746583488511637310201271527358521316869521754217907493013775817560685 | Options: | [C]ipher flag! | [E]ncryption function! | [T]ry the encryption | [Q]uit T | please enter your message to encrypt: 5 | encrypt(5) = 9138235111882552403999066737868741272237077317461879328851946383170074502110138866102961463192000169205582713336295923563695038153057065214378975901615352 | Options: | [C]ipher flag! | [E]ncryption function! | [T]ry the encryption | [Q]uit T | please enter your message to encrypt: 6 | encrypt(6) = 2452005653490227443134115907304689897961850228412336980708440775685083988797652884217872917304430808402147317979607322964610061027367868705404332660528930 | Options: | [C]ipher flag! | [E]ncryption function! | [T]ry the encryption | [Q]uit T | please enter your message to encrypt: 7 | encrypt(7) = 5498707883150410367812869017020975499963199487536045372182234744682280774702963141210087797007919340297528759788544725211435577426207026426769532744583663 | Options: | [C]ipher flag! | [E]ncryption function! | [T]ry the encryption | [Q]uit [+] a = 3046702229660182924678753109716285602001349259123708391473793968997196785905310256992214879703488531895381441808937402246825516398839157721365200084054606 [+] b = 3637655651634145666149005129567650238506907370016588111100276114666277871801383820019190490265615402427492341457234915175477949683389630837892818806483316 [+] p = 9732931688052507885543703940280336976276576348173250739617299576482187299217796238877303425591057892698816837165626002845910493524528354230339843325141119 CCTF{__Gerolamo__Cardano_4N_itaLi4N_p0lYma7H}
CCTF{__Gerolamo__Cardano_4N_itaLi4N_p0lYma7H}
Trailing Bits
2進数コードになっているが、そのままでは文字にならない。シフトしながらデコードしてみる。
with open('output.txt', 'r') as f: enc = f.read().rstrip() for j in range(8): try_enc = enc[j:] msg = '' for i in range(0, len(try_enc), 8): msg += chr(int(try_enc[i:i+8], 2)) print '[+] shift =', j print msg
実行結果は以下の通り。
[+] shift = 0 H禄レXネ[ル・[剱ワ婢][ロ・[・ロロ\][卻[・Yレ]ロロ[][唸リ][ロ慷・H麓YH\ネHワ ・X[・X]Hル・喙禄曰Yレ]摸WHH 兔兔ル[・ネHルレXリン]Hレ]ロ僣ル・ロネワワレX・H麓Y\ヒ・\ルH麓Y\ネ\僣[ワロロ[[ロ・H兔兔ル[ \ネZ]\・ワ ン\・兔兔ル[・][ロ慂ン\ネ拑Kル麓ルY\ヒロ嵳 Wフロ・NZレ筆UンラワメY・モL゚B・Hロワ恙\ワロ・[俛H兢ルY[・\ルH麓Y\ネ[・H\レXン]\ネル・H[・\・Z[卻ンワ郎ルHワ・]唸ルH\ネHX]\・ル・ロロ撕[・[ロ・[・Y劔\兌・\ワレYロ婪[・ネX^H僣\]兌・レ][・Hリ[YH]唸ルHワ・巍ワ麓K X^H僣\レXリ[H[\[Y[・レHロヒ\ン [+] shift = 1 ・0ケエア・キ4コ7ウ4キ37ケ6ーコ4キキ4キ1キカク:コ4キ3・キ224ウエコ0カ1キカカコキ4アーコ4キキ9・*42・0カイ・ケ ・・7ケ:6ーキ:2ーコ・ウ14キ0ケ<・4ウエコ-舒・42・4コ92ク92ケイキ:9・・7ウエアーカ9コ0コ2・エコ47キ2・ウ:;キ・7ケケエア62・0カ:イケ・*42ケイ・0カ:イケ・ケ2・キケコ1キカカキキ6<・2ク92ケイキ:2イ0ケ・エコ42ケ7ケ・1:コ7コ42ケ92ク92ケイキ:0コ4キキ9・コアエ0ケ・9:イ竜0カ9イ・<イケ旅7・列DI7ケ7キキウ30ケ2・キカカキキ*42・60ウ・ケ・。ェ#=エコッ匚:惷/オ*坎/コ'ッケ、ウ:/ヲ卆・42・キケ92ケク7キ22キ1イ・2コ;イイキ:42ケイ・0カ:イケ・キ2:42・4<ケエアーカ9コ0コ2ケ・ウ:42・キ22ケ6<エキ3・コ7ケ0ウイ・ケ22サ4アイ・ケ・・ーコ:2ケ7ウ1キキ;2キ:4キキ0キ224ウ32ケ2キ:0ケケエウキ6イキ:9・ーシ・2・ケイイ2サ2キ;エコ44キ:42・ーカイ・2サ4アイ・ケ897ウケ0カ・$コ6ーシ・2・4<ケエアーカ6<・カク62カイキ:2イ;エコ40・;キ婿コ [+] shift = 2 basic unit of information in computing and digital communications. The name is a portmanteau of binary digit.[1] The bit represents a logical state with one of two possible values. These values are most commonly represented as either 0or1, but other representations such as true/false, yes/no, +/竏・ or on/off are common. The flag is CCTF{it5_3n0u9h_jU5T_tO_sH1ft_M3} The correspondence between these values and the physical states of the underlying storage or device is a matter of convention, and different assignments may be used even within the same device or program. It may be physically implemented with a two-st [+] shift = 3 @トツ贅ニ@・メ錙゙フ@メワブ蒂ツ靨゙ワ@メワ@ニ゙レ瑕靨ワホ@ツワネ@ネメホメ霙リ@ニ゙レレ・メニツ靨゙ワ觸@ィミハ@ワツレハ@メ襦ツ@玻蒻レツワ靆ツ鵝゙フ@トメワツ蔗@ネメホメ鐔カbコ@ィミハ@トメ錙萍琅ハ賁ワ韆@ツ@リ゙ホメニツリ@跖ツ靆@迤靤@゙ワハ@゙フ@韶゙@玻跏メトリハ@・リ・觸@ィミハ賁@・リ・襦ツ萍@レ゙跖@ニ゙レレ゙ワリ萍琅ハ賁ワ靆ネ@ツ襦ハメ靤ハ隋`゙臙X@ト・@゙靤ハ隋萍琅ハ賁ワ霙靨゙ワ襦跛ニミ@ツ襦鞴・^フツリ賁X@訖ヷX@V_ナ$X@゙隋゙ワ^゙フフ@ツ萍@ニ゙レレ゙ワ\ィミハ@フリツホ@メ襦・ィ公メ鑠セfワ`靡ミセヤェjィセ陞セ謳bフ霎喃・ィミハ@ニ゙蒿ハ赳゙ワネハワニハ@トハ韶ハハワ@靤ハ賁@・リ・襦ツワネ@靤ハ@獎メニツリ@跖ツ靆襦゙フ@靤ハ@・ネハ蒭ワホ@跖゙萃ホハ@゙隋ネハ・ニハ@メ襦ツ@レツ韋ハ隋゙フ@ニ゙ワ・ワ靨゙ワX@ツワネ@ネメフフハ萍ワ錙ツ跏メホワレハワ韆@レツトハ@・ハネ@ハ・ワ@迤靤メワ@靤ハ@貭レハ@ネハ・ニハ@゙隋琅゙ホ萃レ\@定@レツトハ@獎メニツリリメレ獵ハレハワ靆ネ@迤靤@ツ@韶゙Z跖 [+] shift = 4 ♂・・戟ユケ・ミ⊃・・ケ區ノオ・・スク▼ク″スオチユム・ケ怐・吹則擂ム・″スオオユケ・劫ム・スケフク_。煤ケ・煤・フ >・スノムオ・ム腐ヤ⊃・翁ケ・艨則擂ミケlナt_。煤翁ミ∨蔽ノ箆併ムフ>・ス擂劫ー∀ム・煤ン・ム⊃ケ煤ス・ムンシ・スヘヘ・桶煤ル・ユ蔑ク_。箆煤ル・ユ蔑≦ノ煤オスヘミ″スオオスケア艨ノ蔽ノ箆併ム武≦フ&・ム。癖€チスネトー♂ユミ⊃ム。癖∨蔽ノ箆併ム・・スケフ∀ユ頃≦フ・ノユ反刔アヘ伐∝蔑スケシー€ャソ・Hー⊃ネ⊃クスス劍≦ノ煤鎖Q綋ミユ|ヘクチヤ蝪}ゥTユQ}ム=}ヘ ナ厶}4ヘ・Q。煤鎖ノノ箆チスケ装ケ鵠♂篇ン封ク・。箆煤ル・ユ蔑≦ケ吹ム。煤チ。袁・劫ー∀ム・蔑⊃・ム。煤ユケ装ノア螂ケ怐ヘムスノ・煤スネ¢弁・鵠▼フ>・・ム癖⊃・鎖ケル併ム・スクー≦ケ吹則劔碧併ミ≦ヘヘ・攣オ併ムフ・・♂煤ユヘ武&ル丙∂・ム。・ク・。煤ヘ・煤装ル・鵠⊃ネ・ノス數・ク・ミ ・・♂煤チ。袁・劫アア艨・オチア雰併ム武∂・ム>・ンシオヘム [+] shift = 5 姙ォsK。{1Ks3{徒」K{qKq{kΝ」Ks9s!#K;K」a{kkォsK」K{s冫」C)sk)K・ ボ謄ks」+ゥ{1Ks橡#K;K。rル企」C)K。・ン+・s」・ c{;Ka屮」)サK」A{s){1」サyボ屁Kc)ウcォ+冫」C+・ウcォ+・・k{孱{kk{scノ・ン+・s」+!・+K」C+・ボ痩aォ。{」C+・・ン+・s」」K{s・岫A・」騰){3c・aヒ+几syaYD疎{・{q{{31・{kk{qpR」C)3c9K・「3ロK。ェqΛヒB炫ゥェ「裵z蕓A・「仡幄R」C){涛+寃{s#+s)+」サ++q」C+・ウcォ+・s!」C)イヒ姙a屮」+・{1」C)ォs#+田ヒKs9屮{・;){・#+ウK)K・ k」」+・{1{sウ+s」K{qas!#K33+・s。屁K;sk+s」・kノ)ォ・!+ウ+qサK」CKq」C)・k)#+ウK){・ン{;・iqK。kノ)イヒ姙ccノKkツ+k+s」+!サK」A 」サyk屮 [+] shift = 6 &6・V譌B匁f・ヨF柳・問6WF匁r襭F没友ツ6ラV譁6F柳・・F・・ヨR・・Fヨ蹤VR&匁'・F没唯蟲メF・&唯&W&W6V蹠2ニ・ツ7FFRv友・RGv・・6・ニRfヌVW2・F・6RfヌVW2&Rヨ・B6ヨヌ・&W&W6V蹤VB2V友・"・ツ'WB・"&W&W6V蹤F柳・7V6・2G'VRヌ6Rツ妨2イ(・ツ・fb&R6ヨ爭F・fニr・45Dgカ佑U・・S妹SUE4・gE7ミ・F・6・&W7FV・R&WGvVV・F・6RfヌVW2襭F・∠6・ツ7FFW2F・V襷W&ヌ末誡7F・vR・FWf・R・ヨGFW"6fV蹤柳篦襭F貿fW&V蹌76没贍V蹠2ヨ・&RW6VBWfV・v友・・F・6ヨRFWf・R・&&メ・唯ヨ・&R ∠6・ニヌ・儲ニVヨV蹤VBv友・Gv7F [+] shift = 7 -トm縈ョ・フ・-フ・・・・・m縨ョュヘ,l.・腠eト ・M-フ.O$・・・f+、 ?m,M研フ-汐ョeト・$ 遣ャュホ軒・・・$種螳n・ 、、l-ャ、鍵ヘ,l、ァ-曻ヲェ駒雅靖,ホ矩ヲo。J・、m琮Lョ
shift=2の時に復号できている。
CCTF{it5_3n0u9h_jU5T_tO_sH1ft_M3}