こんにちは!セキュリティの世界へようこそ。
日々の開発やインフラの管理、本当にお疲れ様です。「セキュリティって何から勉強すればいいんだろう…」「専門用語が難しすぎて挫折しそう…」そんな風に悩んでいませんか?
今回は、サイバー攻撃の世界で使われる「GOT(Global Offset Table)オーバーライト」というテクニックについて、身近な例えを交えながら、一歩ずつ優しく紐解いていきたいと思います。
難しそうな名前をしていますが、仕組みが分かると「お家の防犯」とまったく同じなんだな、とスッキリ納得できるはずです。一緒に楽しく学んでいきましょうね!
—
1. 身近な例えでイメージしよう:プログラムの「住所録」の仕組み
まずは、プログラムが外部の便利な機能(ライブラリ)を使う仕組みを、私たちの生活に例えて考えてみましょう。
皆さんがお家にいて、「水道の調子が悪いな」「鍵が壊れちゃったな」と思ったとき、どうしますか? 自分ですべて直すのは大変なので、水道屋さんや鍵屋さんといった「専門のプロ(外部のサービス)」を呼びますよね。
プログラムもこれと同じです。画面に文字を表示したり、ファイルを保存したりするとき、毎回ゼロからその仕組みを作るのは大変なので、OSがあらかじめ用意してくれている便利な「共通の関数(お助けマン)」を呼び出します。
連絡先をメモした「アドレス帳(GOT)」
プログラムの中には、その「お助けマン」がどこにいるのか(電話番号や住所)をメモした、小さなお手製のアドレス帳があります。これが、今回主役になるGOT(Global Offset Table)です。
プログラムは、誰かを呼びたいときにまずこのGOTを見て、「あ、水道屋さんは内線3番ね」と確認してから連絡を取ります。
—
2. 攻撃者はどこを狙う?「住所のすり替え」という手口
ここで、もしも悪意を持った泥棒(攻撃者)が家に忍び込み、こっそり電話帳のメモを書き換えてしまったらどうなるでしょうか?
- 本当のメモ: 内線3番 = 丁寧で頼りになる「水道屋さん」
- 書き換えられたメモ: 内線3番 = 泥棒の仲間である「怪しい業者」
プログラム自身は、「いつも通り内線3番にかけたんだから、水道屋さんが来てくれるはず!」と信じ込んでいます。しかし、電話に出たのは怪しい業者です。結果として、プログラムの大切な鍵を開けて家の中をめちゃくちゃにされてしまいますよね。
これが、「GOTオーバーライト(書き換え)」という攻撃の正体です。
プログラムが信頼しきっている「アドレス帳(GOT)」のなかにある、関数のアドレス(連絡先)をこっそり悪意あるコードのアドレスに書き換えることで、プログラムの主導権を奪い取るという高度なテクニックなんです。
—
3. 実際にコードを見てみよう:脆弱なC言語のプログラム
では、もう少し技術的な側面も覗いてみましょう。といっても、難しいことはありません。新人の開発者の方でも「あ、こういうコードが危ないんだな」とイメージできるように、簡単なC言語のサンプルを用意しました。
以下のコードを見てください。
#include <stdio.h>
#include <string.h>
// 脆弱なデータ処理を行う関数
void vulnerable_function(char *input) {
char buffer[64]; // 64バイトの小さな箱(バッファ)
// 【危険なポイント】入力データの長さを確認せずにコピーしてしまっています!
// もし64バイトより長いデータを渡されると、箱からあふれて隣のメモリー領域まで壊してしまいます。
strcpy(buffer, input);
}
int main(int argc, char **argv) {
if (argc > 1) {
vulnerable_function(argv[1]);
}
printf("プログラムが正常に終了しました。\n");
return 0;
}
上記のコードには、「バッファオーバーフロー」と呼ばれる有名な脆弱性が潜んでいます。
strcpyという関数は、「箱に入り切るかどうか」を確認せずにデータを詰め込んでしまうため、あふれたデータがメモリの別の場所(今回であればアドレス帳であるGOTの周辺)を破壊し、書き換えてしまう原因になるのです。
—
4. どうやって身を守るの?現代の強力な防犯システム
「えっ、プログラムってそんなに簡単に書き換えられちゃうの?怖すぎる…」と思いましたか? ご安心ください! 現代のオペレーティングシステム(LinuxやWindowsなど)やコンパイラ(プログラムを翻訳するツール)には、強力な防犯システム(セキュリティ機構)が標準で備わっています。
新人エンジニアの皆さんが、インフラの構築や開発を行う際にぜひ知っておいてほしい「2つの強力な盾」をご紹介します。
① RELRO(Read-Only Relocation)
先ほど、GOTは「アドレス帳(連絡先メモ)」だとお話ししました。このGOT、実は普段はプログラムが起動した瞬間に一度だけ書き込まれたら、あとは二度と内容が変わる必要のないものなんです。
それなら、「最初に書き込んだら、あとはペンのインクを乾かして二度と書き換えられない(読み取り専用)ようにしちゃえばいいじゃない!」という発想で作られたのがRELRO(特にFull RELRO)という機能です。
これをしておけば、たとえ攻撃者がメモリをハチャメチャに壊そうとしても、「ここから先は書き込み禁止です!」とOSがガッチリガードしてくれます。
② ASLR(Address Space Layout Randomization)
もう一つの防犯対策がASLRです。これは、プログラムを起動するたびに、お助けマンやアドレス帳の「配置場所(住所)をランダムに変えてしまう」という仕組みです。
泥棒が家に入ってきても、毎回「リビングのどこに電話帳があるか」がランダムに変わっていたら、どこを書き換えればいいか分からずパニックになってしまいますよね。これによって、攻撃の成功率を劇的に下げることができます。
—
5. 現場で私たちができること:安全な開発の第一歩
最後に、日々の開発やインフラ管理で私たちが実践すべきポイントをまとめます。
1. 安全な関数を使う癖をつける
- 長さのチェックをしない危険な関数(
strcpyやsprintfなど)の利用を避け、サイズを指定できる安全な関数(strncpyやsnprintfなど)を使いましょう。
2. コンパイラのオプションを味方につける
- プログラムをビルドする際は、スタック保護(
-fstack-protector)や、RELRO、ASLRなどのセキュリティ機構が有効になっているかを必ず確認・設定しましょう。現代のビルドツールやCI/CDパイプラインでは、これらを標準で有効にするテンプレートが用意されていることが多いです。
セキュリティの対策は、一度にすべてを完璧にする必要はありません。「危ない書き方をしない」「標準の防犯機能をしっかりと有効にする」という小さな積み重ねが、あなたの大切なシステムとデータを守る最強の盾になります。
一歩ずつ、確実に知識をアップデートしていきましょうね。応援しています!
コメント