Libc Protections

ゼロからヒーローまでAWSハッキングを学ぶ htARTE(HackTricks AWS Red Team Expert)

HackTricks をサポートする他の方法:

チャンクアライメントの強制

Malloc はメモリを 8バイト(32ビット)または16バイト(64ビット)のグループ で割り当てます。これは、32ビットシステムのチャンクの末尾は 0x8 に、64ビットシステムのチャンクの末尾は 0x0 に整列する必要があることを意味します。セキュリティ機能は、バイナリからのポインタを使用する前に、各チャンクがこれらの特定の場所に正しく整列しているかどうかをチェックします。

セキュリティの利点

64ビットシステムでのチャンクアライメントの強制は、フェイクチャンクの配置をアドレスの16分の1に制限することでMallocのセキュリティを大幅に向上させます。これにより、攻撃がより複雑になり、特にユーザーが入力値を制御できる余地が限られているシナリオでは、攻撃がより複雑で成功を収めるのが難しくなります。

  • __malloc_hook への Fastbin Attack

Mallocの新しい整列ルールは、__malloc_hook を巧妙に利用した古典的な攻撃を阻止します。以前は、攻撃者がチャンクのサイズを操作してこの関数ポインタを 上書き し、コード実行権限 を取得できました。しかし、厳格な整列要件により、そのような操作がもはや実行不可能となり、一般的な攻撃経路を閉じ、全体的なセキュリティを向上させます。

fastbins および tcache 上のポインタマングリング

ポインタマングリング は、メモリ管理操作で fastbin および tcache Fd ポインタ を保護するために使用されるセキュリティ強化技術です。この技術は、メモリ情報の漏洩が必要ない、または既知の位置に直接メモリ位置を操作する攻撃手法を防ぐのに役立ちます(相対的な 上書き)。

この技術の中心にあるのは、次のような難読化式です:

New_Ptr = (L >> 12) XOR P

  • L はポインタの ストレージ位置 です。

  • P は実際の fastbin/tcache Fd ポインタ です。

ストレージ位置(L)を右に12ビットシフトしてからXOR演算を行う理由は重要です。この操作は、メモリアドレスの最も下位の12ビットが決定論的であるというシステムアーキテクチャの制約によるものです。ビットをシフトすることで、予測可能な部分が方程式から除外され、新しいマングリングされたポインタのランダム性が向上し、これらのビットの予測可能性に依存する攻撃から保護されます。

このマングリングされたポインタは、プログラムが使用するアドレスをランダム化する アドレス空間配置ランダム化(ASLR) によって提供される既存のランダム性を利用します。これにより、攻撃者がプロセスのメモリレイアウトを予測するのが困難になります。

ポインタの デマングリング には、同じXOR演算を使用して元のアドレスを取得する必要があります。ここでは、マングリングされたポインタを式内のPとして扱い、変更されていないストレージ位置(L)とXOR演算を行うと、元のポインタが明らかになります。このマングリングとデマングリングの対称性により、システムはポインタを効率的にエンコードおよびデコードでき、メモリポインタを操作する攻撃に対するセキュリティを大幅に向上させます。

セキュリティの利点

ポインタマングリングは、ヒープ管理における 部分的および完全なポインタの上書きを防ぐ ことを目的としており、セキュリティを大幅に向上させます。この機能は、いくつかの方法で攻撃手法に影響を与えます:

  1. バイトバイト相対上書きの防止: 以前は、攻撃者が正確なアドレスを知らなくても、ヒープチャンクを異なる場所に リダイレクト するためにポインタの一部を変更できました。これは、リークのない House of Roman 攻撃で明らかな技術です。ポインタマングリングにより、そのような相対的な上書きは ヒープリークなしではブルートフォースが必要 となり、成功の可能性が著しく低下します。

  2. Tcache Bin/Fastbin Attacks の難化: fastbin または tcache エントリを操作して関数ポインタ(たとえば __malloc_hook)を上書きする一般的な攻撃が妨げられます。たとえば、攻撃は LibC アドレスをリークし、tcache ビンにチャンクを解放し、その後 Fd ポインタを __malloc_hook にリダイレクトして任意のコードを実行する可能性があります。ポインタマングリングにより、これらのポインタは正しくマングリングされる必要があり、正確な操作のためにヒープリークが必要 となり、攻撃の障壁が高まります。

  3. ヒープ以外の場所でのヒープリークの必要性: ヒープ以外の場所(スタック、.bss セクション、または PLT/GOT など)に偽のチャンクを作成するには、今後は ヒープリークが必要 となります。これにより、これらの領域の悪用の複雑さが拡大し、LibC アドレスを操作する必要があるのと同様になります。

  4. ヒープアドレスのリークがより困難に: ポインタマングリングにより、fastbin および tcache ビン内の Fd ポインタをヒープアドレスのリーク元として使用することが制限されます。ただし、unsorted、small、large ビン内のポインタはマングリングされず、アドレスのリークには引き続き使用できます。この変化により、攻撃者はこれらのビンを探索して悪用可能な情報を探る必要がありますが、一部の技術ではリーク前にポインタをデマングリングすることができる場合もありますが、制約があります。

