fastbin poisioning & dup

새로운 공격기법에 대해 공부해서 기쁘다.

바로 기존에 계속하던 tcache 공격이 아닌 fastbin 공격이다

일단 기본적인 형식은 비슷하다.

해당 기존 정리글을 읽으면 알 수 있겠지만, fd 하나만 사용하는 단일 연결 리스트 방식이라는 점과 LIFO 이라는 점이 tcache와 상당히 유사하다. 하지만, 당연히 구조적으로 다른데

일단 첫번째로, 가리키는 대상이 다르다. tcache는 next 필드는 다음 free chunk의 next 필드 주소를 가리킨다. 즉, 헤더 ( prev_size , size 필드 ) 가 끝난 곳을 가리킨다.

반면에 fastbin에서는 fd가 다음 free chunk의 시작 부분 ( prev_size 필드에 시작부분 )을 가리킨다. 그 이유라고 하면 기본적은 fastbin은 헤더에 대해서 기본적인 검사를 사용하기 때문인데 바로 아래에서 다루겠다.

두번째로, size에 대한 검사 및 무결성 검사 수행이다.

2.32에 추가된 safe-linking 바로 이전 버전인 2.31 부터 fd에 있는 다음 청크에 대해서 정말 요구하고 있는 size가 맞나? 라는 검증와 더블어 추가적인 검증들이 추가되었다.

바로 코드를 한번 봐보자면

C

static void *
_int_malloc (mstate av, size_t bytes)
{
  INTERNAL_SIZE_T nb;               /* normalized request size */
  unsigned int idx;                 /* associated bin index */
  mbinptr bin;                      /* associated bin */

  mchunkptr victim;                 /* inspected/selected chunk */
  INTERNAL_SIZE_T size;             /* its size */
  int victim_index;                 /* its bin index */

... 중략

  if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ()))
    {
      idx = fastbin_index (nb);
      mfastbinptr *fb = &fastbin (av, idx);
      mchunkptr pp;
      victim = *fb;

      if (victim != NULL)
	{
	  if (__glibc_unlikely (misaligned_chunk (victim)))
	    malloc_printerr ("malloc(): unaligned fastbin chunk detected 2");

	  if (SINGLE_THREAD_P)
	    *fb = REVEAL_PTR (victim->fd);
	  else
	    REMOVE_FB (fb, pp, victim);
	  if (__glibc_likely (victim != NULL))
	    {
	      size_t victim_idx = fastbin_index (chunksize (victim));
	      if (__builtin_expect (victim_idx != idx, 0))
		malloc_printerr ("malloc(): memory corruption (fast)");

다음이 fastbin과 관련된 malloc 부분인데

C
   idx = fastbin_index (nb);
      mfastbinptr *fb = &fastbin (av, idx);
      mchunkptr pp;
      victim = *fb;

요구한 nb에 대해 어떤 인덱스를 사용하는지 ( 0x10 , 0x20 .. 와 크기와 관련된 인덱스 ) 가져오고

fastbin에서 victim을 가져온다.

C
	  if (__glibc_unlikely (misaligned_chunk (victim)))
	    malloc_printerr ("malloc(): unaligned fastbin chunk detected 2");

그리고 일단 먼저 victim의 주소가 정렬되어 있는지 검증을 한다. x64 → 0x10 , x86 → 0x8 정렬

C
    size_t victim_idx = fastbin_index (chunksize (victim));
	      if (__builtin_expect (victim_idx != idx, 0))
		malloc_printerr ("malloc(): memory corruption (fast)");
	      check_remalloced_chunk (av, victim, nb);

그리고 이제 chunksize (victim) 으로 victim 청크의 size 필드의 값을 가져온뒤 해당 size과 malloc에서 요청한 size와 같은 인덱스에 있는지 확인한다. 만약 다르다면 malloc(): memory corruption (fast) error 을 뛰우는 것

이러한 검증이 있기에 fd에 사용되는 주소에서 size 필드를 맞춰야할 필요성이 있다.

그리고 fastbin dup에 대해서는 tcache 처럼 키가 존재하지 않기에

how2heap 링크임

다음 깃허브를 보면서 무슨 느낌인지 알면 될것 같다.