今回の実験で利用するターゲットには,第6回で述べたようにスタック・ベースのバッファ・オーバーフロー脆弱性が存在します。まずは,バッファ・オーバーフロー脆弱性について簡単に解説します。
バッファ・オーバーフローとは,メモリー領域に書き込みをおこなう際,確保されたサイズ以上のデータが書き込まれてしまう現象のことです。C/C++言語で作成したコードに発生しやすいバグの一種です。以下,典型的なバッファ・オーバーフロー・バグの例を示します。
main()
{
char buf[4];
memset(buf,'A',256);
}
ローカル・バッファとして確保された4バイトの領域bufに対し,memset()を使って256バイトのデータをセットしています。その結果,スタック上でバッファ・オーバーフローが発生します。
スタックには,引数やローカル・バッファ,親関数への戻りアドレスなどが格納されています。このため,スタックに確保されているローカル・バッファでオーバーフローが発生すると,この親関数への戻りアドレスが書き換わる可能性があります。
そうなると,関数の処理を終了して親関数に戻る際,適切なアドレスに戻れず新たに書き換わったアドレスにジャンプしてしまいます。この仕組みを利用することで,攻撃者は自身が用意したコード(shellコード)を実行させることができます。
![]() 図9. バッファ・オーバーフロー脆弱性 [画像のクリックで拡大表示] |
C言語では,バッファにデータをセットする際,そのバッファの境界チェックをするのはプログラマの役目となります。この境界チェックが適切におこなわれていないとバッファ・オーバーフローが発生し,場合によっては深刻な脆弱性となります。
例えば,ネットワークから文字列パケットを受け取って処理する際,境界チェックをおこなわずにstrcpy()などで受信文字列をローカル・バッファにコピーしたりすると,ほとんどの場合,深刻なバッファ・オーバーフロー脆弱性となります。
バッファ・オーバーフロー脆弱性の確認
今回の実験のターゲットは,Webサーバーの実装にバッファ・オーバーフロー脆弱性が存在します。ある個所に長い文字列を指定して送信すると,ターゲットはバッファ・オーバーフロー状態となります。単純なスタック・ベースのバッファ・オーバーフローの場合,その性質上,指定された文字列データの値がそのまま関数からの戻りアドレスとして解釈されます。
![]() 図10. バッファ・オーバーフロー脆弱性の確認 [画像のクリックで拡大表示] |
例えば,0x04,0x04,0x04,0x04……といった長い文字列を送信すると,関数から復帰する際,インストラクション・ポインタの値が0x04040404となります。このため,単純なスタック・ベースのバッファ・オーバーフローの場合,アドレス0x04040404にあらかじめブレーク・ポイントを設定しておけば,その脆弱性を確認できます。(第8回へ続く)
「Security Tech」は,米eEye Digital SecurityのSenior Software Engineerである鵜飼裕司氏による技術コラムです。鵜飼氏はMicrosoft製品のセキュリティ脆弱性(セキュリティ・ホール)を多数発見していることでも知られるセキュリティの専門家です。
本コラムでは,あるテーマについて数回にわたって技術解説記事を執筆していただきます。1回目のテーマは,「組み込みシステムのセキュリティ」。全8回にわたって,組み込みシステムにおけるセキュリティ脆弱性の脅威の実際と,開発サイドに求められる組み込み機器独特の防衛策について解説していただきます。 なお,鵜飼氏には「ITpro Watcher」も執筆していただいております。こちらのほうも,併せてお読みいただければ幸いです。(編集部より) |