【セキスペ】H28年秋期 午後Ⅰ BOF問題について考える
セキスペこと、情報セキュリティスペシャリスト(現:安全確保支援士試験)の問題を解いていると興味深い問題を見つけたのでメモ
万が一、勉強中の方がこのページに行き着いた場合も考えて、ある程度しっかりまとめてみます。
どんな問題?
https://www.jitec.ipa.go.jp/1_04hanni_sukiru/mondai_kaitou_2016h28_2/2016h28a_sc_pm1_qs.pdf
こちらより抜粋
この問題に対して、
(1) 下線部②について、利用者認証を回避される引数はどれか
(2) 実際にBOF(バッファオーバーフロー)が発生するのはどの行か
(3) どのように改修するのが適切か
という設問に答えていく。
下準備
ここでは一先ず、「どんなユーザIDもパスワードは必ず"PASS"」ということにする。(とんでもないシステムだが)
// ユーザIDからパスワードを取得する
void getPass(char *pass, char *uid)
{
strcpy(pass, "PASS");
}
分かりやすい様に、メイン処理にデバッグモニタ的な出力を追加する。
int main(int argc, char **argv)
{
static char *uid;
static char *pass;
uid = new char[UID_SIZE + 1];
pass = new char[PASS_SIZE + 1];
cout << "入力されたID: " << argv[1] << endl;
cout << "入力されたPW: " << argv[2] << endl;
cout << "----------------" << endl;
getPass(pass, argv[1]);
strcpy(uid, argv[1]);
cout << "ユーザID: " << uid << endl;
cout << "パスワード: " << pass << endl; // ここが必ず PASS になるはず・・・
if (strlen(pass) == 0 || strcmp(argv[2], pass) != 0) {
cout << "認証失敗" << endl;
} else {
cout << "認証成功" << endl;
}
}
プログラムが意図した動作になっていることを確認
以降はこのプログラムを利用する。
利用者認証を回避される引数はどれか
この場合、利用者認証を回避するためには
if (strlen(pass) == 0 || strcmp(argv[2], pass) != 0)
を満たす必要がある。
となると、何らかの手法で変数 pass の中身を書き換える必要がある。
この際に利用されるのが「「バッファオーバーフロー」」である。
C / C++言語は通常、変数の内容をヒープ領域へ格納する。
実際にこのプログラムの実行時のヒープ領域を確認する。
uid ⇔ 0x867A68
pass ⇔ 0x867A80
となっている。
ココで大事なポイントが
①プログラム内でnew宣言された変数は必ずヒープ領域内に存在している
②変数 uid の取りうる領域を超えたデータを書き込むことで
変数 pass の領域へ侵入することが出来る。
という2点である。
上記の②をBOF攻撃に利用するため、
第一引数から変数 uid へ値をコピーするステップを利用する。
0x867A68 から 0x867A80 までは24バイト離れているため、入力値は
( 適当な 24 バイト分の文字 ) + ( 書き換えたい内容 )
とすると、変数 pass の領域へ侵入することが出来る。
メモリを確認すると領域が埋められていることが分かる。
※アドレスの差は、割り当てられるヒープ領域がプログラム実行毎に変化するため。
よって、正解は「第一引数の末尾」と「第二引数」が一致している
第一引数: 011(繰返し) 1111111101
第二引数: 11111101
が正解である。
BOF(バッファオーバーフロー)が発生するのはどの行か
上の項目でほぼ答えを出してしまったが、23行目の
strcpy(uid, argv[1]);
にてBOFが発生している。
ここで留意すべきなのが15行目、すなわち不正なデータが入力された段階ではBOFは発生していないということである。
つまり、不正なデータに対して何の対処もされていない場合にのみBOFは成立する。ということが言える。
次の設問ではその対処法についての理解を問われる。
どう改修するのが適切か
設問にて提示されている選択肢は以下の5点である
正攻法としては、
入力値が、変数 uid が確保している領域 new char[UID_SIZE + 1] を超えてしまうとBOFが成立する事を踏まえて、
Ⅰ. ア、エは入力値が丸々ヒープ領域内にコピーされてしまう為、確保している領域を超える可能性がある。
Ⅱ. オは、確保する領域を増やしてもそれを上回るデータ入力があれば意味をなさない。
ということから、入力値の制御として適切であるイ、オが正解となる。
BOFが成立する条件を知っているかどうかではあるが、
知らなくてもある程度絞り込める方法があるのでご紹介。
最初の問題文中の
"利用者IDとパスワード"は、いずれも半角英数字、最小6文字最大8文字の文字列と仕様で定められている。
に記載されていように、ID、PWは8文字以上である場合は無条件で不正な値となる。
つまり、8文字( プログラム上は終端文字を加えた9文字 )以上の値はコピーする必要がなく、切り捨てが発生する方が仕様上正しいと言える。
おまけ
プログラムを実行する度にMcAfeeが絡んできた卍
お試ししたい時はアンチウィルスソフトを切ったほうが良いかも
この記事が気に入ったらサポートをしてみませんか?