この大会は2022/11/13 2:00(JST)~2022/11/14 2:00(JST)に開催されました。
今回もチームで参戦。結果は1022点で205チーム中17位でした。
自分で解けた問題をWriteupとして書いておきます。
Sanity Check (Misc)
問題にフラグが書いてあった。
COMPFEST14{Go0d_LucK_4nd_H4vE_FuN_8e53852062}
c0rR3ct10n (Forensics)
PNGフォーマットを逆転し、PNGシグネチャの逆転部分をJPGのヘッダの逆転部分にしたもののようなので、元に戻す。
#!/usr/bin/env python3 with open('lemaoo.png', 'rb') as f: data = f.read() data = data[::-1] data = b'\x89PNG\x0d' + data[5:] with open('lemaoo_fix.png', 'wb') as f: f.write(data)
画像は白黒のものになっていて、8ビットで1つの文字になりそうなので、0, 1に置き換え、デコードする。
#!/usr/bin/env python3 from PIL import Image img = Image.open('lemaoo_fix.png').convert('L') w, h = img.size b = '' for y in range(h): for x in range(w): white = img.getpixel((x, y)) if white == 0: b += '0' else: b += '1' msg = '' for i in range(0, len(b), 8): msg += chr(int(b[i:i+8], 2)) print(msg)
デコード結果は以下の通り。
$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7$#!7https://tinyurl.com/m00nlander$#!7$#!7$#!7$#!7
この文字列の最後の方に以下のURLが埋め込まれている。
https://tinyurl.com/m00nlander
このURLにアクセスすると、m00n.jpgがダウンロードできる。ファイルフォーマットはpngが壊れている状態。シグネチャとシグネチャとIENDチャンクを修復し、画像の幅と高さをブルートフォースで修復する。
#!/usr/bin/env python3 import struct import binascii with open('m00n.jpg', 'rb') as f: data = f.read() data = b'\x89PNG\x0d\x0a' + data[6:-4] + b'\xae\x42\x60\x82' head = data[:12] tail = data[29:] found = False for h in range(1, 2048): for w in range(1, 2048): width = struct.pack('>I', w) height = struct.pack('>I', h) ihdr = data[12:16] + width + height + data[24:29] crc = struct.pack('!I', binascii.crc32(ihdr)) if crc == data[29:33]: found = True out = head + ihdr + tail with open('m00n_fix.png', 'wb') as f: f.write(out) break if found: break
修復した画像をStegSolveで開き、Red plane 4を見ると、フラグが書いてあった。
COMPFEST14{hHhH_th0u_4re_c0Rr3ct!_634af16261}
Seems Familiar (Cryptography)
$ nc 13.212.50.63 11688 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit > 1 Sorry, the get_flag function is currently broken. Please try something else. 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit > 3 Sorry, the decrypt function is currently broken. Please try something else. 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit > 2 message (in hex) = 01 ciphertext (in hex): 442a1735d39a53305034ba74eb55e0afe21e409460204df2de0a27cd35f4267db2a827ccc972fc5e44e55fdb7c413e306aa543695b8bf9549b7d9c8a80f3c457ed853e642bdd50432eb9fa3eca74b6678cf2ba2683f3b2df8c6386daa2d413421f982cbb9b1d7711509ac86efb60b383 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit > 2 message (in hex) = 01234567 ciphertext (in hex): 36b784caea6e47cda9789dcc4ea2ca2ed3833905172743e725463b44f619d6b49803afe8c2259c7e48a89e026b1fbf8084c35b182479744c533d2c5f83fba464f1216cc1545697cec4177e7364afa0dc7d78ad27d355b5c5f816d089fe4ee6613ef406130989ac3fcddcda5d020f657b 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit > 2 message (in hex) = 0123456789ab ciphertext (in hex): 8da318a802fbfe408038290f7c0044a111df296ee4a9b98fc1bcd55398c1296d7c7a68eb0c82443db079efd8068dd937b4a8dccff6bb1429280310dcd19ba5050d1d6bb373d9e55599b034c1fa8a50c0ad589430c420707ceb69cd2df856b48f2d4410a310e0e22724eca54407b4a842 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit > 2 message (in hex) = 0123456789abcdef ciphertext (in hex): 5fae2af342b436f5960c491aee2bce1f271beea4ec5a11008e99636a79dfcfc03df73c327244438dcd37a6de8afb26fd568df9b09ffad97821a2f744b8f9f865c8b8aa9a03f76aa860623cb12f71457fdcc6d3428471da4f715ed939d9632f1da973d0184612add316f2ac6ffede6299 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit > 2 message (in hex) = 0123456789abcdef0123 ciphertext (in hex): bbb38b54ef7f87872ecd3918efd4e550de4d6c9de2dd85b6a3f29dbea516b0a3b8f7f19f3aefde378a70b07b386c9ab0803918ce18eb90f81657ada4394ba195fceff5c1ef61da75564fcd7de2b9aa2adadd5496d09dfce3dc410440b167eb8992e6d0d1a6e8e4f53bd589712fc074bc 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit > 2 message (in hex) = 0123456789abcdef01234567 ciphertext (in hex): 7ed453a2f1dbe838c54b6cdf437bb2f3cb8ee75fbe2ac4ff6c25b734350abe4e92271bb74e90f3e1fecb27226e8435f21d7183c871d75949a4fdcecdbb0d804ff7d6b3d4f2eae8e141c7ff46df63c975d726f7008407fe831b7021ec9c50c68d31ec29e52d7e1d7430d8a3856602e099 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit > 2 message (in hex) = 0123456789abcdef0123456789ab ciphertext (in hex): 5ccd969f2e70cbd0f8136874ec7c299d88f500f79976b1bf0d559d80ff3d63818f16d8027144485ac0048ed7e2d9845b06974b2332dfa59c86e68d648fdf3831b938c16fcb1191537be5a30672cdb0d9143430e69eb988302d5b6e02cead5ea497a1394817f38b7b37bc124ba0fa28a7 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit > 2 message (in hex) = 0123456789abcdef0123456789abcd ciphertext (in hex): d08d6b104b9c6d8b39de04ad39d7d4753760b21d332aa554f193247ce8b80803e412243526544715a4178b7be31490b6f7937ca2404626b3e1cc903051210a96275353032c7c9f5887460f6ea1c89b0ed5b8b407db5d5e3e9ad20266939348cd0c812f0d51827a447479dfb1d1693fe2 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit > 2 message (in hex) = 0123456789abcdef0123456789abcdef ciphertext (in hex): eeba4020a92f51ccb08f40230098e8c5066c6fdf5cc92ac89a988d55c087bbaeea46f1572482ba05ca7df9e37b0f51a89e20f8a65bce827356b4742c36d3a65fc2fd9a41f5b37df1a551d61051659f22c0f86f2315a772aa7b0d4b0765ce5069684bba6974f816298fb9a44f40579696 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit > 2 message (in hex) = 0123456789abcdef0123456789abcdef01 ciphertext (in hex): eeba4020a92f51ccb08f40230098e8c5442a1735d39a53305034ba74eb55e0afe21e409460204df2de0a27cd35f4267db2a827ccc972fc5e44e55fdb7c413e306aa543695b8bf9549b7d9c8a80f3c457ed853e642bdd50432eb9fa3eca74b6678cf2ba2683f3b2df8c6386daa2d413421f982cbb9b1d7711509ac86efb60b383 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit $ nc 13.212.50.63 11688 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit > 2 message (in hex) = 1111111111111111111111111111111111111111111111111111111111111111 ciphertext (in hex): 660995f5cbd73d0172f762fb6e53ab93660995f5cbd73d0172f762fb6e53ab93170dc1d2c55ff93f927ee5c27856acb793d6ec9cbcf87fe06773e72ee849748455cfb2892c070b19f0d812c7b7218691fd3761aa5d84f844df1bca34f96a5a38a0fb000c40b54c5f55fe00906ee8ef98bde103065d72c722afc0121d0b60c176 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit
AES暗号で暗号ブロックの構成は以下のようになると考えられる。
0123456789abcdef IIIIIIIIIIIIIIII FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF PPPPPPPPPPPPPPPP
AES暗号のECBモードと推測し、1文字ずつはみ出させて、同じ暗号となるかを確認しながら、フラグを割り出す。
0123456789abcdef XXXXXXXXXXXXXXXF XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFP
#!/usr/bin/env python3 import socket 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(('13.212.50.63', 11688)) flag = '' for i in range(96): for code in range(32, 127): print('[+] flag :', flag) try_pt = ('X' * 15 + flag)[-15:] + chr(code) + 'X' * (95 - i) try_pt_hex = try_pt.encode().hex() data = recvuntil(s, b'> ') print(data + '2') s.sendall(b'2\n') data = recvuntil(s, b'= ') print(data + try_pt_hex) s.sendall(try_pt_hex.encode() + b'\n') data = recvuntil(s, b'\n').rstrip() print(data) ct = bytes.fromhex(data.split(' ')[-1]) block0 = ct[:16] block6 = ct[96:112] if block0 == block6: flag += chr(code) break if flag[-1] == '}': break print('[*] flag:', flag)
実行結果は以下の通り。
: 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit > 2 message (in hex) = 61634c455f663937616533613034377c58 ciphertext (in hex): 65ddb452545d43e30f6eea797b9fe25a828c7d5af5ff09a31a41f1514c89b57a375ac2a114358aa7b0805375e4c76ed098d40a5f13cc2db219e5227ccf753e666638eca199133385fcfeab15659785900e1919c1a346ef44220ad67b5a4aa1878332f7775dbc529bc7a9deff5ddada4354bd510b4278397c62cff94a61157493 [+] flag : COMPFEST14{1nDeP3ndenT_bLoCK_ENCryPt10n_w1Th_fl4G_ApP3nDED_0f_course_iTS_eCB_oracLE_f97ae3a047 1. Get encrypted flag 2. Encrypt a message 3. Decrypt a message 4. Exit > 2 message (in hex) = 61634c455f663937616533613034377d58 ciphertext (in hex): 8332f7775dbc529bc7a9deff5ddada43828c7d5af5ff09a31a41f1514c89b57a375ac2a114358aa7b0805375e4c76ed098d40a5f13cc2db219e5227ccf753e666638eca199133385fcfeab15659785900e1919c1a346ef44220ad67b5a4aa1878332f7775dbc529bc7a9deff5ddada4354bd510b4278397c62cff94a61157493 [*] flag: COMPFEST14{1nDeP3ndenT_bLoCK_ENCryPt10n_w1Th_fl4G_ApP3nDED_0f_course_iTS_eCB_oracLE_f97ae3a047}
COMPFEST14{1nDeP3ndenT_bLoCK_ENCryPt10n_w1Th_fl4G_ApP3nDED_0f_course_iTS_eCB_oracLE_f97ae3a047}