본문 바로가기

system/material

glibc 2.26 tcache 동작 분석 및 exploit (how2heap)

tcache

이번에 코드게이트 준비하다가 우연히 tcache dup 문제를 풀게 됐는데 한글 문서가 별로 없는것 같아서 glibc 분석 내용을 정리한다.

 

tcache(thread local caching)은 malloc과 free의 호출 횟수를 줄여 속도를 높이기 위해 고안되었다고 한다. 캐싱 작업을 통해 fastbin, unsortedbin 등등..이 불릴 일 없이 빠르게 처리하는 것 같다..


  • tcache 구조체

tcache_entry 구조체는 tcache list를 관리하는 구조체이다. 오직 다음 tcache_chunk를 가르키는 포인터만을 가지고 있다.

 

tcache_perthread_struct 구조체는 tcache list를 총체적으로 관리하는 구조체이다. 배열로서 해당 tcache list의 count와 entries를 관리 한다.

 

tcache는 consolidate를 하지 않으며 때문에 prev_size와 inuse_bit도 셋팅하지 않는다.

tcache_chunk는 size와 next만 존재한다고 생각하면 된다.

 

발로 그려서 보기 힘들 수도 있지만 위 그림을 참고하면 된다.


  • tcache 초기화

tcache_perthread_struct를 처음에 할당해 준다.

 

  • tcache 삽입

tcache list에 chunk를 추가하는 함수이다.

들어온 chunk의 next에 이미 존재하는 tcache chunk를 넣은 후 그 자리에 들어온 chunk를 넣는다.

 

  • tcache 제거

tcache list에서 chunk를 가져오는 함수이다.

tc_idx를 기준으로 next 청크를 현재 tc_idx로 넣고 요청한 chunk를 반환한다.

 

  • tcache_put이 불리는 상황

    • free: _int_free()에서 fastbin 코드가 실행되기 전 size와 count 검사를 통해 해당된다면 ( 유효한 주소인지, 유효한 사이즈인지에 대한 검사밖에 존재하지 않는다.. )

 

  • malloc: fastbin이 return될 때 fastbin 내에 다른 chunk가 존재하고 tcache list가 비어 있을 때 fastbin의 chunk가 tcache list로 이동한다.
  • malloc: smallbin도 동일하게 작동한다.

 

  • malloc: unsortedbin도 동일하게 작동한다. 하지만 unsortedbin은 return_cached를 1로 셋팅한다. 이 의미는 tcache_get에서 확인할 수 있다.

 

  • tcache_get이 불리는 상황

    • _libc_malloc()에서 tc_idx 기준으로 tcache_list가 존재한다면 ( 보호 예외처리가 하나도 없다.. fake_chunk_size 만들 필요도 없을듯 )

 

  • return_cached=1이며 tcache_unsorted_limit를 넘지 않는다면, 즉 unsortedbin에서 tcache list로 이동한 경우, tcache list의 top chunk를 가져오겠다는 말이다. unsortedbin 외 bin은 LIFO로 chunk를 가져온다.

 

  • binning code 이후에 return_cached=1이라면

 

 

tcache 동작을 확인하기 위해 아래의 코드를 사용하였다.

tcache_init()으로 생성된 첫 번째 chunk를 확인해 보면 count와 entries가 저장되어 있는 것을 볼 수 있다.

 

위와 같이 entries에 tcache_entry들이 single linked-list 형태로 저장되어 있다.

 

위와 같은 tcache chunk의 형태를 확인할 수 있다.

 

tcache list를 모두 malloc한 후 fastbin에만 chunk가 남아 있는 상황이다.

 

이 상태에서 malloc을 하게 되면 7개의 chunk가 tcache list로 이동하는 것을 확인할 수 있다.

 

return_cached의 동작을 확인하기 위해 아래의 코드를 사용하였다.

위와 같이 unsortedbin에 bin chain이 구성되어 있는 상황에서 malloc(0x200)을 한다면 원래라면 unsortedbin에서 주소를 가져와야 한다. 일단 위 unsortedbin의 주소를 잘 기억해 두고..

 

성공적으로 malloc 후 chunk들이 tcache list로 넘어왔다. 어떤 주소가 할당됐는지 확인해 보자.

 

위 주소는 tcache list의 topchunk의 다음 주소이다. 원래라면 unsortedbin은 FIFO기 때문에 0x55555757B30 + 0x10이 RAX에 있어야 할터..

이유는 tcache list에 옮겨 둔 후 return_cached의 값이 1로 셋팅되고 tcache list에서 top chunk를 빼왔기 때문이다. ( 근데도 tcache list가 7개인 것은 for문을 돌아 다시 채웠기 때문인 것 같다. 확실하지 않음)

 

동일하게 주석을 지운 후 smallbin에서 실험해 보자.

return_cached를 셋팅하지 않기 때문에 0x555555757b50 + 0x10이 반환되야 할터

 

tcache list에 잘 들어 갔고..

 

예상과 동일하게 RAX에 0x555555757b50 + 0x10이 반환되었다.

 

  • fastbin과 다른 점?

fastbin하고 겁나 비슷하네.. fastbin은 prev_size 위치를 가르키고 있으며 tcache는 data(next) 위치를 가르키고 있다. 또한 fastbin은 main arena가 관리하지만 tcache는 tcache_perthread_struct가 관리한다.

 

  • tcache dup

기존 malloc은 fastbin에서 free시 top chunk를 검사하지만 tcache malloc은 보호가 하나도 없기 때문에 바로 double free bug를 일으켜 동일한 주소를 계속해서 할당받을 수 있다.

 

위와 같은 상황에서 malloc을 한다면 동일한 주소를 2번 할당받을 수 있다.

 

동일한 주소가 2번 할당되었다!

 

  • tcache poisoning

tcache chunk의 next를 원하는 주소로 바꿔 공격하는 기법이다. ( 이 상황에서는 스택 주소를 알아야 공격 가능 ) fastbin dup into stack같이 tcache dup이랑 같이 사용하면 될듯

 

스택 주소가 할당되었다!

 

  • tcache house of spirit

tcache의 free는 invalid pointer, invalid size 검사만이 존재하기 때문에 next chunk size를 설정해줄 필요가 없다는게 특징이다.

임의의 영역에 fake chunk를 만든 뒤 데이터 영역의 주소를 free시키면 다음에 그 주소를 할당받을 수 있다.

 

위와 같은 fake chunk를 free 시키면

 

tcache list에 주소가 추가되어 다음 malloc(0x30)때 위 주소를 할당받게 된다.

 

짜잔~

 

  • 결론

tcache malloc, free에 보호기법이 상당히 부족하다는 점과 fastbin보다 tcache를 먼저 참조하는 점을 감안하면 glibc 2.26 이상의 exploit에서 상당히 효율적일 듯. 위 기법들을 적절히 섞어서 exploit에 낭낭히 사용하면 될 것 같다.

 

  • 참조

https://dangokyo.me/2018/01/16/extra-heap-exploitation-tcache-and-potential-exploitation/

http://tukan.farm/2017/07/08/tcache/

http://m4x.fun/post/dive-into-tcache/

http://eternal.red/2018/children_tcache-writeup-and-tcache-overview/

https://github.com/shellphish/how2heap


'system > material' 카테고리의 다른 글

c++ std::string  (0) 2019.01.22
fastbin dup consolidate 정리  (0) 2019.01.22
x86, x64 srop 정리  (0) 2019.01.21
got_overwrite stack_smashing_detected  (0) 2019.01.12
unsorted bin free 동작..  (0) 2018.12.26