ヒープリークを使用したポインタのデマングリング

プロセスの詳細な説明については、こちらの元の投稿をチェックしてください

アルゴリズムの概要

ポインタのマングリングとデマングリングに使用される式は次のとおりです:

New_Ptr = (L >> 12) XOR P

ここで、L はストレージ位置、P は Fd ポインタです。L を右に12ビットシフトすることで、XOR の性質により、シフトされた L の部分がゼロになり、P の対応するビットが変更されないため、P の上位12ビットが得られます。

アルゴリズムの主要なステップ:

  1. 最上位ビットの初期リーク: シフトされた LP をXOR演算することで、P の上位12ビットが得られます。なぜなら、L のシフトされた部分はゼロになり、P の対応するビットは変更されないからです。

  2. ポインタビットの回復: XORが逆向きに可能であるため、結果と1つのオペランドを知っていると、他のオペランドを計算できます。この性質を使用して、既知のビットセットとマングリングされたポインタの部分とを繰り返しXOR演算することで、P の全ビットセットを導き出します。

  3. 反復的デマングリング: このプロセスは繰り返され、前のステップから得られた P の新しいビットを使用して、マングリングされたポインタの次のセグメントをデコードします。すべてのビットが回復するまで、このプロセスを繰り返します。

  4. 決定論的ビットの処理: シフトにより L の最後の12ビットが失われますが、これらは決定論的であり、後処理で再構築できます。

このアルゴリズムの実装はこちらで見つけることができます: https://github.com/mdulin2/mangle

ポインターガード

ポインターガードは、glibcで使用されるエクスプロイト緩和技術であり、特にatexit()などのライブラリ呼び出しによって登録された関数ポインターを保護するために使用されます。この保護は、ポインターをスクランブルして、スレッドデータ(fs:0x30)に格納された秘密とXOR演算を行い、ビット単位の回転を適用することを含みます。このメカニズムは、関数ポインターを上書きして制御フローを乗っ取る攻撃者を防ぐことを目的としています。

リークを使用してポインターガードをバイパスする

  1. ポインターガード操作の理解: ポインターのスクランブル(マングリング)は、ポインターを64ビットの秘密とXOR演算し、0x11ビットの左回転を行うPTR_MANGLEマクロを使用して行われます。元のポインターを復元するための逆操作はPTR_DEMANGLEによって処理されます。

  2. 攻撃戦略: この攻撃は既知の平文アプローチに基づいており、攻撃者はポインターの元のバージョンとマングルされたバージョンの両方を知る必要があります。

  3. 既知の平文の悪用:

  • 固定関数ポインターの特定: glibcのソースコードを調査するか、__libc_pthread_functionsのような初期化された関数ポインターテーブルを調べることで、攻撃者は予測可能な関数ポインターを見つけることができます。

  • 秘密の計算: __pthread_attr_destroyなどの既知の関数ポインターとその関数ポインターテーブルからのマングルされたバージョンを使用して、秘密を計算することができます。これは、マングルされたポインターを逆回転(右回転)してから、その関数のアドレスとXOR演算することで行われます。

  1. 代替平文: 攻撃者は、0や-1などの既知の値でポインターをスクランブルして、これらがメモリダンプで見つかった場合に秘密を明らかにする可能性がある識別可能なパターンを生成するかどうかを実験することもできます。

  2. 実用的な応用: 秘密を計算した後、攻撃者は制御された方法でポインターを操作することができ、libcベースアドレスの知識と任意のメモリ位置を読む能力を持つことで、マルチスレッドアプリケーションでのポインターガード保護をバイパスすることができます。

参考文献

Last updated