1月6日(木)3、4コマ目
今日、やったこと
バッファオーバーフローでリターンアドレス書き換え
今日のホワイトボード
プログラムを実行すると
コンパイルで出力された実行ファイル(実行命令のリスト)がメモリ上のコード領域にロードされ、命令が順番に実行される。
| 図 コード領域に実行ファイルがロードされる |
関数を呼び出すと
コード領域にロードされた関数の命令リストへジャンプして関数を実行する。
関数実行後、呼び出し元に戻る。コード領域のどこに戻るかが、スタック上に書き込まれている。
このスタック領域の戻るべきアドレスをリターンアドレスと呼び、関数実行時に呼び出し元がスタック領域に書き込んでいる。
| 図 関数呼び出し時にスタック領域に書き込まれるデータ |
サンプルプログラムを確認
main()関数からcheck()関数を呼び出すときのメモリの状態をデバッガで確認。
①コード領域のmain()関数をチェック
逆アセンブルすると、check()関数を呼び出す箇所がわかる。
| 図 main()を逆アセンブルした |
callqでcheck()関数を呼び出し、0x00・・004007a5番地に戻ってくる。
この0x00・・004007a5番地をリターンアドレスとしてスタック上に書き込む。
| 図 メモリ上のイメージ |
②リターンアドレスが書き込まれる位置を確認
ブレークポイントで一時停止して確認すると、pass_buffの先頭から40バイト離れたところにリターンアドレスが書き込まれている。
| 図 デバッガでメモリ確認 |
| 図 メモリのイメージ |
③リターンアドレスを上書きする
このプログラムにはバッファオーバーフローの脆弱性があるため、リターンアドレスを上書きする。
上書きするアドレスはif()の条件成立時に実行するprintf()。
| 図 リターンアドレス書き換え済み |
C言語は危険
strcpy()以外にもコピー先のサイズに関係なくコピーする関数がある。
上限バイト数が指定できる関数を利用すること。
get -> fgets
sprintf -> snprintf
strcat -> strncat
strcpy -> strncpy
vsprintf -> vsnprintf
サンプルプログラムを修正
strcpy()ではなく、strncpy()を使って文字列コピー。