バッファオーバーフロー
バッファAの値を他のバッファBにコピーするとき、BのバッファサイズがAのバッファサイズよりも大きいことをチェックしない場合に生じる脆弱性である。この脆弱性は、プログラマーがこのようなチェックの実装を怠った事により生じる。これはプログラマーが最低限のセキュリティチェックすらしていないことを強く示唆する。
脆弱性の具体例としては、例えばC言語やC++において、配列サイズをチェックする事なく、配列にstrcpyやscanfで文字列等をコピーするといったものがある。攻撃者は意図的に大きな入力をstrcpy、scanf、getsに与えることで、古典的バッファオーバーフローを不正に生じさせる事ができる。
例えば攻撃者がバッファAをバッファオーバーフローさせる事により、Aの隣りにある変数xを不正に変更できた場合、xがセキュリティ上重要なデータ(例えば管理者権限を持っているか否かを判定するビットを保持している)であれば、セキュリティ上重要な問題が生じる。
バッファオーバーフロー攻撃を含めたメモリ破壊攻撃全般を緩和する技術としてASLR(Address Space Layout Randomization、アドレス空間配置のランダム化)がある。これは仮想メモリ空間におけるスタック領域やコード領域の位置、読み込まれるDLLの位置等を(プログラム起動時もしくはOS自身の起動時に)ランダムに変える技術で、これにより攻撃者が攻撃に有効な実行コードの特定箇所を指定してメモリ改ざんを行うのを困難にする。
ASLRはバッファオーバーフロー攻撃の発展形であるReturn-to-libc攻撃(後述)を緩和できるが、さらにその発展形であるReturn-oriented programmingには対抗できない。
カーネル空間のASLRをKASLR(kernel address space layout randomization)といい、linuxカーネル(バージョン3.14以降)、iOS(バージョン6以降)などで実装されている。またKASLRをバイパスしようとする攻撃に対抗する為の機構としてKernel page-table isolationがある。
gccとg++でコンパイルとスタック領域とヒープ領域に対してはASLRを用いるが、コード領域にASLRを用いるにはオプション「-pie」を使わねばならない。また共有ライブラリにASLRを用いるにはオプション「-fPIC」を指定する。
上で述べた攻撃のアイデアが実行可能であるためには、攻撃者がリターンアドレスに上書きすべき仮想アドレスを正確に知り、それを関数gに入力する必要があるが、スタックは動的に変化するため、これは容易ではない。そこで本節ではリターンアドレスに上書きすべき仮想アドレスの「おおよその値」さえ分かれば攻撃が可能になるテクニック(NOPスレッド)を述べる。
NOPとは「何も行わない」事を意味するアセンブリ命令で、本来はタイミングを合わせるなどの動機により何もせずにCPU時間を消費するために用いられる。NOPスレッド(sled、そり)とはこのNOP命令を複数個並べたもので、これを利用する事により攻撃対象の関数をシェルコードの位置まで滑走させる。
具体的には攻撃者は下記のような文字列を攻撃対象の関数gに入力する:
NOP ... NOP (シェルコード)(戻りアドレス)...(戻りアドレス)
最初の「NOP ... NOP」の部分がNOPスレッドである。