Tcache Poisoning
Double Free Bug
를 이용하여 tcache_entry
를 조작하고 이미 할당된 메모리에 다시 힙 청크를 할당하는 공격 기법이다. tcache에서 사용하는 tcache_put
과 tcache_get
함수에서는 old와 p를 검증하지 않기 때문에 한 개의 청크를 연속으로 해제할 수 있다.
- 참고로 GLIBC 2.26과 2.29 이상의 버전에서는 DFB를 검증하는 로직이 추가됐다.
기본적으로 크기가 32byte ~ 1040byte
크기를 갖는 청크들의 경우에는 tcache에 보관한다.
tcache poisoning을 이해하기 위해서는 청크 개념을 알아야 한다.
[사진]의 왼쪽은 alloc 청크, 오른쪽은 free 청크다. 차이점은 alloc 청크에서는 data를 담는 부분이 free 청크에서는 fd, bk를 담는다. 3
- 여기서 생각해볼 지점은 “만약 A 청크가 alloc 청크인지 free 청크인지 구분없이 중첩된 상태라면 어떻게 될 것인가?”이다.
예제를 통해 결과를 확인해보자.
똑같은 메모리를 2번 해제한다고 가정하자.
(0x30) tcache_entry[1](2): 0x1edb260 --> 0x1edb260 (overlap chunk with 0x1edb250(freed))
tcache_entry를 확인하면 자기 자신을 next 포인터로 가리키는 것을 확인할 수 있다.
- 즉, tcache Duplication이 발생했다.
- 청크는 중첩상태가 된다.
이번에는 할당 과정을 수행해보자.
tcache_entry[1](2): 0x1edb260 --> [임의 주소]
이전과 같은 크기로 힙을 할당하고 데이터로 [임의 주소]를 입력하면 어떻게 될까?
- next 포인터가 [임의 주소]로 바뀐다.
신기한 결과가 등장했다!
할당 과정임에도 0x1edb260
주소가 청크로부터 할당되는 것이 아니라 오히려 next 포인터에 [임의 주소]가 연결됐다.
DFB에 의해 청크가 중첩 상태였기 때문에 할당을 했음에도 해제한 것과 같은 결과가 도출된 것이다.
이와 같이 tcache에 저장된 주소를 조작하는 공격을 "Tcache Poisoning"이라고 한다.
이어서 [임의 주소]에 데이터를 덮는 것까지 진행해보자.
0x1edb260 --> 1번째 할당
[임의 주소] --> 2번째 할당
힙을 같은 크기로 2번 추가 할당해보자.
1번째는 0x1edb260
이 할당된다. 다음으로 2번째는 [임의 주소]가 할당된다.
- 즉, [임의 주소]가 할당되는 시점에 데이터를 쓰면 [임의 주소]에 데이터를 쓸 수 있다.
tcache DFB mitigation Bypass
취약점을 방지하고자 GLIBC 2.29
이상 버전에서는 DFB를 방지하기 위한 mitigation이 존재한다.
tcache에 적용된 mitigation 방식과 이를 우회하는 방법을 알아보자.
static __always_inline void tcache_put (mchunkptr chunk, size_t tc_idx)
{
tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
assert (tc_idx < TCACHE_MAX_BINS);
/* Mark this chunk as "in the tcache" so the test in _int_free will
detect a double free. */
e->key = tcache;
e->next = tcache->entries[tc_idx];
tcache->entries[tc_idx] = e;
++(tcache->counts[tc_idx]);
}
GLIBC 2.29
이상의 버전에서는 tcache_put()
가 호출되면 e→key에 tcache 포인터를 삽입한다. 이후에 같은 청크를 해제하면 해당 청크의 e→key가 tcache 포인터인지 비교하고 같은 값이면 Double Free 에러 메세지를 출력하고 비정상 종료한다.
이런 방식으로 tcache에 대한 검증을 수행하기 때문에, 검증을 우회하는 작업이 필요하다.
우회 방법은 e→key를 덮는 것이다. e→key를 덮으면 tcache 포인터인지 비교하더라도 false가 나올 것이다.
즉, 똑같은 공간을 free하더라도 검증 로직을 우회하는 동시에 Double Free Bug로 exploit이 가능하다.
reference
dreamhack - [Exploit Tech: Tcache Poisoning]