この大会は2021/10/2 7:00(JST)~2021/10/4 7:00(JST)に開催されました。
今回もチームで参戦。結果は4154点で18チーム中4位でした。
自分で解けた問題をWriteupとして書いておきます。
Scrambled JPEGs (Algorithms)
以下の処理が指示されている。
5バイトを1ブロックとして処理をする。 ・0 1 2 3 4 -> 4 2 3 1 0という順序に変える。 ・偶数ブロックと奇数ブロックを逆にする。 ・偶数ブロックは右に2バイトシフト、奇数ブロックは左に1バイトシフト
上記のロジックから逆の処理を行い、復号する。
with open('scrambled.jpg', 'rb') as f: enc = f.read() blocks = [enc[i:i+5] for i in range(0, len(enc), 5)] for i in range(len(blocks)): b = blocks[i] if i % 2 == 0: blocks[i] = b[2:] + b[:2] else: blocks[i] = b[-1:] + b[:-1] for i in range(0, len(blocks), 2): blocks[i], blocks[i+1] = blocks[i+1], blocks[i] for i in range(len(blocks)): b = blocks[i] blocks[i] = b[4] + b[3] + b[1] + b[2] + b[0] dec = ''.join(blocks) with open('flag.jpg', 'wb') as f: f.write(dec)
O2F{0v3r_345y_3gg5}
Fibbo Frenzy (Algorithms)
1000番目までのフィボナッチ数列で素数判定し、素数の合計を求める。
from Crypto.Util.number import * fibs = [0, 1] for i in range(2, 1001): v = fibs[i-1] + fibs[i-2] fibs.append(v) sum = 0 for f in fibs: if isPrime(f): sum += f print sum
実行結果は以下の通り。
132725674935014129884681801561570257444232919795125324970917377000488365086871380952521159138505357911319846367559249240
O2F{132725674935014129884681801561570257444232919795125324970917377000488365086871380952521159138505357911319846367559249240}
Barred for life! (OSINT)
バーコードの画像から対応する製品に関する質問に答えていく。バーコードのナンバーは885909918188。885909918188を調べると、以下のページなどで情報を確認できる。
https://www.upcitemdb.com/upc/885909918188 https://www.buycott.com/upc/885909918188
上記のサイトなどでこのような情報が得られる。
UPC 885909918188 is associated with Apple MacBook Pro 13" Retina Display MF840LLA Intel Core i5 2.7GHz 8GB 256GB SSD Model #:MF840LL/A Apple MacBook Pro A1502 13.3" Laptop - MF840LL/A (March, 2015)
モデルナンバーは?
O2F{MF840LL/A}
デバイスは?(Manufacturer + Modelという形式)
O2F{Apple MacBook Pro}
デバイスのドライブ容量は?
O2F{256 GB}
製造された年は?
O2F{2015}
School is cool! (Rev)
各文字のASCIIコードで199とXORしたものと比較しているので、そのことを前提に復号する。
vals = [159, 168, 181, 152, 178, 152, 245, 152, 164, 247, 247, 171, 152, 243, 152, 189, 164, 175, 247, 168, 246] flag = '' for val in vals: flag += chr(val ^ 199) print flag
復号結果は以下の通り。
Xor_u_2_c00l_4_zch0o1
O2F{Xor_u_2_c00l_4_zch0o1}
Bashing My Head In (Rev)
.bash_historyとパスワード付きzip、パスワード生成スクリプトが添付されている。スクリプトを見ると、passwordは時刻から導き出したseedを元に生成している。.bash_historyからpasswordgen.pyを実行した時刻がわかる。seedの可能性があるのは10**5個あるので、そこからパスワードのリストを作成する。
#!/usr/bin/python3 from datetime import datetime class Random: def __init__(self, seed=None): if seed is None: self.seed = round(int(time.time() * (10 ** 5))) else: try: self.seed = int(seed) except ValueError: raise ValueError("Please use a valid integer for the seed.") self.next_seed = 0 def __generatePercentage(self): a = 1664525 c = 1013904223 m = 2 ** 32 if self.next_seed == 0: next_seed = (self.seed * a + c) % m else: next_seed = (self.next_seed * a + c) % m self.next_seed = next_seed randomPercentage = next_seed / m return randomPercentage def choice(self, index): randomIndex = round((self.__generatePercentage() * (len(index) - 1))) randomChoice = index[randomIndex] return randomChoice tstr = '2021-09-24 18:35:20 -0400' t = datetime.strptime(tstr, '%Y-%m-%d %H:%M:%S %z') min_seed = int(t.timestamp() * (10 ** 5)) max_seed = min_seed + 10 ** 5 alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890?!@#$%^&*()" for seed in range(min_seed, max_seed): rand = Random(seed) print(''.join([rand.choice(alphabet) for i in range(16)]))
$ python3 solve.py > password.lst
作成したパスワードのリストを使って、zipパスワードのクラックをする。
$ fcrackzip -u -D -p password.lst data.zip PASSWORD FOUND!!!!: pw == zPd9GoG?ECOho71& $ unzip -P "zPd9GoG?ECOho71&" data.zip Archive: data.zip extracting: flag.txt $ cat flag.txt O2F{t1m3_w0und5_4ll_h33l5}
O2F{t1m3_w0und5_4ll_h33l5}
Shake that AES for me! (Rev)
スクリプトの処理概要は以下の通り。
・AES鍵:'H@ck3rMan__kN0ws' ・flag1:入力 ・AES_flag1_cipher:AES-ECBでflag1を暗号化 →'\x19\xe3\xc9\xa8\xf2\x05\xdaX\x90aP~\xe2L\xbeY'と一致していたら次のパート ・msg_input: 入力(hex) ・msg: msg_inputの0x付きの16進数文字列 ・msg: 10bit左シフト(一番左のビットは一番右へ移動) ・msg: 3bit右シフト(一番右のビットは一番左へ移動) →"b92faa3419b6afa0363619"と一致していたら、入力文字からフラグを構成される。
最初のパートは、AES鍵がわかっているので、そのまま復号する。次のパートは7bit左シフトしているのと同じため、7bit右シフトして復号する。
#!/usr/bin/python3 from Crypto.Cipher import AES import bitstring def Mathers(i, msg): msg.ror(1) return msg flag1_enc = b'\x19\xe3\xc9\xa8\xf2\x05\xdaX\x90aP~\xe2L\xbeY' AES_key = b'H@ck3rMan__kN0ws' flag1_cipher = AES.new(AES_key, AES.MODE_ECB) flag1 = flag1_cipher.decrypt(flag1_enc).decode() print('[+] flag1: ' + flag1) msg_enc = 'b92faa3419b6afa0363619' msg = bitstring.BitArray(hex='0x' + msg_enc) for i in range(7): msg = Mathers(i, msg) flag2 = bytes.fromhex(str(msg).lstrip('0x')).decode() print('[+] flag2: ' + flag2) flag = 'O2F{%s%s}' % (flag1, flag2) print('[*] flag : ' + flag)
実行結果は以下の通り。
[+] flag1: DiViD3_@nD_C0nQu [+] flag2: 3r_Th3m_@ll [*] flag : O2F{DiViD3_@nD_C0nQu3r_Th3m_@ll}
O2F{DiViD3_@nD_C0nQu3r_Th3m_@ll}
Dare To Be Stupid (Forensics-Analytics)
$ file diputsebote.rad.1 diputsebote.rad.1: dar archive, label "44024461 00000000 8302"
darファイルが16個入っている。ファイル名をすべて以下のように修正する。
diputsebote.rad.1 -> diputsebote.1.dar
$ sudo dar -x diputsebote The format version of the archive is too high for that software version, try reading anyway? [return = YES | Esc = NO] Continuing... -------------------------------------------- 5 inode(s) restored including 0 hard link(s) 0 inode(s) not restored (not saved in archive) 0 inode(s) not restored (overwriting policy decision) 0 inode(s) ignored (excluded by filters) 0 inode(s) failed to restore (filesystem error) 0 inode(s) deleted -------------------------------------------- Total number of inode(s) considered: 5 -------------------------------------------- EA restored for 0 inode(s) FSA restored for 0 inode(s) --------------------------------------------
5個のjpgを復旧でき、そのうち4.jpgにフラグが書いてあった。
O2F{h4rdw4re_5t0r3}
Reserved Words (Forensics-Analytics)
以前にも予約語を使った似たような問題があったので、そのときと同じようにperlで実行してみる。
$ mv "reserved words.txt" reserved_words.pl $ perl reserved_words.pl The flag is: O2F{perl_is_fun!}
O2F{perl_is_fun!}
Forgotten Password (Crypt-Stego)
$ zipinfo memearchive.enc.zip Archive: memearchive.enc.zip Zip file size: 2634651 bytes, number of entries: 7 -rwxrwxrwx 3.0 unx 27356 BX defN 21-Sep-26 07:39 meme 3.jpg -rwxrwxrwx 3.0 unx 1769703 BX defN 21-Sep-26 07:39 meme 6.gif -rwxrwxrwx 3.0 unx 11517 BX defN 21-Sep-26 07:43 manananan 9.jpg -rwxrwxrwx 3.0 unx 87495 BX defN 21-Sep-26 07:43 10.jpg -rwxrwxrwx 3.0 unx 243780 BX defN 21-Sep-26 07:43 pain 11.png -rwxrwxrwx 3.0 unx 32239 BX defN 21-Sep-26 07:41 mem8.jpg -rwxrwxrwx 3.0 unx 497607 BX defN 21-Sep-26 07:46 license.jpg 7 files, 2669697 bytes uncompressed, 2633395 bytes compressed: 1.4% $ unzip memearchive.zip Archive: memearchive.zip inflating: meme 1.png inflating: meme 2.jpg inflating: meme 4.jpg inflating: mem 5.jpg inflating: memq 7.png inflating: mem8.jpg $ ls -l mem8.jpg -rwxrwxrwx 1 root root 32239 9月 26 07:41 mem8.jpg
memearchive.zipの方にもmem8.jpgがあり、ファイルサイズ的にも同じものと考えられる。pkcrackで既知平文攻撃をして、memearchive.enc.zipを復号する。
$ zip mem8.zip mem8.jpg adding: mem8.jpg (deflated 1%) $ ./pkcrack-1.2.2/src/pkcrack -C memearchive.enc.zip -c mem8.jpg -p mem8.jpg -P mem8.zip -d decrypted.zip Files read. Starting stage 1 on Sat Oct 2 10:59:09 2021 Generating 1st generation of possible key2_31846 values...done. Found 4194304 possible key2-values. Now we're trying to reduce these... Lowest number: 943 values at offset 28081 Lowest number: 917 values at offset 28078 Done. Left with 917 possible Values. bestOffset is 28078. Stage 1 completed. Starting stage 2 on Sat Oct 2 10:59:23 2021 Ta-daaaaa! key0=bdb07b3f, key1=1e0989cd, key2=b817b2f9 Probabilistic test succeeded for 3773 bytes. Strange... had a false hit. Strange... had a false hit. Strange... had a false hit. Strange... had a false hit. Strange... had a false hit. Strange... had a false hit. Strange... had a false hit. Strange... had a false hit. Stage 2 completed. Starting zipdecrypt on Sat Oct 2 10:59:43 2021 Decrypting meme 3.jpg (df171296401a566b8aaeef94)... OK! Decrypting meme 6.gif (ef4260c8d77febf550acfc94)... OK! Decrypting manananan 9.jpg (bdb4659561cf0e6df9f66a95)... OK! Decrypting 10.jpg (5f0fbabed5857871422e6d95)... OK! Decrypting pain 11.png (80d170db68a6de6fdaf47a95)... OK! Decrypting mem8.jpg (18bc5cccc97dc033b0903195)... OK! Decrypting license.jpg (7573f47a29d6bd74c450c995)... OK! Finished on Sat Oct 2 10:59:43 2021 $ unzip decrypted.zip Archive: decrypted.zip inflating: meme 3.jpg inflating: meme 6.gif inflating: manananan 9.jpg inflating: 10.jpg inflating: pain 11.png replace mem8.jpg? [y]es, [n]o, [A]ll, [N]one, [r]ename: y inflating: mem8.jpg inflating: license.jpg
license.jpgにフラグが書いてあった。
O2F{p141nt3xt_15_p41n}
Based (Crypt-Stego)
from base64 import * enc = '3b 61 7f fc 10 12 13 ae 04 34 23 83 10 3f ff'.split(' ') enc = ''.join([chr(int(c, 16)) for c in enc]) flag = b64encode(enc) print flag
O2F//BASE64ENCODED//
San Francisco (Crypt-Stego)
ルータのコンフィグファイルが添付されている。Ciscoのtype 7のパスワードと思われる記述がある。このパスワードをhttps://www.firewall.cx/cisco-technical-knowledgebase/cisco-routers/358-cisco-type7-password-crack.htmlでクラックする。
w34k_v1gn3re
O2F{w34k_v1gn3re}