この大会は2019/12/31 19:00(JST)~2020/1/1 19:00(JST)に開催されました。
今回もチームで参戦。結果は872点で554チーム中41位でした。
自分で解けた問題をWriteupとして書いておきます。
we1c0me (General)
リンク先の動画にフラグが書かれている。
BAMBOOFOX{we1c0me_t0_B4mbooF0x_CTF}
How2decompyle (Reverse)
ファイルの種類を確認すると、Pythonのバイトコードであるとわかるので、デコンパイルする。
$ file decompyle decompyle: python 2.7 byte-compiled $ mv decompyle decompyle.pyc $ uncompyle6 decompyle.pyc # uncompyle6 version 3.6.0 # Python bytecode 2.7 (62211) # Decompiled from: Python 3.6.8 (default, Oct 9 2019, 14:04:01) # [GCC 5.4.0 20160609] # Embedded file name: decompyle.py # Compiled at: 2019-09-22 21:18:03 import string restrictions = [ 'uudcjkllpuqngqwbujnbhobowpx_kdkp_', 'f_negcqevyxmauuhthijbwhpjbvalnhnm', 'dsafqqwxaqtstghrfbxzp_x_xo_kzqxck', 'mdmqs_tfxbwisprcjutkrsogarmijtcls', 'kvpsbdddqcyuzrgdomvnmlaymnlbegnur', 'oykgmfa_cmroybxsgwktlzfitgagwxawu', 'ewxbxogihhmknjcpbymdxqljvsspnvzfv', 'izjwevjzooutelioqrbggatwkqfcuzwin', 'xtbifb_vzsilvyjmyqsxdkrrqwyyiu_vb', 'watartiplxa_ktzn_ouwzndcrfutffyzd', 'rqzhdgfhdnbpmomakleqfpmxetpwpobgj', 'qggdzxprwisr_vkkipgftuvhsizlc_pbz', 'jerzhlnsegcaqzathfpuufwunakdtceqw', 'lbvlyyrugffgrwo_v_zrqvqszchqrrljq', 'aiwuuhzbszvfpidwwkl_wynlujbsbhfox', 'vmhrizxtiegxdxsqcdoiyxkffloudwtxg', 'tffjnabob_jbf_qiszdsemczghnjysmah', 'zrqkppvynlkelnevngwlkhgaputhoagtt', 'nl_oojyafwoqccbedijmigpedkdzglq_f', 'cksy_skctjlyxktuzchvstunyvcvabomc', 'ppcxleeguvhvhengmvac_bykhzqohjuei', '_clmaicjrrzhwd_fescyaejtbyefxyihy', 'hhopvwsmjtpjiffzatyhjrev_dwnsidyo', 'sjevtrmkkk_zjalxrxfovjsbcxjx_pskp', 'gnynwuuqypddbsylparpcczqimimqmvdl', 'bxitcmhnmanwuhvjxnqeoiimlegrmkjra'] capital = [ 0, 4, 9, 19, 23, 26] flag = raw_input('Please tell me something : ').lower() flag = flag.lower() if len(flag) != len(restrictions[0]): print 'No......You are wrong orzzzzz' exit(0) for f in range(len(flag)): for r in restrictions: if flag[f] not in string.lowercase + '_' or flag[f] == r[f]: print 'No......You are wrong orzzzzzzzzzzzz' exit(0) cap_flag = '' for f in range(len(flag)): if f in capital: cap_flag += flag[f].upper() else: cap_flag += flag[f] print 'Yeah, you got it !\nBambooFox{' + cap_flag + '}\n' # okay decompiling decompyle.pyc
以下の条件を満たすものを探す。
・flagはrestrictions[0]と同じ長さ ・以下のいずれか ・flagは英小文字や_でない。 ・restrictionsの各バイト目で使われていない。
import string def check_no_char(s): chars = string.lowercase + '_' for c in chars: if c not in s: return c return '' restrictions = [ 'uudcjkllpuqngqwbujnbhobowpx_kdkp_', 'f_negcqevyxmauuhthijbwhpjbvalnhnm', 'dsafqqwxaqtstghrfbxzp_x_xo_kzqxck', 'mdmqs_tfxbwisprcjutkrsogarmijtcls', 'kvpsbdddqcyuzrgdomvnmlaymnlbegnur', 'oykgmfa_cmroybxsgwktlzfitgagwxawu', 'ewxbxogihhmknjcpbymdxqljvsspnvzfv', 'izjwevjzooutelioqrbggatwkqfcuzwin', 'xtbifb_vzsilvyjmyqsxdkrrqwyyiu_vb', 'watartiplxa_ktzn_ouwzndcrfutffyzd', 'rqzhdgfhdnbpmomakleqfpmxetpwpobgj', 'qggdzxprwisr_vkkipgftuvhsizlc_pbz', 'jerzhlnsegcaqzathfpuufwunakdtceqw', 'lbvlyyrugffgrwo_v_zrqvqszchqrrljq', 'aiwuuhzbszvfpidwwkl_wynlujbsbhfox', 'vmhrizxtiegxdxsqcdoiyxkffloudwtxg', 'tffjnabob_jbf_qiszdsemczghnjysmah', 'zrqkppvynlkelnevngwlkhgaputhoagtt', 'nl_oojyafwoqccbedijmigpedkdzglq_f', 'cksy_skctjlyxktuzchvstunyvcvabomc', 'ppcxleeguvhvhengmvac_bykhzqohjuei', '_clmaicjrrzhwd_fescyaejtbyefxyihy', 'hhopvwsmjtpjiffzatyhjrev_dwnsidyo', 'sjevtrmkkk_zjalxrxfovjsbcxjx_pskp', 'gnynwuuqypddbsylparpcczqimimqmvdl', 'bxitcmhnmanwuhvjxnqeoiimlegrmkjra'] capital = [0, 4, 9, 19, 23, 26] flag = '' for i in range(len(restrictions[0])): s = '' for j in range(len(restrictions)): s += restrictions[j][i] flag += check_no_char(s) cap_flag = '' for f in range(len(flag)): if f in capital: cap_flag += flag[f].upper() else: cap_flag += flag[f] print 'Yeah, you got it !\nBambooFox{' + cap_flag + '}\n'
BambooFox{You_Know_Decompyle_And_Do_Reverse}
I can't see you! (Misc)
rarファイルにはパスワードがかかっている。johnでクラックする。
$ rar2john what.rar > hash.txt $ john --wordlist=dict/rockyou.txt hash.txt --rules Loaded 1 password hash (RAR5 [PBKDF2-SHA256 128/128 SSE4.1 4x]) Warning: OpenMP is disabled; a non-OpenMP build may be faster Press 'q' or Ctrl-C to abort, almost any other key for status blind (what.rar) 1g 0:00:03:02 DONE (2019-12-31 21:06) 0.005474g/s 105.6p/s 105.6c/s 105.6C/s bre123..benten Use the "--show" option to display all of the cracked passwords reliably Session completed
パスワードblindで解凍すると、点字の画像が展開される。
点字を文字にデコードする。
BAMBOOFOX { YA_YOU_ KNOW_WHAT_ BLIND_ MEANS }
BAMBOOFOX{YA_YOU_KNOW_WHAT_BLIND_MEANS}
Find the Cat (Misc)
$ binwalk cat.png DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 PNG image, 739 x 554, 8-bit/color RGBA, non-interlaced 101 0x65 Zlib compressed data, best compression 371382 0x5AAB6 PNG image, 739 x 554, 8-bit/color RGBA, non-interlaced 371483 0x5AB1B Zlib compressed data, best compression
後ろにPNGがもう一つ付いている。
$ foremost cat.png Processing: cat.png |*|
似たような画像がもう一つ入っていた。差分を白黒で画像にしてみる。
from PIL import Image img1 = Image.open('00000000.png').convert('RGB') img2 = Image.open('00000725.png').convert('RGB') w, h = img1.size output_img = Image.new('RGB', (w, h), (255, 255, 255)) for y in range(0, h): for x in range(0, w): r1, g1, b1 = img1.getpixel((x, y)) r2, g2, b2 = img2.getpixel((x, y)) if r1 == r2 and g1 == g2 and b1 == b2: output_img.putpixel((x, y), (255, 255, 255)) else: output_img.putpixel((x, y), (0, 0, 0)) output_img.save('diff.png')
QRコードになったので、読み取る。
https://imgur.com/download/Xrv86y2
このURLにアクセスすると、Xrv86y2 - Imgur.jpgがダウンロードできた。バイナリエディタで見るとPrintableな文字ばかり含まれているので、BAMBOOFOXで検索してみると、フラグが見つかった。
BAMBOOFOX{Y0u_f1nd_th3_h1dd3n_c4t!!!}
oracle (Crypto)
$ nc 34.82.101.212 20001 1) Info 2) Decrypt 3) Exit > 1 c = 3707379833111040015783163740193874788414803250531435971653144043446898319590407294871874573636048964074059158735677108453718201912319567996556576283315815748346821418011805401072680103982963210417620997185812458739089731859722602065043829112903847812848345496034190632584920309575488320362226972676630275524 n = 96194794049596317702519938191271814417816716400282810425930600761352066370293757401367088699070463576925336421861089418264302022319363405255438953242163929922974851426935044638903429374717691402537243254925572965917089355609141962782853759805533770299159601171220779548891129054688964114370404823325735253993 1) Info 2) Decrypt 3) Exit > 2 c = 123 m = 1 1) Info 2) Decrypt 3) Exit > 3
復号した結果を3で割った数がわかる。2で割った数がわかる場合は通常のRSA LSB Decryption Oracle Attackで解けるが、そのままでは解けないので、RSA LSB Decryption Oracle Attackの原理を考え、スクリプトをカスタマイズする。
fを復号関数とする。 a = 3^e mod n -> f(a^i * c) = (3^i * m mod n) mod 3 i = 1の場合、f(a * c) = (3*m mod n) mod 3 以下の条件を満たす ・3m < 3n ・3m / n = 0 or 1 or 2 ★n % 3 == 1 ☆f(ac) = 2 3*m mod n ⇒ n < 3*m < 2*n ⇒ n/3 < m < n*2/3 ☆f(ac) = 1 3*m mod n ⇒ 2*n < 3*m < 3*n ⇒ n*2/3 < m < n ☆f(ac) = 0 3*m mod n ⇒ 0 < 3*m < n ⇒ 0 < m < n/3 ★n % 3 == 2 ☆f(ac) = 2 3*m mod n ⇒ 2*n < 3*m < 3*n ⇒ n*2/3 < m < n ☆f(ac) = 1 3*m mod n ⇒ n < 3*m < 2*n ⇒ n/3 < m < n*2/3 ☆f(ac) = 0 3*m mod n ⇒ 0 < 3*m < n ⇒ 0 < m < n/3
from fractions import Fraction from Crypto.Util.number import * import socket def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) def remainder_oracle(enc): data = recvuntil(s, '>') print data + '2' s.sendall('2\n') data = recvuntil(s, '= ') print data + str(enc) s.sendall(str(enc) + '\n') data = recvuntil(s, '\n').rstrip() print data m = int(data.split(' = ')[1]) return m s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('34.82.101.212', 20001)) data = recvuntil(s, '>') print data + '1' s.sendall('1\n') data = recvuntil(s, '\n').rstrip() print data c = int(data.split(' = ')[1]) data = recvuntil(s, '\n').rstrip() print data n = int(data.split(' = ')[1]) e = 65537 bounds = [0, Fraction(n)] i = 0 m = 0 while True: print 'Round %d' % (i + 1) i += 1 c2 = (c * pow(3, e, n)) % n remainder = remainder_oracle(c2) diff = bounds[1] - bounds[0] if remainder == 2: if n % 3 == 1: bounds[0] = bounds[0] + diff/3 bounds[1] = bounds[1] - diff/3 elif n % 3 == 2: bounds[0] = bounds[1] - diff/3 elif remainder == 1: if n % 3 == 1: bounds[0] = bounds[1] - diff/3 elif n % 3 == 2: bounds[0] = bounds[0] + diff/3 bounds[1] = bounds[1] - diff/3 else: bounds[1] = bounds[0] + diff/3 diff = bounds[1] - bounds[0] diff = diff.numerator / diff.denominator if diff == 0: m = bounds[1].numerator / bounds[1].denominator break c = c2 flag = long_to_bytes(m) print flag
BAMBOOFOX{SimPlE0RACl3}