ハッカーが学ぶ、GOT/PLTハイジャック入門(動的リンクテーブルを書き換えて何が起きるか)
プログラムが外部のライブラリ関数(例 printf、malloc)を呼ぶとき、実際の関数のアドレスはプログラム起動直後に全て決まっているとは限りません。
LinuxのELF形式では「遅延バインディング」という仕組みを使い、呼び出し時に実際のアドレスを見つけて保存します。このしくみを支えるのが PLT(Procedure Linkage Table)と、GOT(Global Offset Table)です。便利な仕組みですが、もしプログラムのメモリ(GOT)を書き換えられると、以降の関数呼び出しを別の場所へ誘導されてしまう可能性があります。
※イメージです。
GOT/PLTとは
・GOT(Global Offset Table)
動的リンクされた関数の「実際のアドレス」を格納するテーブル。(データ領域)
・PLT(Procedure Linkage Table)
関数呼び出し時に最初にジャンプする「中継コード」。GOTを参照して実アドレスへ飛ぶ役割を持つ。
プログラムが外部ライブラリの関数を実行するとき、まずPLTで処理を仲介し、解決されたアドレスをGOTに保存して次回以降は高速に呼び出すための仕組みです。
GOT/PLTの背景
動的リンク(shared libraries)はプログラムサイズ削減・ライブラリ再利用・アップデートの容易さをもたらします。全てを実行時に解決するより、必要になったときだけ解決する「遅延バインディング」は性能面の利点があります。しかし「実行時に書き換えられるデータ領域(GOT)」が存在するため、もしそのデータ領域へ任意の書き込みができる脆弱性(バッファオーバーフローや任意書き込み)があると、関数呼び出しの向き先を変えられてしまうリスクが生まれます。つまり、機能的に便利な設計と、安全性のトレードオフが背景にあります。
※遅延バインディングとは
初回の呼び出しのみ動的リンカ(ld-linux)が割り込みアドレスを解決してGOTに書き、2回目以降はGOTの値へ直接ジャンプする ― これを「lazy binding」と言います。
GOT/PLTが引き起こす影響について
攻撃者視点の影響
・GOTエントリを書き換えることで、ある関数呼び出しを別の関数に置き換えられる。
・ログに痕跡を残さない巧妙な挙動変更が可能。検出が難しい場合がある。
・情報漏えいや任意の処理呼び出しにつなげられる可能性がある。
防御者視点の影響
・静的シグネチャ検出が効きにくい。メモリの一部を書き換えるだけで挙動が変わるため、検査が難しい。・ただし、ASLR・RELRO・PIEなどの組み合わせで攻撃の難易度は大きく上がる。防御設計次第で十分にリスクを低減できる。
GOT/PLTの動作イメージ
分かりにくいので、はじめてのピザの注文のイメージで説明します。
(前提)
・プログラムは、家にいる貴方
・ライブラリ関数(printf等)は、配達先のサービス(ピザ屋)
・PLT(呼び出しの中継)は、家の玄関の受話器
・GOT(玄関の住所メモ)は、玄関に貼られた「ピザ屋連絡先」
動作イメージ
1.初めてピザを頼むとき、玄関の受話器(PLT)を利用して「ピザ屋連絡先」を電話番号案内に問い合わせる。
2.電話番号案内が住所を教えると、それを玄関の住所メモ(GOT)に書き込む。
3.ピザを注文します。
4.次回からは、玄関の住所メモ(GOT)を見て直接配達先へつなぐ。(速い)
※危険点(なぜ書き換えで乗っ取れるか)
玄関の住所メモ(GOT)は普通の紙なので、もし誰かがその紙をすり替えられたら、配達は別の場所へ行ってしまう。これがGOT書き換えの本質になります。
ハッカーが学ぶ、GOT/PLTハイジャック入門(動的リンクテーブルを書き換えて何が起きるか)のまとめ
GOT/PLTハイジャックは、動的リンクが提供する「遅延バインディング」の仕組みを利用した攻撃概念で、GOT(実行時に書き込まれるアドレステーブル)を書き換えられると関数呼び出しを別の処理へ誘導される可能性があります。
設計段階から「書き換え可能な重要データは最小化する」という考え方を持つことが、最も根本的な防御になります。