상세 컨텐츠

본문 제목

Tcache

SYSTEM HACKING/Exploit Tech

by koharin 2020. 6. 10. 14:51

본문

728x90
반응형

1. Tcache(Thread local Caching)

 

glibc 2.26 버전 이후 힙 메모리 관리 매커니즘

-> 주어진 라이브러리 버전을 보고 Tcache 여부 판단한다.

힙 메모리 관리 속도 향상 위해 추가 -> 이전 버전보다 공격이 쉽다.

 

malloc() 함수로 동적 할당 요청이 들어오면 __libc_malloc 호출된다.

 

__libc_malloc 함수: MAYBE_INIT_TCACHE 매크로 호출해 tcache_init 함수 호출한다.

 

#define MAYBE_INIT_TCACHE() \
  if (__glibc_unlikely (tcache == NULL)) \
    tcache_init();
void * __libc_malloc (size_t bytes)
{
    ...
    MAYBE_INIT_TCACHE ();
}

 

tcache_init 함수: tcache_perthread_struct 구조체를 힙 영역에 할당 후 초기화하는 역할. 구조체는 힙 페이지의 맨 첫 부분에 할당한다.

tcache_perthread_struct 구조체:  tcache_entry 관리. glibc 2.26 버전 이후 할당된 tcache의 힙 관리.

 

(이전 버전에서는 할당된 힙을 main_arena가 관리했다.)

tcache_entry 구조체: 멤버 변수 next 포인터는 tcache->entries의 연결 리스트 관리한다.

typedef struct tcache_perthread_struct
{
  char counts[TCACHE_MAX_BINS];
  tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;

 

fastbin과 차이점

(1) tcache는 fd가 fd를 가리킨다. (fastbin에서는 prev_size를 가리킨다.)

(2) tcache는 병합이 발생하지 않으므로 prev_size, prev_inuse_bit 설정하지 않는다.

(3) tcache는 힙에 있는 tcache_perthread_struct가 관리하고, fastbin은 libc에 존재하는 main_arena가 관리한다. 

 

 

2. tcache_put 함수

 

static void tcache_put (mchunkptr chunk, size_t tc_idx)
{
  tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
  assert (tc_idx < TCACHE_MAX_BINS);
  e->next = tcache->entries[tc_idx];
  tcache->entries[tc_idx] = e;
  ++(tcache->counts[tc_idx]);
}

- 해제 요청 들어오면 tcache->entries(tcache list)에 해제된 힙 청크의 주소를 추가한다.

- 동일한 크기의 tcache->entries는 7개의 힙 청크만 관리한다. -> 8번째 free 청크는 fastbin 또는 smallbin에 들어간다. 

- 새로 들어온 청크의 next에 기존에 존재하던 청크의 주소를 넣는다.

- _init_malloc과 _init_free에서 호출된다.

- fastbin과 smallbin 크기의 청크 해제 시 먼저 tcache가 관리한다.

 

★ free 함수가 호출되면 _init_free가 호출되고, 해제된 힙 청크 주소를 tcache->entries에 삽입할 때 힙 청크의 크기와 유효한 주소인지만 검증하고 Double Free에 대한 검증이 없다.

 

 

3. tcache_get 함수

 

static void *tcache_get (size_t tc_idx)
{
  tcache_entry *e = tcache->entries[tc_idx];
  assert (tc_idx < TCACHE_MAX_BINS);
  assert (tcache->entries[tc_idx] > 0);
  tcache->entries[tc_idx] = e->next;
  --(tcache->counts[tc_idx]);
  return (void *) e;
}

- 저장되어 있는 tcache->entries(tcache list)에서 힙 청크를 가져온다. 

- 가져온 힙 청크의 next 포인터를 tcache->entries에 삽입 후 힙 청크 주소를 반환한다.

- _libc_malloc과 _init_malloc에서 호출된다.

- 요청된 크기에 맞는 tcache_entry 존재하면 tcache_get 함수가 호출된다.

예외처리가 존재하지 않아 공격이 쉽다.

 

_libc_mallc: malloc 호출 시 가장 먼저 호출되고, _libc_malloc에서 _init_malloc을 호출한다.

★ fastbin처럼 fake chunk size를 맞출 필요가 없다.

 

 

4. 예시

 

// gcc -o tcache_ex tcache_ex.c -no-pie
#include <stdio.h>
#include <stdlib.h>
int main()
{
	char *ptr = malloc(0x10);
	char *ptr2 = malloc(0x20);
	char *ptr3 = malloc(0x30);
	free(ptr);
	free(ptr2);
	free(ptr3);
	ptr = malloc(0x10);
	ptr2 = malloc(0x20);
	ptr3 = malloc(0x30);
}

 

 

 

힙 페이지 시작 부분(0x602000)을 확인해보면, 0x251 크기를 가진 힙 청크가 존재한다.

malloc 호출 시 tcache_init 함수를 통해 tcache_perthread_struct 구조체가 힙 영역에 할당된 것이다.

 

(1) 첫 번째 청크 해제 

 

 

첫 번째 free 함수 호출한 직후 모습이다.

첫 번째 청크 해제 후, tcache_count가 1 증가했다.

 

tcache_entry의 0번 인덱스에 해제된 청크의 주소가 적힌다.

 

(2) 두 번째 청크 해제

 

 

두 번째 힙 청크는 첫 번째 청크와 다른 tcache_entry 인덱스를 가지고 있다.

두 번째 청크 해제 시 tcacahe_count가 증가하고, tcache_entry에 두 번째 청크에 대한 포인터가 적힌다.

 

(3) 세 번째 힙 청크 해제

 

 

세 번째 힙 청크 해제된 후에도 tcache_count가 증가하고, tcache_entry에 세 번째 청크에 대한 포인터가 적힌다.

 

따라서 각 크기마다 tcache_entry와 tcache_count가 관리되는 것을 확인할 수 있다.

 

(4) 첫 번째 tcache_entry가 관리하는 크기의 청크 재할당

 

첫 번째 tcache_entry의 tcache_count가 감소되어 0이 되었다.

첫 번째 포인터 위치에 재할당되었으므로 tcache_entry에서 포인터가 지워진 것을 확인할 수 있다.

 

5. 예시2

 

// gcc -o tcache_escape tcache_escape.c -no-pie
#include <stdio.h>
#include <stdlib.h>
int main()
{
	char *ptr[8];
	int i;
	for(i=0;i<=7;i++) {
		printf("malloc !\n");
		ptr[i] = malloc(0x20);
	}
	for(i=0;i<=7;i++) {
		printf("free!\n");
		free(ptr[i]);
	}
}

tcache는 7개의 힙 청크만 관리하므로 7개까지는 tcache_entry에 들어가지만, 나머지 해제된 1개는 fastbin에 들어가게 된다.

 


 

 

 

 

728x90
반응형

'SYSTEM HACKING > Exploit Tech' 카테고리의 다른 글

fastbin dup  (0) 2020.06.10
Tcache Dup  (0) 2020.06.10
Master canary  (0) 2020.06.08
Stack Frame & 함수 호출 규약 (32bit, 64bit)  (0) 2020.05.30
[Back to Basic] Linux exploitation & Mitigation #1  (0) 2020.04.06

관련글 더보기