情報機器、プログラム及び不正なプログラムコードの実行防止方法
【課題】CPUが所有する機能に依存せずバッファオーバーフローに関する不正アクセスを確実且つ容易に防止する。
【解決手段】情報機器1は、メモリに展開された各プログラムコードと中央制御部との協働によりデータ処理を行い、フック処理によって、プログラムコードの呼び出し時を検出し、スタックレイアウトチェック処理によって、RAM30に展開された各プログラムコードのリターンアドレスを順次取得して、この取得されたリターンアドレスが示す先のアドレスに基づいて不正アクセスを検出し、不正アクセスが検出された場合にはデータ処理を停止させる。
【解決手段】情報機器1は、メモリに展開された各プログラムコードと中央制御部との協働によりデータ処理を行い、フック処理によって、プログラムコードの呼び出し時を検出し、スタックレイアウトチェック処理によって、RAM30に展開された各プログラムコードのリターンアドレスを順次取得して、この取得されたリターンアドレスが示す先のアドレスに基づいて不正アクセスを検出し、不正アクセスが検出された場合にはデータ処理を停止させる。
【発明の詳細な説明】
【技術分野】
【0001】
本発明は、情報機器、プログラム及び不正なプログラムコードの実行防止方法に関する。
【背景技術】
【0002】
一般的に、PC(Personal Computer)やWS(Work Station)等の情報機器では、CPU(Central Processing Unit)などの制御部がRAM(Random Access Memory)等の記憶部の作業領域に展開されたプログラムコードを順次実行することで、各種データ処理を実行している。近年、悪意のあるユーザによって作成されたプログラムコードによる不正な処理によって、情報機器に対する不正アクセスが発生している。
【0003】
通常、情報機器が管理するデータにはアクセス権限が設定されている。従って、データへのアクセス権限がなければ、不正アクセスが行われることはない。しかしながら、データへのアクセス権限がある通常のプログラムコードを利用し、不正な操作が実行された場合は、不正アクセスが可能となる。このような手法としては、プログラムコードの実行時のデータをRAM等に確保された所定領域からオーバーフローさせる、いわゆるバッファオーバーフローを用いた手法が知られている。
【0004】
ここで、バッファオーバーフローを用いた不正アクセスについて、正常にプログラムコードが実行された場合と、プログラムコードの実行時に不正が行われた場合と、を比較して詳細に説明する。
【0005】
先ず、図9、図10を参照して正常にプログラムコードが実行された場合を説明する。
図9に、プログラムコードのソースコードを例示する概念図を示す。図9に示すプログラムコードは、main()関数から開始され、main()関数の中でstrcpy_helloworld()関数を呼び出している。このプログラムコードでは、strcpy_helloworld()関数の中で「Hello!」という文字列を用意し、main()関数のprintf()関数でこの文字列をモニタ等に表示させている。なお、関数とは、所定の機能をモジュール化してまとめたサブルーチンやサブプログラムなどであり、メインとなるプログラム内で随時呼び出すことができる。
【0006】
図9に示すプログラムコードの実行時のデータは、RAM等に確保されたスタック領域に格納される。このスタック領域では、後入れ先出し (LIFO: Last In First Out; FILO: First In Last Out) 構造でデータが格納される。
【0007】
図10に、プログラムコード実行時におけるスタック領域の概要を例示する概念図を示す。図10に示すように、上から下に向かって順次確保された領域へプログラムコードの実行時のデータが格納される。
【0008】
例えば、図9に例示したソースコードによるプログラムコードの実行時には、main()関数を処理した際に、ReturnAddress1、ebp backup、char buf[8]などが1つのスタックフレームとして格納される。次いで、main()関数の中でstrcpy_helloworld()関数が呼び出された際に、ReturnAddress2、ebp backup2、int i等が一つのスタックフレームとして格納される。
【0009】
ReturnAddress(リターンアドレス)は、プログラムの終了時に戻るべきアドレス値や、関数などによりサブプログラムが呼び出された場合の当該サブプログラム終了時に戻るべきアドレス値を示す。このReturnAddressは、プログラムの実行直後や関数などによりサブプログラムが呼び出された直後に、CPUにより自動的にスタック領域へ格納される。
【0010】
ebpは、CPUのレジスタの一種であり、現在使用している一時的なメモリ領域のアドレスの直前を示す。図10の例では、char buf[8]、int iの前のアドレスであり、スタックフレームのReturnAddressが該当する。従って、スタックフレームにおいて、上記レジスタ値をebp backupとしてバックアップすることで、このスタックフレーム内の一領域を一時的なデータ(変数や配列等)を格納するメモリ領域として簡単に使用することが可能となる。
【0011】
char buf[8]は、main()関数で使用される配列であるbufを格納する。このbufは、char型の変数(1バイト)を8個格納する配列であり、8バイト分のデータが格納可能となっている。int iは、strcpy_helloworld()関数で使用されるint型の変数であるiを格納する。
【0012】
従って、上記プログラムコードの実行により、スタック領域では、main()関数のスタックフレームが確保され、strcpy_helloworld()関数のスタックフレームが確保される。次いで、int iの値が順次インクリメントされて、「Hello!」という6バイト分の文字列がchar buf[8]に格納される。次いで、strcpy_helloworld()関数の終了により、ReturnAddress2が読み出されてmain()関数へ復帰され、main()関数の終了により、ReturnAddress1が読み出されてプログラムは正常終了する。
【0013】
次に、図11、図12を参照してプログラムコードの実行時に不正が行われた場合を説明する。
【0014】
図11に、プログラムコードのソースコードを例示する概念図を示す。図11に示すプログラムコードは、配列bufへ「Hello World」という12バイト分(11文字+文字列終端)のデータを書き込む点において、図9に示すプログラムコードと異なる。
【0015】
図12に、プログラムコード実行時におけるスタック領域の概要を例示する概念図を示す。図12に示すように、スタック領域では、配列bufを格納する領域として8バイト分の領域が確保されている。従って、strcpy_helloworld()関数が実行された際には、確保されているサイズ以上のデータが書き込まれる。このように、メモリに確保されているサイズ以上のデータが書き込まれるとバッファオーバーフローが発生する。なお、このバッファオーバーフローがスタック領域で起きる場合をスタックベースのバッファオーバーフローという。
【0016】
図12に示したスタック領域おいて、領域の確保は上から下に向かって順次行われ、その確保された領域へのデータの書き込みは下から上に向かって行われる。従って、ReturnAddress1、ebp backupはstrcpy_helloworld()関数が実行された際に、「Hello World」という12バイト分のデータにより不正に上書き(overwrite)される。上述した上書きにより、ReturnAddress1の内容が実行可能なプログラムコードが置いてあるアドレスに書き換えられた場合は、main()関数の終了によりReturnAddress1が読み出され、その書き換えられたプログラムコードが実行される。
【0017】
図11に示したソースコードでは、「Hello World」という予め定義された文字列によりオーバーフローとなっている。しかしながら、実際には、メールサーバやWebサーバ等の通信ポートで受信されたデータや、コンソールやファイルから入力されたデータなどが配列bufに格納される場合もある。このような場合は、悪意のあるユーザにより通信、コンソール入力、ファイル入力などを介して任意のプログラムコードが実行され、データの盗みだしや改竄などの不正アクセスが発生する。
【0018】
これらの不正アクセスを検出する方法として、スタック領域に格納されているリターンアドレスを検査し、正常なプログラム実行時と攻撃コード動作時のリターンアドレスの配置パターンの違いを比べることによって不正アクセスが実行されるか否かを検出する方法が考えられる。例えば、リターンアドレスが示す先のメモリ属性が、プログラムコードを配置するためのメモリ領域を支援している場合又はこのメモリ領域が書き込み不可能な属性にある場合は正常なプログラムと判断する等である。
【0019】
しかし、このような不正アクセスの検出方法では、Return-to-libc攻撃(非特許文献1参照)を検出できない可能性がある。Return-to-libc攻撃とは、悪意のあるコードをプログラムコードに書き加えることなく、コンピュータに既に記憶されている関数を呼び出すことによって不正アクセスを行う攻撃手法である。
【0020】
図13に、図11に示すプログラムコード実行時においてReturn-to-libc攻撃された際のスタック領域の概要を例示する概念図を示す。図13に示すように、Return-to-libc攻撃では、上記説明したリターンアドレスが示す値が、OS(Operating System)の標準関数等の正常な関数の先頭アドレスに設定される。スタック領域上のリターンアドレスが、プログラムコードを置くためのメモリ領域を示していたり、このメモリ領域が書き込み不可能な属性にあったりした場合には、正常なプログラムと区別がつかない可能性がある。
【0021】
このReturn-to-libc攻撃を応用し、既に情報機器の記憶部に記憶されているプログラムのプログラムコードを組み合わせることによって所定のプログラムコードを実行する攻撃が考えられる。この攻撃方法においても、スタック領域上のリターンアドレスはReturn-to-libc攻撃と同様の特徴があるため、正常なプログラムと区別がつかない可能性がある。
【0022】
特許文献1には、CPUの機能の一つであるブランチトレースを使用し、実行中の関数から呼び出し元の関数の処理に戻る際に、OSの標準関数の先頭アドレスに戻るという動きを検出することによってReturn-to-libc攻撃を検出する技術が開示されている。
【先行技術文献】
【特許文献】
【0023】
【特許文献1】米国特許第10/763,867号明細書
【非特許文献】
【0024】
【非特許文献1】”Return-to-libc attack”、[online]、ウィキメディア財団、[2009年3月23日検索]、インターネット、(URL:http://en.wikipedia.org/wiki/Return-to-libc_attack)
【発明の概要】
【発明が解決しようとする課題】
【0025】
しかしながら、特許文献1に記載の技術では、Return-to-libc攻撃をブランチトレースという機能を使用して検出することはできるが、CPUが所有する機能を使用しているため、CPUの処理負荷の増大、ブランチトレース機能を使用する他のアプリケーション(パフォーマンス計測ツール等)の使用の制限等が発生する可能性がある。つまり、Return-to-libc攻撃を検出するための処理が実行されている間は、コンピュータの処理負荷が増大し、ユーザビリティの低下を招く可能性がある。
【0026】
本発明の課題は、上記従来技術の問題に鑑みてなされたものであり、CPUが所有する機能に依存せずバッファオーバーフローに関する不正アクセスを確実且つ容易に防止する技術を提供することである。
【課題を解決するための手段】
【0027】
上記課題を解決するために、請求項1に記載の発明は、
メモリに展開された各プログラムコードと中央制御部との協働によりデータ処理を行う情報機器であって、
前記いずれかのプログラムコードの呼び出し時を検出する検出手段と、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記メモリに展開された各プログラムコードのリターンアドレスを順次取得するリターンアドレス取得手段と、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記リターンアドレス取得手段により順次取得されたリターンアドレスが示す先のアドレスに基づいて不正アクセスを検出し、当該不正アクセスが検出された場合には前記データ処理を停止させる停止手段と、
を備える。
【0028】
請求項2に記載の発明は、請求項1に記載の発明において、
前記メモリは、各プログラムコードのリターンアドレスを格納するスタック領域を備え、
前記リターンアドレス取得手段は、前記スタック領域に格納されたリターンアドレスをトレースして取得する。
【0029】
請求項3に記載の発明は、請求項1又は2に記載の発明において、
前記停止手段は、前記属性取得手段により取得された各リターンアドレスが示す先のアドレスが関数の開始アドレスである場合に不正アクセスを検出し、当該不正アクセスが検出された場合には、前記データ処理を停止させる。
【0030】
請求項4に記載の発明は、請求項1〜3の何れか一項に記載の発明において、
前記停止手段は、前記属性取得手段により取得された各リターンアドレスが示す先のアドレスに対応する一つ前の命令がコール命令ではない場合に不正アクセスを検出し、当該不正アクセスが検出された場合には、前記データ処理を停止させる。
【0031】
請求項5に記載の発明は、
メモリに展開された各プログラムコードを実行するコンピュータを、
前記いずれかのプログラムコードの呼び出し時を検出する検出手段、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記メモリに展開された各プログラムコードのリターンアドレスを順次取得するリターンアドレス取得手段、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記リターンアドレス取得手段により順次取得されたリターンアドレスが示す先のアドレスに基づいて不正アクセスを検出し、当該不正アクセスが検出された場合には前記データ処理を停止させる停止手段、
として機能させる。
【0032】
請求項6に記載の発明は、
メモリに展開された各プログラムコードを実行するコンピュータにおける不正なプログラムコードの実行防止方法であって、
前記いずれかのプログラムコードの呼び出し時を検出し、当該検出されたプログラムコードの呼び出し時において、前記メモリに展開された各プログラムコードのリターンアドレスを順次取得し、当該取得された各リターンアドレスが示す先のアドレスに基づいて不正アクセスを検出し、当該不正アクセスが検出された場合には前記データ処理を停止させる。
【発明の効果】
【0033】
本発明によれば、CPUが所有する機能に依存せずバッファオーバーフローに関する不正アクセスを確実且つ容易に防止することが可能となる。
【図面の簡単な説明】
【0034】
【図1】本実施の形態に係る情報機器の機能的構成を模式的に示すブロック図である。
【図2】(a)は、Return-to-libc攻撃が実行されている場合のRAM30の所定領域に確保されるスタック領域の一例を示す図であり、(b)は、Return-to-libc攻撃の応用手法を用いた攻撃の場合におけるRAM30の所定領域に確保されるスタック領域の一例を示す図である。
【図3】情報機器のフック処理を示すフローチャートである。
【図4】情報機器において実行されるスタックレイアウトチェック処理の実装例を示すフローチャートである。
【図5】リターンアドレスが関数の開始アドレス付近の場合におけるコードの一例を示す概念図である。
【図6】リターンアドレスが関数の開始アドレスとは全く別のプログラムコードのアドレスに設定して、このプログラムを実行させる場合におけるコードの一例を示す概念図である。
【図7】Return-to-libc攻撃においてCreateFileが実行中である場合のスタックの内容を示す図である。
【図8】Return-to-libc攻撃においてURLDownloadTofileが実行中である場合のスタックの内容を示す図である。
【図9】プログラムコードのソースコードを例示する概念図である。
【図10】プログラムコード実行時におけるスタック領域の概要を例示する概念図である。
【図11】プログラムコードのソースコードを例示する概念図である。
【図12】プログラムコード実行時におけるスタック領域の概要を例示する概念図である。
【図13】Return-to-libc攻撃時におけるプログラムコード実行時におけるスタック領域の概要を例示する概念図である。
【発明を実施するための形態】
【0035】
以下、本発明の実施の形態について図を参照して説明するが、この発明の範囲は以下の実施の形態に限定されない。
【0036】
先ず、本実施の形態に係る情報機器の構成について説明する。
図1に、情報機器1の機能的構成を模式的に示す。図1に示すように、情報機器1は、CPU10、記憶部20、RAM30、操作部40、表示部50、I/F部60を有する。上記情報機器1の各部はバス70により電気的に接続されている。具体的には、情報機器1は、PC、WS、PDA(Personal Digital Assistant)、携帯電話等である。
【0037】
CPU10は、情報機器1の動作を中央制御する。CPU10は、記憶部20に記憶されたプログラムコードや各種データをRAM30のワークエリアに展開し、RAM30に展開されたデータとの協働により各部へ制御信号を出力する。
【0038】
記憶部20は、プログラムコードや各種設定情報などのデータをCPU10から読み書き可能に記憶する。例えば、記憶部20は、HDD(Hard Disk Drive)や半導体メモリ等である。また、記憶部20は、上記データをROM(Read Only Memory)などに記憶する構成であってもよい。なお、記憶部20が記憶するプログラムコードとしては、OS(Operating System)などの基本的なソフトウエアの他、ベンダーが提供した各種アプリケーションプログラム、後述する処理に係るプログラムなどが含まれる。
【0039】
RAM30には、プログラムコードの実行時のデータを格納するスタック領域が確保される。
【0040】
図2(a)に、Return-to-libc攻撃が実行されている場合のRAM30のスタック領域における、あるスタックフレームの一例を示す。図2(a)に示すように、スタック領域には、Exitprocessの引数、ReturnAddress、WinExecの引数2及び1、ExitProcessの開始アドレス、ebp backup等のデータが格納される。Return-to-libc攻撃では、WinExec()が実行された後のリターンアドレスとして、ExitProcess()の開始アドレスが設定される場合がある。図2(a)に示す例は、Return-to-libc攻撃が行われ、WinExec()が実行されている最中におけるスタック領域を示している。
【0041】
Exitprocess()は、プログラムを終了させるための関数であり、引数には終了すべきプログラムの終了コードが設定される。WinExec()は、指定されたプログラムを実行させるための関数である。ebp backupの直前にはReturnAddressがあるので、ebp backupを辿ることでReturnAddressを順次トレースして取得することが可能となる。
【0042】
スタック領域に含まれるスタックフレームは、各プログラムコードが順次実行された場合に、そのプログラムコードの実行に伴って順次確保される。例えば、メインとなるプログラムコードが実行され、そのプログラムコード内でサブルーチンに関するプログラムコードが呼び出され、更に別のプログラムコードが呼び出された場合などは、スタックフレームの各々の順に各プログラムコードに係る領域が確保される。この各プログラムコードに係る処理が終了した際には、スタックフレームのReturnAddressが読み出されることで、メインとなるプログラムコードへの復帰や、プログラム終了後の処理が行われる。
【0043】
図2(b)に、先述したReturn-to-libc攻撃の応用手法におけるRAM30の所定領域に確保されるスタック領域のスタックフレームの一例を示す。「既存のプログラムコード」の領域には、既存のプログラムコード内のExitProcessを呼び出すコードが格納されている。
【0044】
操作部40は、ユーザからの操作入力を受け付け、当該操作に応じた操作信号をCPU10へ出力する。例えば、操作部40は、文字入力キー、数字入力キー、その他各種機能に対応付けられたキーを備えたキーボード、マウス等のポインティングデバイス等である。
【0045】
表示部50は、CPU10から出力された表示制御信号に基づいた画像を表示画面に表示する。例えば、表示部50は、CRT(Cathode Ray Tube)、LCD(Liquid Crystal Display)などであってよい。
【0046】
I/F部60は、データ通信用IC(Integrated Circuit)や接続コネクタなどを備え(いずれも図示しない)、外部機器や通信ネットワークと通信可能に接続する。例えば、I/F部60は、USB(Universal Serial Bus)通信ポートや、LAN(Local Area Network)、WAN(Wide Area Network)、インターネットなどと接続するネットワークインターフェイスカード(NIC:Network Interface Card)であってよい。
【0047】
次に、情報機器1が不正なプログラムコードの実行を検出する際の動作について説明する。情報機器1において、不正なプログラムコードの実行を防止するためには、不正なプログラムコードの実行に必要なAPI、ライブラリ関数、システムコールなどを検出し、不正なプログラムコードの実行の有無をチェックする処理を挿入する必要がある。本実施の形態の情報機器1では、所定のライブラリ関数を呼び出す悪意のあるコードの検出と、不正のチェックを行う処理の挿入を、フック(Hook)を用いて実現している。
【0048】
フックは、プログラム中の特定の箇所に、利用者が独自の処理を追加できるようにする仕組みである。すなわち、フックされる側のプログラムコードを作成したプログラマーと、フックする側のプログラムコードを作成したプログラマーと、が同じプログラマーでなく、互いのプログラムコードに関するソースコードが同一のプログラマーにより作成されない場合に利用される仕組みである。従って、ベンダーが提供するOSや関数の機能変更や、任意の処理の追加時に使用される。
【0049】
なお、フックは、チェック対象となる関数などのサブプログラムをプログラマー自身が修正可能である場合であっても用いてよい。但し、プログラマー自身がサブプログラムを修正可能であり、当該サブプログラムが実行された際に不正のチェックを行うように修正した場合は、フックを使用する必要はなくなるとともに、既存の関数やライブラリをより安全なものとして実装することが可能となる。
【0050】
先ず、APIフック(ライブラリ関数をフックする)を行って不正なプログラムコードの実行の有無をチェックする場合について図3を参照して説明する。
【0051】
以下では、ベンダーが用意したWinExec()というライブラリ関数のフック処理(図3)を例示し、当該ライブラリ関数が呼び出された際に実行されるスタックレイアウトチェック処理(図4)を例示している。なお、他のライブラリ関数(例えば、ExitProcess()等)のフック処理についても同様である。
【0052】
図3に、情報機器1において実行されるフック処理のフローチャートを示す。フック処理は、CPU10と記憶部20に記憶されたプログラムとの協働により実行される。
【0053】
図3に示すように、まずWinExec()の関数の開始アドレスを取得する。(ステップS1)。この関数のアドレス取得は、ベンダーから提供される関数を呼び出すことで可能である。
【0054】
次いで、APIの実行にフックをかける小さな関数(一時的な関数)を動的に生成する(ステップS2)。この動的に生成する関数とは、後述するスタックレイアウトチェック処理を呼び出す関数である。
【0055】
次いで、WinExec()の先頭コードの書き換えが行われ、ステップS2で生成された関数が実行されるように変更される(ステップS3)。
【0056】
情報機器1では、上述したフック処理により、サブプログラムコードの呼び出しを検出し、不正のチェックを行う処理の挿入が可能となっている。通常、関数に係るサブプログラムが呼び出された場合は、ある関数で呼び出された関数がそのまま実行される。しかしながら、情報機器1では、サブプログラムコードが呼び出される前に上述したフック処理を行うことで、サブプログラムコード呼び出し時にスタックレイアウトチェック処理を実行させることができる。
【0057】
図4に、情報機器1において実行されるスタックレイアウトチェック処理のフローチャートを示す。スタックレイアウトチェック処理は、CPU10と記憶部20に記憶されたプログラムとの協働により、フック処理によって動的に生成された関数から呼び出される。なお、このスタックレイアウトチェック処理では、StackWalk()関数を使用してスタックトレースを行っているが、StackWalk()を使用しないでスタックトレースを行うことも可能である。
【0058】
図4に示すように、StackWalk()ライブラリの初期化が行われる(ステップS11)。StackWalk()ライブラリは、ベンダーが用意したスタックトレースを行う関数である。このStackWalk()を利用してトレース位置をインクリメント又はデクリメントすることで、スタック領域に格納されたリターンアドレスを順次取得することが可能となる。
【0059】
次いで、StackWalk()が呼び出されてスタック領域のスタックフレームを順次呼び出すように、スタックが1つバックトレースされ(ステップS12)、トレース後にリターンアドレスが正しく取得できたか否かが判定される(ステップS13)。
【0060】
ステップS13において、リターンアドレスが正しく取得できたと判断されない場合は(ステップS13;NO)、正常終了としてチェック対象であるWinExec()の実行が続行される。これは不正アクセス以外の未知の理由などにより、スタックが破壊されており、StackWalk()が正常に動作しない場合等が該当する。なお、本実施の形態では、StackWalk()が正常に動作しない場合に正常終了しているが、このスタックトレースが失敗した場合にも、プログラムの停止や、ユーザに停止するか否かを確認するためのダイアログを表示部50へ表示してもよい。
【0061】
一方、リターンアドレスが正しく取得できたと判断された場合は(ステップS13;YES)、このリターンアドレスが関数の開始アドレスであるか否かが判断される(ステップS14)。関数の開始アドレスは、公知の様々な取得方法によって取得されるようにすればよく、例えば、予め記憶部20に記憶されている値を参照してもよいし、インポートされる関数の実際のメモリアドレスが格納するための配列であるIAT(Import Address Table)を参照することによって取得されるようにしてもよい。
【0062】
開始アドレスであると判断されない場合(ステップS14;NO)、リターンアドレスの一つ前の命令がCALL命令であるか否かが判断される(ステップS15)。CALL命令とは、サブルーチンを呼び出すための命令であり、ステップS15においては、リターンアドレスの指し示す先の一つ前の命令が判断される。
CALL命令であると判断された場合(ステップS15;YES)、未チェックのリターンアドレスが存在するか否かが判定される(ステップS16)。
【0063】
未チェックのリターンアドレスが存在すると判断された場合(ステップS16;YES)、ステップS12へ戻って、次のリターンアドレスがトレースされる。
未チェックのリターンアドレスが存在すると判断されない場合(ステップS16;NO)、正常終了としてチェック対象であるWinExec()が実行される。
【0064】
一方、開始アドレスであると判断された場合(ステップS14;YES)、CALL命令ではないと判断した場合(ステップS15;NO)、不正アクセス等の攻撃を検出し、不正なプログラムコードの実行を防止するためにデータ処理を一時的に停止する旨のダイアログが表示部50に表示され(ステップS17)、プログラムの実行が停止される(ステップS18)。
【0065】
以上説明したスタックレイアウトチェック処理では、ステップS14及びステップS15においてReturn-to-libc攻撃を検出する。Return-to-libc攻撃が行われた際には、リターンアドレスの指し示す先が関数の開始アドレスであるという特徴がある。通常のプログラムの場合には、リターンアドレスの指し示す先が関数の開始アドレスではなく、この関数の続きから処理が継続される。
【0066】
また、Return-to-libc攻撃の応用手法である、情報機器1に記憶されているプログラムコードを組み合わせた攻撃では、リターンアドレスの指し示す先の一つ前の命令がCALL命令でないという特徴がある。これらの2つの特徴は、正常なプログラムを実行する際には無い特徴である。スタックレイアウトチェック処理では、これらの2つの特徴に基づいてReturn-to-libc攻撃を検出する。
【0067】
次に、スタックレイアウトチェック処理において検出可能な、Return-to-libc攻撃の派生パターンについて説明する。上記説明したスタックレイアウトチェック処理においては、リターンアドレスの指し示す先をチェックすることによりReturn-to-libc攻撃の検出が可能となるが、Return-to-libc攻撃には様々な攻撃パターンが知られている。
【0068】
図5に、リターンアドレスが関数の開始アドレス付近の場合におけるコードC1の一例を示す。通常、OSが提供している関数の開始アドレスの直前には、CPUで実行しても何も行わない命令が配置されていることが多い。Return-to-libc攻撃においては、リターンアドレスを関数の開始アドレスではなく、わざと開始アドレス付近に指定することも考えられる。図5に示すように、関数の開始アドレスの位置の前に複数のnop命令が挿入されている。nop命令とは、CPUが何も実行しないことを示す命令である。
【0069】
図5に示す場合、リターンアドレスが指し示す先が関数の開始アドレスではないため、ステップS14においてReturn-to-libc攻撃を検出することはできないが、ステップS15においてリターンアドレスの指し示す先の一つ前の命令がCALL命令であるか否かをチェックすることにより、Return-to-libc攻撃を検出することができる。
【0070】
図6に、リターンアドレスが関数の開始アドレスとは全く別のプログラムコードのアドレスに設定して、このプログラムを実行させる場合におけるコードC2の一例を示す。図6に示す例では、リターンアドレスの指し示す先に「jmp eax」という命令コードが格納されている。「jmp eax」という命令は、eaxレジスタに格納されている値が指し示す先の命令を実行させるという命令である。eaxレジスタには、実行させたい関数の開始アドレスが格納されている。図6に示す状態でリターンアドレスの指し示す先のコードが実行されると、まず、「jmp eax」が実行され、次に、実行させたい関数の開始アドレスが実行される。
【0071】
図6に示す場合、リターンアドレスが指し示す先が関数の開始アドレスではないため、ステップS14においてReturn-to-libc攻撃を検出することはできない。但し、悪意のある攻撃者は別のプログラムコードの領域内から「jmp eax」となっている命令コードを探しだし、リターンアドレスに設定する必要がある。Return-to-libc攻撃においては、「jmp eax」となっている命令コードの一つ前の命令がCALL命令でない場合が多く、ステップS15においてReturn-to-libc攻撃を検出することができる。
【0072】
次に、Windows(登録商標。以下、注記を省略する。)において実行されるReturn-to-libc攻撃の例を挙げ、本発明に係る情報機器1がReturn-to-libc攻撃を検出するタイミングについて述べる。
【0073】
まず、CPU10が作成したファイルを実行することによるReturn-to-libc攻撃の一例を説明する。この場合では、Windowsが提供する関数であるCreateFile()、WriteFile()、WinExec()、Exitprocess()等の関数を使用し、Return-to-libc攻撃を行う。CreateFile()とは、ファイル等を作成するための関数であり、作成するファイル名等が引数となる。WriteFile()とは、ファイルにデータを書き込むための関数であり、データを書き込む対象を示すファイルハンドルや書き込むデータ、データサイズ等が引数となる。
【0074】
まず、Return-to-libc攻撃においては、CreateFile()、WriteFile()を使用して、所定のファイルが作成される。この作成されたファイルをWinExec()で実行させ、ExitProcess()で終了させる手順となっている。
【0075】
図7に、Return-to-libc攻撃においてCreateFile()が実行中である場合のRAM30に記憶されたスタック領域の一例を示す。図7に示すスタックの状態では、スタックレイアウトチェック処理におけるチェック対象のリターンアドレスとして、「WriteFileの開始アドレス」、「WinExecの開始アドレス」、「ExitProcessの開始アドレス」の3つがチェック対象となる。開始アドレスが、図5に示すような開始アドレス付近や、図6に示すような別のプログラムコードを示している場合でも、ステップS15においてReturn-to-libc攻撃を検出することができる。
【0076】
Return-to-libc攻撃における攻撃コードがインターネットを介して悪意のあるコードをダウンロードし、そのファイルが実行される場合もある。例えば、まずWindowsが提供するURLDownloadTofile()という関数を使用して、I/F部60を介してインターネットから悪意のあるファイルをダウンロードする。ダウンロードされたファイルは、WinExec()を使用することにより実行される。
【0077】
図8に、Return-to-libc攻撃においてURLDownloadTofile()が実行中である場合のRAM30に記憶されるスタック領域の一例を示す。図8に示すスタックの状態では、スタックレイアウトチェック処理におけるチェック対象のリターンアドレスとして、「WinExecの開始アドレス」、「ExitProcessの開始アドレス」の2つがチェック対象となる。開始アドレスが、図5に示すような開始アドレス付近や、図6に示すような別のプログラムコードを示している場合でも、ステップS15においてReturn-to-libc攻撃を検出することができる。
【0078】
以上のように、本発明に係る情報機器によれば、CPUが所有する機能に依存せずバッファオーバーフローに関する不正アクセスの手法であるReturn-to-libc攻撃を確実且つ容易に防止することができる。
【0079】
なお、上述した実施の形態における記述は、一例を示すものであり、これに限定するものではない。上述した実施の形態における構成及び動作に関しては、適宜変更が可能である。
【0080】
例えば、以上の説明では、本発明に係るプログラムのコンピュータ読み取り可能な媒体として記憶部20やROMを使用した例を開示したが、この例に限定されない。その他のコンピュータ読み取り可能な媒体として、フラッシュメモリ等の不揮発性メモリ、CD-ROM等の可搬型記録媒体を適用することが可能である。また、本発明に係るプログラムのデータをI/F部60と接続する通信回線を介して提供する媒体として、キャリアウエーブ(搬送波)も本発明に適用される。
【符号の説明】
【0081】
1 情報機器
10 CPU
20 記憶部
30 RAM
40 操作部
50 表示部
60 I/F部
70 バス
【技術分野】
【0001】
本発明は、情報機器、プログラム及び不正なプログラムコードの実行防止方法に関する。
【背景技術】
【0002】
一般的に、PC(Personal Computer)やWS(Work Station)等の情報機器では、CPU(Central Processing Unit)などの制御部がRAM(Random Access Memory)等の記憶部の作業領域に展開されたプログラムコードを順次実行することで、各種データ処理を実行している。近年、悪意のあるユーザによって作成されたプログラムコードによる不正な処理によって、情報機器に対する不正アクセスが発生している。
【0003】
通常、情報機器が管理するデータにはアクセス権限が設定されている。従って、データへのアクセス権限がなければ、不正アクセスが行われることはない。しかしながら、データへのアクセス権限がある通常のプログラムコードを利用し、不正な操作が実行された場合は、不正アクセスが可能となる。このような手法としては、プログラムコードの実行時のデータをRAM等に確保された所定領域からオーバーフローさせる、いわゆるバッファオーバーフローを用いた手法が知られている。
【0004】
ここで、バッファオーバーフローを用いた不正アクセスについて、正常にプログラムコードが実行された場合と、プログラムコードの実行時に不正が行われた場合と、を比較して詳細に説明する。
【0005】
先ず、図9、図10を参照して正常にプログラムコードが実行された場合を説明する。
図9に、プログラムコードのソースコードを例示する概念図を示す。図9に示すプログラムコードは、main()関数から開始され、main()関数の中でstrcpy_helloworld()関数を呼び出している。このプログラムコードでは、strcpy_helloworld()関数の中で「Hello!」という文字列を用意し、main()関数のprintf()関数でこの文字列をモニタ等に表示させている。なお、関数とは、所定の機能をモジュール化してまとめたサブルーチンやサブプログラムなどであり、メインとなるプログラム内で随時呼び出すことができる。
【0006】
図9に示すプログラムコードの実行時のデータは、RAM等に確保されたスタック領域に格納される。このスタック領域では、後入れ先出し (LIFO: Last In First Out; FILO: First In Last Out) 構造でデータが格納される。
【0007】
図10に、プログラムコード実行時におけるスタック領域の概要を例示する概念図を示す。図10に示すように、上から下に向かって順次確保された領域へプログラムコードの実行時のデータが格納される。
【0008】
例えば、図9に例示したソースコードによるプログラムコードの実行時には、main()関数を処理した際に、ReturnAddress1、ebp backup、char buf[8]などが1つのスタックフレームとして格納される。次いで、main()関数の中でstrcpy_helloworld()関数が呼び出された際に、ReturnAddress2、ebp backup2、int i等が一つのスタックフレームとして格納される。
【0009】
ReturnAddress(リターンアドレス)は、プログラムの終了時に戻るべきアドレス値や、関数などによりサブプログラムが呼び出された場合の当該サブプログラム終了時に戻るべきアドレス値を示す。このReturnAddressは、プログラムの実行直後や関数などによりサブプログラムが呼び出された直後に、CPUにより自動的にスタック領域へ格納される。
【0010】
ebpは、CPUのレジスタの一種であり、現在使用している一時的なメモリ領域のアドレスの直前を示す。図10の例では、char buf[8]、int iの前のアドレスであり、スタックフレームのReturnAddressが該当する。従って、スタックフレームにおいて、上記レジスタ値をebp backupとしてバックアップすることで、このスタックフレーム内の一領域を一時的なデータ(変数や配列等)を格納するメモリ領域として簡単に使用することが可能となる。
【0011】
char buf[8]は、main()関数で使用される配列であるbufを格納する。このbufは、char型の変数(1バイト)を8個格納する配列であり、8バイト分のデータが格納可能となっている。int iは、strcpy_helloworld()関数で使用されるint型の変数であるiを格納する。
【0012】
従って、上記プログラムコードの実行により、スタック領域では、main()関数のスタックフレームが確保され、strcpy_helloworld()関数のスタックフレームが確保される。次いで、int iの値が順次インクリメントされて、「Hello!」という6バイト分の文字列がchar buf[8]に格納される。次いで、strcpy_helloworld()関数の終了により、ReturnAddress2が読み出されてmain()関数へ復帰され、main()関数の終了により、ReturnAddress1が読み出されてプログラムは正常終了する。
【0013】
次に、図11、図12を参照してプログラムコードの実行時に不正が行われた場合を説明する。
【0014】
図11に、プログラムコードのソースコードを例示する概念図を示す。図11に示すプログラムコードは、配列bufへ「Hello World」という12バイト分(11文字+文字列終端)のデータを書き込む点において、図9に示すプログラムコードと異なる。
【0015】
図12に、プログラムコード実行時におけるスタック領域の概要を例示する概念図を示す。図12に示すように、スタック領域では、配列bufを格納する領域として8バイト分の領域が確保されている。従って、strcpy_helloworld()関数が実行された際には、確保されているサイズ以上のデータが書き込まれる。このように、メモリに確保されているサイズ以上のデータが書き込まれるとバッファオーバーフローが発生する。なお、このバッファオーバーフローがスタック領域で起きる場合をスタックベースのバッファオーバーフローという。
【0016】
図12に示したスタック領域おいて、領域の確保は上から下に向かって順次行われ、その確保された領域へのデータの書き込みは下から上に向かって行われる。従って、ReturnAddress1、ebp backupはstrcpy_helloworld()関数が実行された際に、「Hello World」という12バイト分のデータにより不正に上書き(overwrite)される。上述した上書きにより、ReturnAddress1の内容が実行可能なプログラムコードが置いてあるアドレスに書き換えられた場合は、main()関数の終了によりReturnAddress1が読み出され、その書き換えられたプログラムコードが実行される。
【0017】
図11に示したソースコードでは、「Hello World」という予め定義された文字列によりオーバーフローとなっている。しかしながら、実際には、メールサーバやWebサーバ等の通信ポートで受信されたデータや、コンソールやファイルから入力されたデータなどが配列bufに格納される場合もある。このような場合は、悪意のあるユーザにより通信、コンソール入力、ファイル入力などを介して任意のプログラムコードが実行され、データの盗みだしや改竄などの不正アクセスが発生する。
【0018】
これらの不正アクセスを検出する方法として、スタック領域に格納されているリターンアドレスを検査し、正常なプログラム実行時と攻撃コード動作時のリターンアドレスの配置パターンの違いを比べることによって不正アクセスが実行されるか否かを検出する方法が考えられる。例えば、リターンアドレスが示す先のメモリ属性が、プログラムコードを配置するためのメモリ領域を支援している場合又はこのメモリ領域が書き込み不可能な属性にある場合は正常なプログラムと判断する等である。
【0019】
しかし、このような不正アクセスの検出方法では、Return-to-libc攻撃(非特許文献1参照)を検出できない可能性がある。Return-to-libc攻撃とは、悪意のあるコードをプログラムコードに書き加えることなく、コンピュータに既に記憶されている関数を呼び出すことによって不正アクセスを行う攻撃手法である。
【0020】
図13に、図11に示すプログラムコード実行時においてReturn-to-libc攻撃された際のスタック領域の概要を例示する概念図を示す。図13に示すように、Return-to-libc攻撃では、上記説明したリターンアドレスが示す値が、OS(Operating System)の標準関数等の正常な関数の先頭アドレスに設定される。スタック領域上のリターンアドレスが、プログラムコードを置くためのメモリ領域を示していたり、このメモリ領域が書き込み不可能な属性にあったりした場合には、正常なプログラムと区別がつかない可能性がある。
【0021】
このReturn-to-libc攻撃を応用し、既に情報機器の記憶部に記憶されているプログラムのプログラムコードを組み合わせることによって所定のプログラムコードを実行する攻撃が考えられる。この攻撃方法においても、スタック領域上のリターンアドレスはReturn-to-libc攻撃と同様の特徴があるため、正常なプログラムと区別がつかない可能性がある。
【0022】
特許文献1には、CPUの機能の一つであるブランチトレースを使用し、実行中の関数から呼び出し元の関数の処理に戻る際に、OSの標準関数の先頭アドレスに戻るという動きを検出することによってReturn-to-libc攻撃を検出する技術が開示されている。
【先行技術文献】
【特許文献】
【0023】
【特許文献1】米国特許第10/763,867号明細書
【非特許文献】
【0024】
【非特許文献1】”Return-to-libc attack”、[online]、ウィキメディア財団、[2009年3月23日検索]、インターネット、(URL:http://en.wikipedia.org/wiki/Return-to-libc_attack)
【発明の概要】
【発明が解決しようとする課題】
【0025】
しかしながら、特許文献1に記載の技術では、Return-to-libc攻撃をブランチトレースという機能を使用して検出することはできるが、CPUが所有する機能を使用しているため、CPUの処理負荷の増大、ブランチトレース機能を使用する他のアプリケーション(パフォーマンス計測ツール等)の使用の制限等が発生する可能性がある。つまり、Return-to-libc攻撃を検出するための処理が実行されている間は、コンピュータの処理負荷が増大し、ユーザビリティの低下を招く可能性がある。
【0026】
本発明の課題は、上記従来技術の問題に鑑みてなされたものであり、CPUが所有する機能に依存せずバッファオーバーフローに関する不正アクセスを確実且つ容易に防止する技術を提供することである。
【課題を解決するための手段】
【0027】
上記課題を解決するために、請求項1に記載の発明は、
メモリに展開された各プログラムコードと中央制御部との協働によりデータ処理を行う情報機器であって、
前記いずれかのプログラムコードの呼び出し時を検出する検出手段と、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記メモリに展開された各プログラムコードのリターンアドレスを順次取得するリターンアドレス取得手段と、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記リターンアドレス取得手段により順次取得されたリターンアドレスが示す先のアドレスに基づいて不正アクセスを検出し、当該不正アクセスが検出された場合には前記データ処理を停止させる停止手段と、
を備える。
【0028】
請求項2に記載の発明は、請求項1に記載の発明において、
前記メモリは、各プログラムコードのリターンアドレスを格納するスタック領域を備え、
前記リターンアドレス取得手段は、前記スタック領域に格納されたリターンアドレスをトレースして取得する。
【0029】
請求項3に記載の発明は、請求項1又は2に記載の発明において、
前記停止手段は、前記属性取得手段により取得された各リターンアドレスが示す先のアドレスが関数の開始アドレスである場合に不正アクセスを検出し、当該不正アクセスが検出された場合には、前記データ処理を停止させる。
【0030】
請求項4に記載の発明は、請求項1〜3の何れか一項に記載の発明において、
前記停止手段は、前記属性取得手段により取得された各リターンアドレスが示す先のアドレスに対応する一つ前の命令がコール命令ではない場合に不正アクセスを検出し、当該不正アクセスが検出された場合には、前記データ処理を停止させる。
【0031】
請求項5に記載の発明は、
メモリに展開された各プログラムコードを実行するコンピュータを、
前記いずれかのプログラムコードの呼び出し時を検出する検出手段、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記メモリに展開された各プログラムコードのリターンアドレスを順次取得するリターンアドレス取得手段、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記リターンアドレス取得手段により順次取得されたリターンアドレスが示す先のアドレスに基づいて不正アクセスを検出し、当該不正アクセスが検出された場合には前記データ処理を停止させる停止手段、
として機能させる。
【0032】
請求項6に記載の発明は、
メモリに展開された各プログラムコードを実行するコンピュータにおける不正なプログラムコードの実行防止方法であって、
前記いずれかのプログラムコードの呼び出し時を検出し、当該検出されたプログラムコードの呼び出し時において、前記メモリに展開された各プログラムコードのリターンアドレスを順次取得し、当該取得された各リターンアドレスが示す先のアドレスに基づいて不正アクセスを検出し、当該不正アクセスが検出された場合には前記データ処理を停止させる。
【発明の効果】
【0033】
本発明によれば、CPUが所有する機能に依存せずバッファオーバーフローに関する不正アクセスを確実且つ容易に防止することが可能となる。
【図面の簡単な説明】
【0034】
【図1】本実施の形態に係る情報機器の機能的構成を模式的に示すブロック図である。
【図2】(a)は、Return-to-libc攻撃が実行されている場合のRAM30の所定領域に確保されるスタック領域の一例を示す図であり、(b)は、Return-to-libc攻撃の応用手法を用いた攻撃の場合におけるRAM30の所定領域に確保されるスタック領域の一例を示す図である。
【図3】情報機器のフック処理を示すフローチャートである。
【図4】情報機器において実行されるスタックレイアウトチェック処理の実装例を示すフローチャートである。
【図5】リターンアドレスが関数の開始アドレス付近の場合におけるコードの一例を示す概念図である。
【図6】リターンアドレスが関数の開始アドレスとは全く別のプログラムコードのアドレスに設定して、このプログラムを実行させる場合におけるコードの一例を示す概念図である。
【図7】Return-to-libc攻撃においてCreateFileが実行中である場合のスタックの内容を示す図である。
【図8】Return-to-libc攻撃においてURLDownloadTofileが実行中である場合のスタックの内容を示す図である。
【図9】プログラムコードのソースコードを例示する概念図である。
【図10】プログラムコード実行時におけるスタック領域の概要を例示する概念図である。
【図11】プログラムコードのソースコードを例示する概念図である。
【図12】プログラムコード実行時におけるスタック領域の概要を例示する概念図である。
【図13】Return-to-libc攻撃時におけるプログラムコード実行時におけるスタック領域の概要を例示する概念図である。
【発明を実施するための形態】
【0035】
以下、本発明の実施の形態について図を参照して説明するが、この発明の範囲は以下の実施の形態に限定されない。
【0036】
先ず、本実施の形態に係る情報機器の構成について説明する。
図1に、情報機器1の機能的構成を模式的に示す。図1に示すように、情報機器1は、CPU10、記憶部20、RAM30、操作部40、表示部50、I/F部60を有する。上記情報機器1の各部はバス70により電気的に接続されている。具体的には、情報機器1は、PC、WS、PDA(Personal Digital Assistant)、携帯電話等である。
【0037】
CPU10は、情報機器1の動作を中央制御する。CPU10は、記憶部20に記憶されたプログラムコードや各種データをRAM30のワークエリアに展開し、RAM30に展開されたデータとの協働により各部へ制御信号を出力する。
【0038】
記憶部20は、プログラムコードや各種設定情報などのデータをCPU10から読み書き可能に記憶する。例えば、記憶部20は、HDD(Hard Disk Drive)や半導体メモリ等である。また、記憶部20は、上記データをROM(Read Only Memory)などに記憶する構成であってもよい。なお、記憶部20が記憶するプログラムコードとしては、OS(Operating System)などの基本的なソフトウエアの他、ベンダーが提供した各種アプリケーションプログラム、後述する処理に係るプログラムなどが含まれる。
【0039】
RAM30には、プログラムコードの実行時のデータを格納するスタック領域が確保される。
【0040】
図2(a)に、Return-to-libc攻撃が実行されている場合のRAM30のスタック領域における、あるスタックフレームの一例を示す。図2(a)に示すように、スタック領域には、Exitprocessの引数、ReturnAddress、WinExecの引数2及び1、ExitProcessの開始アドレス、ebp backup等のデータが格納される。Return-to-libc攻撃では、WinExec()が実行された後のリターンアドレスとして、ExitProcess()の開始アドレスが設定される場合がある。図2(a)に示す例は、Return-to-libc攻撃が行われ、WinExec()が実行されている最中におけるスタック領域を示している。
【0041】
Exitprocess()は、プログラムを終了させるための関数であり、引数には終了すべきプログラムの終了コードが設定される。WinExec()は、指定されたプログラムを実行させるための関数である。ebp backupの直前にはReturnAddressがあるので、ebp backupを辿ることでReturnAddressを順次トレースして取得することが可能となる。
【0042】
スタック領域に含まれるスタックフレームは、各プログラムコードが順次実行された場合に、そのプログラムコードの実行に伴って順次確保される。例えば、メインとなるプログラムコードが実行され、そのプログラムコード内でサブルーチンに関するプログラムコードが呼び出され、更に別のプログラムコードが呼び出された場合などは、スタックフレームの各々の順に各プログラムコードに係る領域が確保される。この各プログラムコードに係る処理が終了した際には、スタックフレームのReturnAddressが読み出されることで、メインとなるプログラムコードへの復帰や、プログラム終了後の処理が行われる。
【0043】
図2(b)に、先述したReturn-to-libc攻撃の応用手法におけるRAM30の所定領域に確保されるスタック領域のスタックフレームの一例を示す。「既存のプログラムコード」の領域には、既存のプログラムコード内のExitProcessを呼び出すコードが格納されている。
【0044】
操作部40は、ユーザからの操作入力を受け付け、当該操作に応じた操作信号をCPU10へ出力する。例えば、操作部40は、文字入力キー、数字入力キー、その他各種機能に対応付けられたキーを備えたキーボード、マウス等のポインティングデバイス等である。
【0045】
表示部50は、CPU10から出力された表示制御信号に基づいた画像を表示画面に表示する。例えば、表示部50は、CRT(Cathode Ray Tube)、LCD(Liquid Crystal Display)などであってよい。
【0046】
I/F部60は、データ通信用IC(Integrated Circuit)や接続コネクタなどを備え(いずれも図示しない)、外部機器や通信ネットワークと通信可能に接続する。例えば、I/F部60は、USB(Universal Serial Bus)通信ポートや、LAN(Local Area Network)、WAN(Wide Area Network)、インターネットなどと接続するネットワークインターフェイスカード(NIC:Network Interface Card)であってよい。
【0047】
次に、情報機器1が不正なプログラムコードの実行を検出する際の動作について説明する。情報機器1において、不正なプログラムコードの実行を防止するためには、不正なプログラムコードの実行に必要なAPI、ライブラリ関数、システムコールなどを検出し、不正なプログラムコードの実行の有無をチェックする処理を挿入する必要がある。本実施の形態の情報機器1では、所定のライブラリ関数を呼び出す悪意のあるコードの検出と、不正のチェックを行う処理の挿入を、フック(Hook)を用いて実現している。
【0048】
フックは、プログラム中の特定の箇所に、利用者が独自の処理を追加できるようにする仕組みである。すなわち、フックされる側のプログラムコードを作成したプログラマーと、フックする側のプログラムコードを作成したプログラマーと、が同じプログラマーでなく、互いのプログラムコードに関するソースコードが同一のプログラマーにより作成されない場合に利用される仕組みである。従って、ベンダーが提供するOSや関数の機能変更や、任意の処理の追加時に使用される。
【0049】
なお、フックは、チェック対象となる関数などのサブプログラムをプログラマー自身が修正可能である場合であっても用いてよい。但し、プログラマー自身がサブプログラムを修正可能であり、当該サブプログラムが実行された際に不正のチェックを行うように修正した場合は、フックを使用する必要はなくなるとともに、既存の関数やライブラリをより安全なものとして実装することが可能となる。
【0050】
先ず、APIフック(ライブラリ関数をフックする)を行って不正なプログラムコードの実行の有無をチェックする場合について図3を参照して説明する。
【0051】
以下では、ベンダーが用意したWinExec()というライブラリ関数のフック処理(図3)を例示し、当該ライブラリ関数が呼び出された際に実行されるスタックレイアウトチェック処理(図4)を例示している。なお、他のライブラリ関数(例えば、ExitProcess()等)のフック処理についても同様である。
【0052】
図3に、情報機器1において実行されるフック処理のフローチャートを示す。フック処理は、CPU10と記憶部20に記憶されたプログラムとの協働により実行される。
【0053】
図3に示すように、まずWinExec()の関数の開始アドレスを取得する。(ステップS1)。この関数のアドレス取得は、ベンダーから提供される関数を呼び出すことで可能である。
【0054】
次いで、APIの実行にフックをかける小さな関数(一時的な関数)を動的に生成する(ステップS2)。この動的に生成する関数とは、後述するスタックレイアウトチェック処理を呼び出す関数である。
【0055】
次いで、WinExec()の先頭コードの書き換えが行われ、ステップS2で生成された関数が実行されるように変更される(ステップS3)。
【0056】
情報機器1では、上述したフック処理により、サブプログラムコードの呼び出しを検出し、不正のチェックを行う処理の挿入が可能となっている。通常、関数に係るサブプログラムが呼び出された場合は、ある関数で呼び出された関数がそのまま実行される。しかしながら、情報機器1では、サブプログラムコードが呼び出される前に上述したフック処理を行うことで、サブプログラムコード呼び出し時にスタックレイアウトチェック処理を実行させることができる。
【0057】
図4に、情報機器1において実行されるスタックレイアウトチェック処理のフローチャートを示す。スタックレイアウトチェック処理は、CPU10と記憶部20に記憶されたプログラムとの協働により、フック処理によって動的に生成された関数から呼び出される。なお、このスタックレイアウトチェック処理では、StackWalk()関数を使用してスタックトレースを行っているが、StackWalk()を使用しないでスタックトレースを行うことも可能である。
【0058】
図4に示すように、StackWalk()ライブラリの初期化が行われる(ステップS11)。StackWalk()ライブラリは、ベンダーが用意したスタックトレースを行う関数である。このStackWalk()を利用してトレース位置をインクリメント又はデクリメントすることで、スタック領域に格納されたリターンアドレスを順次取得することが可能となる。
【0059】
次いで、StackWalk()が呼び出されてスタック領域のスタックフレームを順次呼び出すように、スタックが1つバックトレースされ(ステップS12)、トレース後にリターンアドレスが正しく取得できたか否かが判定される(ステップS13)。
【0060】
ステップS13において、リターンアドレスが正しく取得できたと判断されない場合は(ステップS13;NO)、正常終了としてチェック対象であるWinExec()の実行が続行される。これは不正アクセス以外の未知の理由などにより、スタックが破壊されており、StackWalk()が正常に動作しない場合等が該当する。なお、本実施の形態では、StackWalk()が正常に動作しない場合に正常終了しているが、このスタックトレースが失敗した場合にも、プログラムの停止や、ユーザに停止するか否かを確認するためのダイアログを表示部50へ表示してもよい。
【0061】
一方、リターンアドレスが正しく取得できたと判断された場合は(ステップS13;YES)、このリターンアドレスが関数の開始アドレスであるか否かが判断される(ステップS14)。関数の開始アドレスは、公知の様々な取得方法によって取得されるようにすればよく、例えば、予め記憶部20に記憶されている値を参照してもよいし、インポートされる関数の実際のメモリアドレスが格納するための配列であるIAT(Import Address Table)を参照することによって取得されるようにしてもよい。
【0062】
開始アドレスであると判断されない場合(ステップS14;NO)、リターンアドレスの一つ前の命令がCALL命令であるか否かが判断される(ステップS15)。CALL命令とは、サブルーチンを呼び出すための命令であり、ステップS15においては、リターンアドレスの指し示す先の一つ前の命令が判断される。
CALL命令であると判断された場合(ステップS15;YES)、未チェックのリターンアドレスが存在するか否かが判定される(ステップS16)。
【0063】
未チェックのリターンアドレスが存在すると判断された場合(ステップS16;YES)、ステップS12へ戻って、次のリターンアドレスがトレースされる。
未チェックのリターンアドレスが存在すると判断されない場合(ステップS16;NO)、正常終了としてチェック対象であるWinExec()が実行される。
【0064】
一方、開始アドレスであると判断された場合(ステップS14;YES)、CALL命令ではないと判断した場合(ステップS15;NO)、不正アクセス等の攻撃を検出し、不正なプログラムコードの実行を防止するためにデータ処理を一時的に停止する旨のダイアログが表示部50に表示され(ステップS17)、プログラムの実行が停止される(ステップS18)。
【0065】
以上説明したスタックレイアウトチェック処理では、ステップS14及びステップS15においてReturn-to-libc攻撃を検出する。Return-to-libc攻撃が行われた際には、リターンアドレスの指し示す先が関数の開始アドレスであるという特徴がある。通常のプログラムの場合には、リターンアドレスの指し示す先が関数の開始アドレスではなく、この関数の続きから処理が継続される。
【0066】
また、Return-to-libc攻撃の応用手法である、情報機器1に記憶されているプログラムコードを組み合わせた攻撃では、リターンアドレスの指し示す先の一つ前の命令がCALL命令でないという特徴がある。これらの2つの特徴は、正常なプログラムを実行する際には無い特徴である。スタックレイアウトチェック処理では、これらの2つの特徴に基づいてReturn-to-libc攻撃を検出する。
【0067】
次に、スタックレイアウトチェック処理において検出可能な、Return-to-libc攻撃の派生パターンについて説明する。上記説明したスタックレイアウトチェック処理においては、リターンアドレスの指し示す先をチェックすることによりReturn-to-libc攻撃の検出が可能となるが、Return-to-libc攻撃には様々な攻撃パターンが知られている。
【0068】
図5に、リターンアドレスが関数の開始アドレス付近の場合におけるコードC1の一例を示す。通常、OSが提供している関数の開始アドレスの直前には、CPUで実行しても何も行わない命令が配置されていることが多い。Return-to-libc攻撃においては、リターンアドレスを関数の開始アドレスではなく、わざと開始アドレス付近に指定することも考えられる。図5に示すように、関数の開始アドレスの位置の前に複数のnop命令が挿入されている。nop命令とは、CPUが何も実行しないことを示す命令である。
【0069】
図5に示す場合、リターンアドレスが指し示す先が関数の開始アドレスではないため、ステップS14においてReturn-to-libc攻撃を検出することはできないが、ステップS15においてリターンアドレスの指し示す先の一つ前の命令がCALL命令であるか否かをチェックすることにより、Return-to-libc攻撃を検出することができる。
【0070】
図6に、リターンアドレスが関数の開始アドレスとは全く別のプログラムコードのアドレスに設定して、このプログラムを実行させる場合におけるコードC2の一例を示す。図6に示す例では、リターンアドレスの指し示す先に「jmp eax」という命令コードが格納されている。「jmp eax」という命令は、eaxレジスタに格納されている値が指し示す先の命令を実行させるという命令である。eaxレジスタには、実行させたい関数の開始アドレスが格納されている。図6に示す状態でリターンアドレスの指し示す先のコードが実行されると、まず、「jmp eax」が実行され、次に、実行させたい関数の開始アドレスが実行される。
【0071】
図6に示す場合、リターンアドレスが指し示す先が関数の開始アドレスではないため、ステップS14においてReturn-to-libc攻撃を検出することはできない。但し、悪意のある攻撃者は別のプログラムコードの領域内から「jmp eax」となっている命令コードを探しだし、リターンアドレスに設定する必要がある。Return-to-libc攻撃においては、「jmp eax」となっている命令コードの一つ前の命令がCALL命令でない場合が多く、ステップS15においてReturn-to-libc攻撃を検出することができる。
【0072】
次に、Windows(登録商標。以下、注記を省略する。)において実行されるReturn-to-libc攻撃の例を挙げ、本発明に係る情報機器1がReturn-to-libc攻撃を検出するタイミングについて述べる。
【0073】
まず、CPU10が作成したファイルを実行することによるReturn-to-libc攻撃の一例を説明する。この場合では、Windowsが提供する関数であるCreateFile()、WriteFile()、WinExec()、Exitprocess()等の関数を使用し、Return-to-libc攻撃を行う。CreateFile()とは、ファイル等を作成するための関数であり、作成するファイル名等が引数となる。WriteFile()とは、ファイルにデータを書き込むための関数であり、データを書き込む対象を示すファイルハンドルや書き込むデータ、データサイズ等が引数となる。
【0074】
まず、Return-to-libc攻撃においては、CreateFile()、WriteFile()を使用して、所定のファイルが作成される。この作成されたファイルをWinExec()で実行させ、ExitProcess()で終了させる手順となっている。
【0075】
図7に、Return-to-libc攻撃においてCreateFile()が実行中である場合のRAM30に記憶されたスタック領域の一例を示す。図7に示すスタックの状態では、スタックレイアウトチェック処理におけるチェック対象のリターンアドレスとして、「WriteFileの開始アドレス」、「WinExecの開始アドレス」、「ExitProcessの開始アドレス」の3つがチェック対象となる。開始アドレスが、図5に示すような開始アドレス付近や、図6に示すような別のプログラムコードを示している場合でも、ステップS15においてReturn-to-libc攻撃を検出することができる。
【0076】
Return-to-libc攻撃における攻撃コードがインターネットを介して悪意のあるコードをダウンロードし、そのファイルが実行される場合もある。例えば、まずWindowsが提供するURLDownloadTofile()という関数を使用して、I/F部60を介してインターネットから悪意のあるファイルをダウンロードする。ダウンロードされたファイルは、WinExec()を使用することにより実行される。
【0077】
図8に、Return-to-libc攻撃においてURLDownloadTofile()が実行中である場合のRAM30に記憶されるスタック領域の一例を示す。図8に示すスタックの状態では、スタックレイアウトチェック処理におけるチェック対象のリターンアドレスとして、「WinExecの開始アドレス」、「ExitProcessの開始アドレス」の2つがチェック対象となる。開始アドレスが、図5に示すような開始アドレス付近や、図6に示すような別のプログラムコードを示している場合でも、ステップS15においてReturn-to-libc攻撃を検出することができる。
【0078】
以上のように、本発明に係る情報機器によれば、CPUが所有する機能に依存せずバッファオーバーフローに関する不正アクセスの手法であるReturn-to-libc攻撃を確実且つ容易に防止することができる。
【0079】
なお、上述した実施の形態における記述は、一例を示すものであり、これに限定するものではない。上述した実施の形態における構成及び動作に関しては、適宜変更が可能である。
【0080】
例えば、以上の説明では、本発明に係るプログラムのコンピュータ読み取り可能な媒体として記憶部20やROMを使用した例を開示したが、この例に限定されない。その他のコンピュータ読み取り可能な媒体として、フラッシュメモリ等の不揮発性メモリ、CD-ROM等の可搬型記録媒体を適用することが可能である。また、本発明に係るプログラムのデータをI/F部60と接続する通信回線を介して提供する媒体として、キャリアウエーブ(搬送波)も本発明に適用される。
【符号の説明】
【0081】
1 情報機器
10 CPU
20 記憶部
30 RAM
40 操作部
50 表示部
60 I/F部
70 バス
【特許請求の範囲】
【請求項1】
メモリに展開された各プログラムコードと中央制御部との協働によりデータ処理を行う情報機器であって、
前記いずれかのプログラムコードの呼び出し時を検出する検出手段と、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記メモリに展開された各プログラムコードのリターンアドレスを順次取得するリターンアドレス取得手段と、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記リターンアドレス取得手段により順次取得されたリターンアドレスが示す先のアドレスに基づいて不正アクセスを検出し、当該不正アクセスが検出された場合には前記データ処理を停止させる停止手段と、
を備える情報機器。
【請求項2】
前記メモリは、各プログラムコードのリターンアドレスを格納するスタック領域を備え、
前記リターンアドレス取得手段は、前記スタック領域に格納されたリターンアドレスをトレースして取得する請求項1に記載の情報機器。
【請求項3】
前記停止手段は、前記属性取得手段により取得された各リターンアドレスが示す先のアドレスが関数の開始アドレスである場合に不正アクセスを検出し、当該不正アクセスが検出された場合には、前記データ処理を停止させる請求項1又は2に記載の情報機器。
【請求項4】
前記停止手段は、前記属性取得手段により取得された各リターンアドレスが示す先のアドレスに対応する一つ前の命令がコール命令ではない場合に不正アクセスを検出し、当該不正アクセスが検出された場合には、前記データ処理を停止させる請求項1〜3の何れか一項に記載の情報機器。
【請求項5】
メモリに展開された各プログラムコードを実行するコンピュータを、
前記いずれかのプログラムコードの呼び出し時を検出する検出手段、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記メモリに展開された各プログラムコードのリターンアドレスを順次取得するリターンアドレス取得手段、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記リターンアドレス取得手段により順次取得されたリターンアドレスが示す先のアドレスに基づいて不正アクセスを検出し、当該不正アクセスが検出された場合には前記データ処理を停止させる停止手段、
として機能させるためのプログラム。
【請求項6】
メモリに展開された各プログラムコードを実行するコンピュータにおける不正なプログラムコードの実行防止方法であって、
前記いずれかのプログラムコードの呼び出し時を検出し、当該検出されたプログラムコードの呼び出し時において、前記メモリに展開された各プログラムコードのリターンアドレスを順次取得し、当該取得された各リターンアドレスが示す先のアドレスに基づいて不正アクセスを検出し、当該不正アクセスが検出された場合には前記データ処理を停止させる不正なプログラムコードの実行防止方法。
【請求項1】
メモリに展開された各プログラムコードと中央制御部との協働によりデータ処理を行う情報機器であって、
前記いずれかのプログラムコードの呼び出し時を検出する検出手段と、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記メモリに展開された各プログラムコードのリターンアドレスを順次取得するリターンアドレス取得手段と、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記リターンアドレス取得手段により順次取得されたリターンアドレスが示す先のアドレスに基づいて不正アクセスを検出し、当該不正アクセスが検出された場合には前記データ処理を停止させる停止手段と、
を備える情報機器。
【請求項2】
前記メモリは、各プログラムコードのリターンアドレスを格納するスタック領域を備え、
前記リターンアドレス取得手段は、前記スタック領域に格納されたリターンアドレスをトレースして取得する請求項1に記載の情報機器。
【請求項3】
前記停止手段は、前記属性取得手段により取得された各リターンアドレスが示す先のアドレスが関数の開始アドレスである場合に不正アクセスを検出し、当該不正アクセスが検出された場合には、前記データ処理を停止させる請求項1又は2に記載の情報機器。
【請求項4】
前記停止手段は、前記属性取得手段により取得された各リターンアドレスが示す先のアドレスに対応する一つ前の命令がコール命令ではない場合に不正アクセスを検出し、当該不正アクセスが検出された場合には、前記データ処理を停止させる請求項1〜3の何れか一項に記載の情報機器。
【請求項5】
メモリに展開された各プログラムコードを実行するコンピュータを、
前記いずれかのプログラムコードの呼び出し時を検出する検出手段、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記メモリに展開された各プログラムコードのリターンアドレスを順次取得するリターンアドレス取得手段、
前記検出手段により検出されたプログラムコードの呼び出し時に、前記リターンアドレス取得手段により順次取得されたリターンアドレスが示す先のアドレスに基づいて不正アクセスを検出し、当該不正アクセスが検出された場合には前記データ処理を停止させる停止手段、
として機能させるためのプログラム。
【請求項6】
メモリに展開された各プログラムコードを実行するコンピュータにおける不正なプログラムコードの実行防止方法であって、
前記いずれかのプログラムコードの呼び出し時を検出し、当該検出されたプログラムコードの呼び出し時において、前記メモリに展開された各プログラムコードのリターンアドレスを順次取得し、当該取得された各リターンアドレスが示す先のアドレスに基づいて不正アクセスを検出し、当該不正アクセスが検出された場合には前記データ処理を停止させる不正なプログラムコードの実行防止方法。
【図1】
【図2】
【図3】
【図4】
【図5】
【図6】
【図7】
【図8】
【図9】
【図10】
【図11】
【図12】
【図13】
【図2】
【図3】
【図4】
【図5】
【図6】
【図7】
【図8】
【図9】
【図10】
【図11】
【図12】
【図13】
【公開番号】特開2010−257275(P2010−257275A)
【公開日】平成22年11月11日(2010.11.11)
【国際特許分類】
【出願番号】特願2009−107294(P2009−107294)
【出願日】平成21年4月27日(2009.4.27)
【特許番号】特許第4572259号(P4572259)
【特許公報発行日】平成22年11月4日(2010.11.4)
【出願人】(507351506)株式会社フォティーンフォティ技術研究所 (4)
【Fターム(参考)】
【公開日】平成22年11月11日(2010.11.11)
【国際特許分類】
【出願日】平成21年4月27日(2009.4.27)
【特許番号】特許第4572259号(P4572259)
【特許公報発行日】平成22年11月4日(2010.11.4)
【出願人】(507351506)株式会社フォティーンフォティ技術研究所 (4)
【Fターム(参考)】
[ Back to top ]