今回は動的メモリ管理に関する脆弱性の続きです。unlinkテクニックと呼ばれる古典的な攻撃手法を紹介します。
この連載では、前回から「動的メモリ管理に関する脆弱性」と題してヒープメモリの扱いに関連する話題を取り上げていますが、副読本としてちょうどよさそうな資料を見つけたので紹介します。
これは「Heap Exploitのこれまでと現状」と題したレポートで、@ITでも連載を行っているFFRIというセキュリティ会社が、月例レポートの1つとして2013年12月に公開したものです。
このレポートでは、Windows環境における動的メモリ管理に関する脆弱性の攻撃手法について概説しています。Windows環境におけるヒープメモリ管理や具体的な攻撃手法に興味があるなら、まずこの資料でおおざっぱなイメージをつかんでから、より詳しい情報に当たるとよいのではないかと思います。
FFRI Monthly Report
「Heap Exploitのこれまでと現状」
さて、今回はヒープバッファーオーバーフローの脆弱性があるプログラムに対して行われる古典的な攻撃手法として、「unlinkテクニック」と呼ばれる手法のエッセンスを紹介します。
前回も少し説明しましたが、ヒープメモリはメモリ管理ライブラリによって、ある程度の大きさのブロックの集まりとして管理されます。プログラムが動作するにつれてmalloc()やfree()の呼び出しが繰り返され、やがて使用中のブロックと使用されていない(解放された)ブロックがヒープメモリ上に混在する状態になっていきます。
このような状況を管理する仕組みとして、プログラムの読み書きに使われるメモリブロックごとに、使用中か解放済みかを表すフラグやメモリブロックのサイズ情報など、管理用の情報を一緒にまとめて扱うという方法が考えられます(図1)。
このようなブロックがメモリのあちこちに散在する状況で、メモリ管理ライブラリは、malloc()呼び出しに対して適切なサイズのブロックを探し出してくる必要があります。
典型的なアプローチがリンクトリストを使ったメモリブロックの管理です。ブロックを数珠つなぎにして持っておき、割り当て依頼が来るとリンクをたどって適切なブロックを探し出します。また、メモリブロックが解放された場合にはこのリストに戻して次の割り当てに備えるわけです。
このようなアプローチで、メモリ割り当てや解放のときにどのような操作が行われるのか、もう少し詳しく見てみましょう。
まず、プログラムの実行開始時点では、空きメモリブロックのリストが用意されます(リストからたどれるブロックは「解放済み」のメモリブロックであるということです)。
ここでは、各メモリブロックに付随する管理情報として、
を持っているものとします。図2では、3個のブロック、n1、n2、n3からなるリストを図示しています。
malloc()呼び出しがあると、メモリ管理ライブラリは、先頭ポインターからメモリブロックを順番に調べ、適切な空きメモリブロックを返します。また、free()呼び出しが行われると、解放されたメモリブロックを再度リストにつなぎます。
図2においてmalloc()が呼ばれ、メモリ管理ライブラリがブロックn2を選んだとしましょう。すると、ブロックn2をリストから外し、malloc()の返り値としてブロックn2(の空きメモリ部分の先頭)を指すポインターを返す必要があります。
リストからブロックを外す手順を書き下すと、次のようになるでしょう(図3、図4)。
この操作をCのコードで表すと次のようになります。
typedef struct node_t { size_t size; struct node_t *next; struct node_t *prev; char space[BLOCKSIZE]; } *node; // e をメモリブロックのリストから外す void unlink(node e) { node n3 = e->next; node n1 = e->prev; n3->prev = n1; n1->next = n3; }
一方、free()でメモリブロックが解放された場合にリストに取り込む操作は次のようになるでしょう(図5、図6)。
こちらの操作もCのコードで表すと次のようになります。
//eをn1の後ろに入れる void insert(node e, node n1){ node n3 = n1->next; n1->next = e; n3->prev = e; e->next = n3; e->prev = n1; }
実際のメモリ管理では、このようなリストに対する基本操作に加えて、解放されたブロックが複数隣接している場合に1個のブロックに統合して管理するとか、ブロックの大きさごとに複数のリストを作って管理するなどの工夫がありますが、話を簡単にするために省略します。
アプリケーションプログラムからmalloc()やfree()が呼び出されると、その内側ではこのようなヒープメモリ管理のための作業(リストに対する操作)が行われているのです。
さて、これでunlinkテクニックを説明する準備ができました。
Copyright © ITmedia, Inc. All Rights Reserved.